diff --git a/src/cluster/k8sClientHandler.go b/src/cluster/k8sClientHandler.go index e63f3e97..39a83849 100644 --- a/src/cluster/k8sClientHandler.go +++ b/src/cluster/k8sClientHandler.go @@ -6,8 +6,10 @@ import ( "sort" "strings" + "github.com/accuknox/auto-policy-discovery/src/config" "github.com/accuknox/auto-policy-discovery/src/libs" "github.com/accuknox/auto-policy-discovery/src/types" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -346,6 +348,7 @@ func GetClusterNameFromK8sClient() string { func GetDeploymentsFromK8sClient() []types.Deployment { results := []types.Deployment{} + nsNotFilter := config.CurrentCfg.ConfigSysPolicy.NsNotFilter client := ConnectK8sClient() if client == nil { @@ -361,8 +364,10 @@ func GetDeploymentsFromK8sClient() []types.Deployment { } for _, d := range deployments.Items { - if d.Namespace == "kube-system" { - continue + for _, notns := range nsNotFilter { + if strings.Contains(d.Namespace, notns) { + continue + } } if d.Spec.Selector.MatchLabels != nil { @@ -379,9 +384,9 @@ func GetDeploymentsFromK8sClient() []types.Deployment { }) } } - results = append(results, GetReplicaSetsFromK8sClient()...) results = append(results, GetStatefulSetsFromK8sClient()...) + results = append(results, GetDaemonSetsFromK8sClient()...) return results } @@ -392,6 +397,7 @@ func GetDeploymentsFromK8sClient() []types.Deployment { func GetReplicaSetsFromK8sClient() []types.Deployment { results := []types.Deployment{} + nsNotFilter := config.CurrentCfg.ConfigSysPolicy.NsNotFilter client := ConnectK8sClient() if client == nil { @@ -408,8 +414,10 @@ func GetReplicaSetsFromK8sClient() []types.Deployment { for _, rs := range replicasets.Items { if rs.OwnerReferences == nil { - if rs.Namespace == "kube-system" { - continue + for _, notns := range nsNotFilter { + if strings.Contains(rs.Namespace, notns) { + continue + } } if rs.Spec.Selector.MatchLabels != nil { @@ -430,12 +438,60 @@ func GetReplicaSetsFromK8sClient() []types.Deployment { return results } +// ================= // +// == Daemonset == // +// ================= // + +func GetDaemonSetsFromK8sClient() []types.Deployment { + results := []types.Deployment{} + nsNotFilter := config.CurrentCfg.ConfigSysPolicy.NsNotFilter + + client := ConnectK8sClient() + if client == nil { + log.Error().Msg("failed to create k8s client") + return results + } + + // get namespaces from k8s api client + daemonsets, err := client.AppsV1().DaemonSets("").List(context.Background(), metav1.ListOptions{}) + if err != nil { + log.Error().Msg(err.Error()) + return results + } + + for _, ds := range daemonsets.Items { + if ds.OwnerReferences == nil { + for _, notns := range nsNotFilter { + if strings.Contains(ds.Namespace, notns) { + continue + } + } + + if ds.Spec.Selector.MatchLabels != nil { + var labels []string + + for k, v := range ds.Spec.Selector.MatchLabels { + labels = append(labels, k+"="+v) + } + + results = append(results, types.Deployment{ + Name: ds.Name, + Namespace: ds.Namespace, + Labels: strings.Join(labels, ","), + }) + } + } + } + return results +} + // ================= // // == StatefulSet == // // ================= // func GetStatefulSetsFromK8sClient() []types.Deployment { results := []types.Deployment{} + nsNotFilter := config.CurrentCfg.ConfigSysPolicy.NsNotFilter client := ConnectK8sClient() if client == nil { @@ -452,8 +508,10 @@ func GetStatefulSetsFromK8sClient() []types.Deployment { for _, sts := range statefulset.Items { if sts.OwnerReferences == nil { - if sts.Namespace == "kube-system" { - continue + for _, notns := range nsNotFilter { + if strings.Contains(sts.Namespace, notns) { + continue + } } if sts.Spec.Selector.MatchLabels != nil { diff --git a/src/conf/local-file.yaml b/src/conf/local-file.yaml index c7d32f55..920f1e8b 100644 --- a/src/conf/local-file.yaml +++ b/src/conf/local-file.yaml @@ -119,8 +119,13 @@ recommend: operation-mode: 1 # 1: cronjob | 2: one-time-job cron-job-time-interval: "1h0m00s" # format: XhYmZs recommend-host-policy: true - template-version: "" # policy template version to be used for recommendation (keep empty to fetches latest) - admission-controller-policy: false + template-version: "v0.2.2" # policy template version to be used for recommendation (keep empty to fetches latest) + +# Recommended policies configuration +crownjewel: + operation-mode: 1 # 1: cronjob | 2: one-time-job + cron-job-time-interval: "0h0m20s" # format: XhYmZs + # license license: enabled: false diff --git a/src/conf/local.yaml b/src/conf/local.yaml index e591cc5f..682d7c99 100644 --- a/src/conf/local.yaml +++ b/src/conf/local.yaml @@ -86,6 +86,11 @@ recommend: template-version: "" admission-controller-policy: false +# Recommended policies configuration +crownjewel: + operation-mode: 1 # 1: cronjob | 2: one-time-job + cron-job-time-interval: "1h0m00s" # format: XhYmZs + # license license: enabled: false diff --git a/src/config/configManager.go b/src/config/configManager.go index 2774e356..c819d538 100644 --- a/src/config/configManager.go +++ b/src/config/configManager.go @@ -219,6 +219,13 @@ func LoadConfigFromFile() { RecommendTemplateVersion: viper.GetString("recommend.template-version"), } + // crown jewel policy configurations + CurrentCfg.ConfigCrownjewelPolicy = types.ConfigCrownjewelPolicy{ + CronJobTimeInterval: "@every " + viper.GetString("crownjewel.cron-job-time-interval"), + OneTimeJobTimeSelection: "", // e.g., 2021-01-20 07:00:23|2021-01-20 07:00:25 + OperationMode: viper.GetInt("crownjewel.operation-mode"), + } + // load database CurrentCfg.ConfigDB = LoadConfigDB() @@ -533,6 +540,25 @@ func GetCfgRecommendAdmissionControllerPolicy() bool { return CurrentCfg.ConfigRecommendPolicy.RecommendAdmissionControllerPolicy } +// ================================== // +// == Get Crown Jewel Config Info == // +// ================================ // + +// run the Crown jewel scan once +func GetCfgCrownjewelOneTime() string { + return CurrentCfg.ConfigCrownjewelPolicy.OneTimeJobTimeSelection +} + +// run the Crown jewel scan as a cron job +func GetCfgCrownjewelCronJobTime() string { + return CurrentCfg.ConfigCrownjewelPolicy.CronJobTimeInterval +} + +// dont' run the Crown jewel scan +func GetCfgCrownjewelOperationMode() int { + return CurrentCfg.ConfigCrownjewelPolicy.OperationMode +} + func GetCfgRecommendTemplateVersion() string { return CurrentCfg.ConfigRecommendPolicy.RecommendTemplateVersion } diff --git a/src/crownjewel/crownjewel.go b/src/crownjewel/crownjewel.go new file mode 100644 index 00000000..2d2ea77c --- /dev/null +++ b/src/crownjewel/crownjewel.go @@ -0,0 +1,482 @@ +package crownjewel + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/accuknox/auto-policy-discovery/src/cluster" + "github.com/accuknox/auto-policy-discovery/src/common" + "github.com/accuknox/auto-policy-discovery/src/config" + cfg "github.com/accuknox/auto-policy-discovery/src/config" + "github.com/accuknox/auto-policy-discovery/src/libs" + logger "github.com/accuknox/auto-policy-discovery/src/logging" + obs "github.com/accuknox/auto-policy-discovery/src/observability" + opb "github.com/accuknox/auto-policy-discovery/src/protobuf/v1/observability" + "github.com/accuknox/auto-policy-discovery/src/systempolicy" + "github.com/accuknox/auto-policy-discovery/src/types" + "github.com/robfig/cron" + "github.com/rs/zerolog" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +var log *zerolog.Logger + +// CrownjewelCronJob for cron job +var CrownjewelCronJob *cron.Cron + +var CrownjewelStopChan chan struct{} + +// CrownjewelWorkerStatus global worker +var CrownjewelWorkerStatus string + +// const values +const ( + // operation mode + opModeNoop = 0 + opModeCronjob = 1 + + // status + statusRunning = "running" + statusIdle = "idle" +) + +// init Function +func init() { + log = logger.GetInstance() + CrownjewelWorkerStatus = statusIdle + CrownjewelStopChan = make(chan struct{}) +} + +// StartCrownjewelWorker starts the crown jewel worker (run once or as a cronjob) +func StartCrownjewelWorker() { + if CrownjewelWorkerStatus != statusIdle { + log.Info().Msg("There is no idle Crown jewel policy worker") + return + } + if cfg.GetCfgCrownjewelOperationMode() == opModeNoop { // Do not run the operation + log.Info().Msg("Crown jewel operation mode is NOOP... ") + } else if cfg.GetCfgCrownjewelOperationMode() == opModeCronjob { // every time intervals + log.Info().Msg("Crown jewel policy cron job started") + CrownjewelPolicyMain() + StartCrownjewelCronJob() + } else { // one-time generation + CrownjewelPolicyMain() + log.Info().Msgf("Crown jewel policy onetime job done") + } +} + +// StartCrownjewelCronJob starts the cronjob +func StartCrownjewelCronJob() { + // init cron job + CrownjewelCronJob = cron.New() + err := CrownjewelCronJob.AddFunc(cfg.GetCfgCrownjewelCronJobTime(), CrownjewelPolicyMain) + if err != nil { + log.Error().Msg(err.Error()) + return + } + CrownjewelCronJob.Start() +} + +// StopCrownjewelCronJob stops the cronjob +func StopCrownjewelCronJob() { + if CrownjewelCronJob != nil { + log.Info().Msg("Got a signal to terminate the auto system policy discovery") + + CrownjewelStopChan = make(chan struct{}) + + close(CrownjewelStopChan) + + CrownjewelCronJob.Stop() // Stop the scheduler (does not stop any jobs already running). + + CrownjewelCronJob = nil + } +} + +// Create Crown Jewel Policy based on K8s object type +func CrownjewelPolicyMain() { + deployment := cluster.GetDeploymentsFromK8sClient() + client := cluster.ConnectK8sClient() + + for _, d := range deployment { + err := getFilteredPolicy(client, d.Name, d.Namespace, d.Labels) + if err != nil { + log.Error().Msg("Error getting mount paths, err=" + err.Error()) + } + } +} + +type LabelMap = map[string]string + +// Get list of running processes from observability data +func getProcessList(client kubernetes.Interface, namespace string, labels string) ([]string, error) { + var processList []string + duplicatePaths := make(map[string]bool) + + podList, err := client.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{ + LabelSelector: labels, + }) + if err != nil { + log.Warn().Msg(err.Error()) + } + for _, pod := range podList.Items { + for _, container := range pod.Spec.Containers { + sumResp, err := obs.GetSummaryData(&opb.Request{ + PodName: pod.Name, + NameSpace: pod.Namespace, + ContainerName: container.Name, + Type: "process,file,network", + }) + if err != nil { + log.Warn().Msgf("Error getting summary data for pod %s, container %s, namespace %s: %s", pod.Name, container.Name, pod.Namespace, err.Error()) + break + } + + for _, procData := range sumResp.ProcessData { + if !duplicatePaths[procData.Source] { + processList = append(processList, procData.Source) + duplicatePaths[procData.Source] = true + } + if !duplicatePaths[procData.Destination] { + processList = append(processList, procData.Destination) + duplicatePaths[procData.Destination] = true + } + } + for _, fileData := range sumResp.FileData { + if !duplicatePaths[fileData.Source] { + processList = append(processList, fileData.Source) + duplicatePaths[fileData.Source] = true + } + } + for _, netData := range sumResp.IngressConnection { + if !duplicatePaths[netData.Command] { + processList = append(processList, netData.Command) + duplicatePaths[netData.Command] = true + } + } + for _, netData := range sumResp.EgressConnection { + if !duplicatePaths[netData.Command] { + processList = append(processList, netData.Command) + duplicatePaths[netData.Command] = true + } + } + } + } + return processList, nil +} + +// Get all mounted paths +func getVolumeMountPaths(client kubernetes.Interface, labels string) ([]string, error) { + podList, err := client.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{ + LabelSelector: labels, + }) + if err != nil { + return nil, fmt.Errorf("failed to get pod list: %v", err) + } + + var mountPaths []string + + for _, pod := range podList.Items { + for _, container := range pod.Spec.Containers { + for _, volumeMount := range container.VolumeMounts { + // fmt.Printf("\n\n\n%s\n\n\n", volumeMount.MountPath) + if volumeMount.MountPath == "/var/run/secrets/kubernetes.io/serviceaccount" { + // + mountPaths = append(mountPaths, "/run/secrets/kubernetes.io/serviceaccount") + continue + } + mountPaths = append(mountPaths, volumeMount.MountPath) + } + } + } + return mountPaths, nil +} + +// Get used mount paths from observability data +func usedPaths(client kubernetes.Interface, namespace string, labels string) ([]string, map[string]string, error) { + var sumResponses []string + fromSource := make(map[string]string) + + podList, err := client.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{ + LabelSelector: labels, + }) + if err != nil { + log.Warn().Msg(err.Error()) + } + + for _, pod := range podList.Items { + for _, container := range pod.Spec.Containers { + sumResp, err := obs.GetSummaryData(&opb.Request{ + PodName: pod.Name, + NameSpace: pod.Namespace, + ContainerName: container.Name, + Type: "file", + }) + if err != nil { + log.Warn().Msgf("Error getting summary data for pod %s, container %s, namespace %s: %s", pod.Name, container.Name, pod.Namespace, err.Error()) + break + } + + for _, fileData := range sumResp.FileData { + sumResponses = append(sumResponses, fileData.Destination) + fromSource[fileData.Destination] = fileData.Source + } + } + } + return sumResponses, fromSource, nil +} + +// Get network information from observability data +func usedNetwork(client kubernetes.Interface, namespace string, labels string) ([]types.KnoxMatchProtocols, error) { + fromSource := make(map[string][]string) + + podList, err := client.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{ + LabelSelector: labels, + }) + if err != nil { + log.Warn().Msg(err.Error()) + } + + for _, pod := range podList.Items { + for _, container := range pod.Spec.Containers { + sumResp, err := obs.GetSummaryData(&opb.Request{ + PodName: pod.Name, + NameSpace: pod.Namespace, + ContainerName: container.Name, + Type: "network", + }) + if err != nil { + log.Warn().Msgf("Error getting summary data for pod %s, container %s, namespace %s: %s", pod.Name, container.Name, pod.Namespace, err.Error()) + break + } + + for _, netData := range sumResp.IngressConnection { + if strings.Contains(strings.ToLower(netData.Protocol), "tcp") { + fromSource["tcp"] = append(fromSource["tcp"], netData.Command) + } + if strings.Contains(strings.ToLower(netData.Protocol), "udp") { + fromSource["udp"] = append(fromSource["udp"], netData.Command) + } + if strings.Contains(strings.ToLower(netData.Protocol), "icmp") { + fromSource["icmp"] = append(fromSource["icmp"], netData.Command) + } + if strings.Contains(strings.ToLower(netData.Protocol), "raw") { + fromSource["raw"] = append(fromSource["raw"], netData.Command) + } + } + for _, netData := range sumResp.EgressConnection { + if strings.Contains(strings.ToLower(netData.Protocol), "tcp") { + fromSource["tcp"] = append(fromSource["tcp"], netData.Command) + } + if strings.Contains(strings.ToLower(netData.Protocol), "udp") { + fromSource["udp"] = append(fromSource["udp"], netData.Command) + } + if strings.Contains(strings.ToLower(netData.Protocol), "icmp") { + fromSource["icmp"] = append(fromSource["icmp"], netData.Command) + } + if strings.Contains(strings.ToLower(netData.Protocol), "raw") { + fromSource["raw"] = append(fromSource["raw"], netData.Command) + } + } + } + } + + var matchProtocols []types.KnoxMatchProtocols + + for k, v := range fromSource { + var matchProto types.KnoxMatchProtocols + matchProto.Protocol = k + for _, src := range v { + matchProto.FromSource = append(matchProto.FromSource, types.KnoxFromSource{Path: src}) + } + matchProtocols = append(matchProtocols, matchProto) + } + return matchProtocols, nil +} + +// Match used mounts paths with actually accessed mount paths +func accessedMountPaths(sumResp, mnt []string) ([]string, error) { + var matchedMountPaths []string + duplicatePaths := make(map[string]bool) + + for _, sumRespPath := range sumResp { + for _, mntPath := range mnt { + if strings.HasPrefix(sumRespPath, mntPath) && !duplicatePaths[mntPath] { + matchedMountPaths = append(matchedMountPaths, mntPath) + duplicatePaths[mntPath] = true + } + } + } + return matchedMountPaths, nil +} + +// Ignore namespaces based on config +func getFilteredPolicy(client kubernetes.Interface, cname, namespace string, labels string) error { + // filters to check the namespaces to be ignored + nsFilter := config.CurrentCfg.ConfigSysPolicy.NsFilter + nsNotFilter := config.CurrentCfg.ConfigSysPolicy.NsNotFilter + + var policies []types.KnoxSystemPolicy + var err error + if len(nsFilter) > 0 { + for _, ns := range nsFilter { + if strings.Contains(namespace, ns) { + policies, err = getCrownjewelPolicy(client, cname, namespace, labels) + if err != nil { + log.Error().Msg("Error getting Crown jewel policy, err=" + err.Error()) + } + } + } + systempolicy.UpdateSysPolicies(policies) + } else if len(nsNotFilter) > 0 { + for _, notns := range nsNotFilter { + if !strings.Contains(namespace, notns) { + policies, err = getCrownjewelPolicy(client, cname, namespace, labels) + if err != nil { + log.Error().Msg("Error getting Crown jewel policy, err=" + err.Error()) + } + } + } + systempolicy.UpdateSysPolicies(policies) + } + return nil +} + +// Generate crown jewel policy +func getCrownjewelPolicy(client kubernetes.Interface, cname, namespace string, labels string) ([]types.KnoxSystemPolicy, error) { + var policies []types.KnoxSystemPolicy + + var matchedMountPaths []string + var ms types.MatchSpec + action := "Allow" + + // file paths being used (from observability) + sumResp, fileFromSrc, _ := usedPaths(client, namespace, labels) + + netFromSrc, _ := usedNetwork(client, namespace, labels) + + // all mount paths being used (from k8s cluster) + mnt, _ := getVolumeMountPaths(client, labels) + + // mount paths being used and are present in observability data (accessed mount paths) + matchedMountPaths, _ = accessedMountPaths(sumResp, mnt) + + // process paths being used and are present in observability data + matchedProcessPaths, _ := getProcessList(client, namespace, labels) + + policy := createCrownjewelPolicy(ms, cname, namespace, action, labels, mnt, matchedMountPaths, matchedProcessPaths, fileFromSrc, netFromSrc) + // Check for empty policy + if policy.Spec.File.MatchDirectories == nil && policy.Spec.File.MatchPaths == nil && + policy.Spec.Process.MatchDirectories == nil && policy.Spec.Process.MatchPaths == nil { + return nil, nil + } + policies = append(policies, policy) + + return policies, nil +} + +// Build Crown jewel System policy structure +func buildSystemPolicy(cname, ns, action string, labels string, matchDirs []types.KnoxMatchDirectories, matchPaths []types.KnoxMatchPaths, matchProtocols []types.KnoxMatchProtocols) types.KnoxSystemPolicy { + clustername := config.GetCfgClusterName() + + // create policy name + name := strconv.FormatUint(uint64(common.HashInt(labels+ns+clustername+cname)), 10) + return types.KnoxSystemPolicy{ + APIVersion: "security.kubearmor.com/v1", + Kind: "KubeArmorPolicy", + Metadata: map[string]string{ + "name": "autopol-sensitive-" + name, + "namespace": ns, + "status": "latest", + }, + Spec: types.KnoxSystemSpec{ + Severity: 7, + Selector: types.Selector{ + MatchLabels: libs.LabelMapFromString(labels)}, + Action: "Allow", // global action - default Allow + Message: "Sensitive assets and process control policy", + File: types.KnoxSys{ + MatchDirectories: matchDirs, + }, + Process: types.KnoxSys{ + MatchPaths: matchPaths, + }, + Network: types.NetworkRule{ + MatchProtocols: matchProtocols, + }, + }, + } +} + +func createCrownjewelPolicy(ms types.MatchSpec, cname, namespace, action string, labels string, matchedDirPts, matchedMountPts, matchedProcessPts []string, fromSrc map[string]string, matchProtocols []types.KnoxMatchProtocols) types.KnoxSystemPolicy { + var matchDirs []types.KnoxMatchDirectories + i := 1 + for _, dirpath := range matchedDirPts { + action = "Block" + for _, mountPt := range matchedMountPts { + if dirpath == mountPt { + action = "Allow" + break + } + } + + var fromSourceVal []types.KnoxFromSource + for key, value := range fromSrc { + if strings.HasPrefix(key, dirpath) { + // Check if the value already exists in fromSourceVal + exists := false + for _, existing := range fromSourceVal { + if existing.Path == value { + exists = true + break + } + } + if !exists { + fromSourceVal = append(fromSourceVal, types.KnoxFromSource{Path: value}) + } + } + } + + matchDir := types.KnoxMatchDirectories{ + Dir: dirpath + "/", + Recursive: true, + FromSource: fromSourceVal, + Action: action, + } + + if action == "Allow" { + // Block that dir from global access + matchAllowedDir := types.KnoxMatchDirectories{ + Dir: dirpath + "/", + Recursive: true, + Action: "Block", + } + matchDirs = append(matchDirs, matchAllowedDir) + } + + matchDirs = append(matchDirs, matchDir) + + if i == 1 { + // default allow access to root directory "/" + matchDir := types.KnoxMatchDirectories{ + Dir: "/", + Recursive: true, + } + matchDirs = append(matchDirs, matchDir) + i++ + } + } + + var matchPaths []types.KnoxMatchPaths + for _, processpath := range matchedProcessPts { + matchPath := types.KnoxMatchPaths{ + Path: processpath, + } + matchPaths = append(matchPaths, matchPath) + } + policy := buildSystemPolicy(cname, namespace, action, labels, matchDirs, matchPaths, matchProtocols) + + return policy +} diff --git a/src/libs/common.go b/src/libs/common.go index a3b9cb1f..96bbadbf 100644 --- a/src/libs/common.go +++ b/src/libs/common.go @@ -589,6 +589,7 @@ func WriteKubeArmorPolicyToYamlFile(fname string, policies []types.KubeArmorPoli continue } writeYamlByte(f, yamlBytes) + f.WriteString("---\n") } if err := f.Close(); err != nil { diff --git a/src/plugin/kubearmor.go b/src/plugin/kubearmor.go index d9b7eca0..10a2a5e9 100644 --- a/src/plugin/kubearmor.go +++ b/src/plugin/kubearmor.go @@ -71,12 +71,15 @@ func ConvertKnoxSystemPolicyToKubeArmorPolicy(knoxPolicies []types.KnoxSystemPol kubePolicy.Spec = policy.Spec - if kubePolicy.Kind == types.KindKubeArmorPolicy && policy.Spec.Action == "Allow" { - dirRule := types.KnoxMatchDirectories{ - Dir: types.PreConfiguredKubearmorRule, - Recursive: true, + // skip adding preconfigured rule in case of crown-jewel policies + if !strings.Contains(policy.Metadata["name"], "sensitive") { + if kubePolicy.Kind == types.KindKubeArmorPolicy && policy.Spec.Action == "Allow" { + dirRule := types.KnoxMatchDirectories{ + Dir: types.PreConfiguredKubearmorRule, + Recursive: true, + } + kubePolicy.Spec.File.MatchDirectories = append(policy.Spec.File.MatchDirectories, dirRule) } - kubePolicy.Spec.File.MatchDirectories = append(policy.Spec.File.MatchDirectories, dirRule) } for _, procpath := range kubePolicy.Spec.Process.MatchPaths { diff --git a/src/recommendpolicy/helperFunctions.go b/src/recommendpolicy/helperFunctions.go index 7c7e8698..0ae96212 100644 --- a/src/recommendpolicy/helperFunctions.go +++ b/src/recommendpolicy/helperFunctions.go @@ -122,7 +122,6 @@ func getNextRule(idx *int) (types.MatchSpec, error) { } func genericPolicy(precondition []string) bool { - for _, preCondition := range precondition { if strings.Contains(preCondition, "OPTSCAN") { return true @@ -132,7 +131,6 @@ func genericPolicy(precondition []string) bool { } func generateKnoxSystemPolicy(name, namespace string, labels LabelMap) ([]types.KnoxSystemPolicy, error) { - var ms types.MatchSpec var err error var policies []types.KnoxSystemPolicy @@ -203,6 +201,9 @@ func generateKyvernoPolicy(name, namespace string, labels LabelMap) ([]kyvernov1 func createRestrictAutomountSATokenPolicy(ms types.MatchSpec, name, namespace string, labels LabelMap) kyvernov1.PolicyInterface { policyInterface := *(ms.KyvernoPolicy) policy := (policyInterface.(*kyvernov1.Policy)).DeepCopy() + if policy.Annotations == nil { + policy.Annotations = make(map[string]string) + } policy.Annotations[types.RecommendedPolicyTagsAnnotation] = strings.Join(ms.KyvernoPolicyTags, ",") policy.Name = name + "-" + ms.Name policy.Namespace = namespace @@ -351,7 +352,6 @@ func createPolicy(ms types.MatchSpec, name, namespace string, labels LabelMap) ( } func addPolicyRule(policy *types.KnoxSystemPolicy, r *types.KnoxSystemSpec) { - if r.File.MatchDirectories != nil || r.File.MatchPaths != nil { policy.Spec.File = r.File } diff --git a/src/server/grpcServer.go b/src/server/grpcServer.go index a197a65d..173861bd 100644 --- a/src/server/grpcServer.go +++ b/src/server/grpcServer.go @@ -5,6 +5,7 @@ import ( "errors" "strings" + "github.com/accuknox/auto-policy-discovery/src/crownjewel" "github.com/accuknox/auto-policy-discovery/src/license" "github.com/spf13/viper" @@ -371,6 +372,8 @@ func AddServers(s *grpc.Server) *grpc.Server { //start recommendation recommend.StartRecommendWorker() + // start crown jewel + crownjewel.StartCrownjewelWorker() return s } diff --git a/src/systempolicy/systemPolicy.go b/src/systempolicy/systemPolicy.go index 6fc67425..d5b46fc5 100644 --- a/src/systempolicy/systemPolicy.go +++ b/src/systempolicy/systemPolicy.go @@ -287,7 +287,8 @@ func WriteSystemPoliciesToFile(namespace, clustername, labels, fromsource string latestPolicies := libs.GetSystemPolicies(CfgDB, namespace, "latest") if len(latestPolicies) > 0 { kubeArmorPolicies := plugin.ConvertKnoxSystemPolicyToKubeArmorPolicy(latestPolicies) - libs.WriteKubeArmorPolicyToYamlFile("kubearmor_policies", kubeArmorPolicies) + fname := "kubearmor_policies_sensitive" + libs.WriteKubeArmorPolicyToYamlFile(fname, kubeArmorPolicies) } WriteSystemPoliciesToFile_Ext(namespace, clustername, labels, fromsource, includeNetwork) } diff --git a/src/types/configData.go b/src/types/configData.go index 929f16dc..a40ef0af 100644 --- a/src/types/configData.go +++ b/src/types/configData.go @@ -130,7 +130,13 @@ type ConfigRecommendPolicy struct { OneTimeJobTimeSelection string `json:"one_time_job_time_selection,omitempty" bson:"one_time_job_time_selection,omitempty"` RecommendHostPolicy bool `json:"recommend_host_policy,omitempty" bson:"recommend_host_policy,omitempty"` RecommendAdmissionControllerPolicy bool `json:"recommend_admission_controller_policy,omitempty" bson:"recommend_admission_controller_policy,omitempty"` - RecommendTemplateVersion string `json:"template_version,omitempty" bson:"template_version,omitempty"` + RecommendTemplateVersion string `json:"template_version,omitempty" bson:"template_version,omitempty"` +} + +type ConfigCrownjewelPolicy struct { + OperationMode int `json:"operation_mode,omitempty" bson:"operation_mode,omitempty"` + CronJobTimeInterval string `json:"cronjob_time_interval,omitempty" bson:"cronjob_time_interval,omitempty"` + OneTimeJobTimeSelection string `json:"one_time_job_time_selection,omitempty" bson:"one_time_job_time_selection,omitempty"` } type Configuration struct { @@ -145,12 +151,13 @@ type Configuration struct { ConfigCiliumHubble ConfigCiliumHubble `json:"config_cilium_hubble,omitempty" bson:"config_cilium_hubble,omitempty"` ConfigKubeArmorRelay ConfigKubeArmorRelay `json:"config_kubearmor_relay,omitempty" bson:"config_kubearmor_relay,omitempty"` - ConfigNetPolicy ConfigNetworkPolicy `json:"config_network_policy,omitempty" bson:"config_network_policy,omitempty"` - ConfigSysPolicy ConfigSystemPolicy `json:"config_system_policy,omitempty" bson:"config_system_policy,omitempty"` - ConfigAdmissionControllerPolicy ConfigAdmissionControllerPolicy `json:"config_admission_controller_policy,omitempty" bson:"config_admission_controller_policy,omitempty"` - ConfigClusterMgmt ConfigClusterMgmt `json:"config_cluster_mgmt,omitempty" bson:"config_cluster_mgmt,omitempty"` - ConfigObservability ConfigObservability `json:"config_observability,omitempty" bson:"config_observability,omitempty"` - ConfigPurgeOldDBEntries ConfigPurgeOldDBEntries `json:"config_purge_old_db_entries,omitempty" bson:"config_purge_old_db_entries,omitempty"` - ConfigRecommendPolicy ConfigRecommendPolicy `json:"config_recommend_policy,omitempty" bson:"config_recommend_policy,omitempty"` - ConfigAutoDepolyDiscoveredPolicy bool `json:"config_dsp,omitempty" bson:"config_dsp,omitempty"` + ConfigNetPolicy ConfigNetworkPolicy `json:"config_network_policy,omitempty" bson:"config_network_policy,omitempty"` + ConfigSysPolicy ConfigSystemPolicy `json:"config_system_policy,omitempty" bson:"config_system_policy,omitempty"` + ConfigAdmissionControllerPolicy ConfigAdmissionControllerPolicy `json:"config_admission_controller_policy,omitempty" bson:"config_admission_controller_policy,omitempty"` + ConfigClusterMgmt ConfigClusterMgmt `json:"config_cluster_mgmt,omitempty" bson:"config_cluster_mgmt,omitempty"` + ConfigObservability ConfigObservability `json:"config_observability,omitempty" bson:"config_observability,omitempty"` + ConfigPurgeOldDBEntries ConfigPurgeOldDBEntries `json:"config_purge_old_db_entries,omitempty" bson:"config_purge_old_db_entries,omitempty"` + ConfigRecommendPolicy ConfigRecommendPolicy `json:"config_recommend_policy,omitempty" bson:"config_recommend_policy,omitempty"` + ConfigAutoDepolyDiscoveredPolicy bool `json:"config_dsp,omitempty" bson:"config_dsp,omitempty"` + ConfigCrownjewelPolicy ConfigCrownjewelPolicy `json:"config_crownjewel_policy,omitempty" bson:"config_crownjewel_policy,omitempty"` } diff --git a/src/types/policyData.go b/src/types/policyData.go index d369ebd4..420316ac 100644 --- a/src/types/policyData.go +++ b/src/types/policyData.go @@ -247,6 +247,7 @@ type KnoxMatchPaths struct { ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` OwnerOnly bool `json:"ownerOnly,omitempty" yaml:"ownerOnly,omitempty"` FromSource []KnoxFromSource `json:"fromSource,omitempty" yaml:"fromSource,omitempty"` + Action string `json:"action,omitempty"` } // KnoxMatchDirectories Structure @@ -256,6 +257,7 @@ type KnoxMatchDirectories struct { ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"` OwnerOnly bool `json:"ownerOnly,omitempty" yaml:"ownerOnly,omitempty"` FromSource []KnoxFromSource `json:"fromSource,omitempty" yaml:"fromSource,omitempty"` + Action string `json:"action,omitempty"` } // KnoxMatchProtocols Structure