Skip to content

Commit

Permalink
restructure policy format to remove redundant allow rule
Browse files Browse the repository at this point in the history
Signed-off-by: Ankur Kothiwal <ankur.kothiwal99@gmail.com>
  • Loading branch information
Ankurk99 committed Jun 7, 2023
1 parent 748818f commit b722107
Showing 1 changed file with 68 additions and 44 deletions.
112 changes: 68 additions & 44 deletions src/crownjewel/crownjewel.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import (
"context"
"encoding/json"
"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"
Expand Down Expand Up @@ -95,6 +97,7 @@ func StopCrownjewelCronJob() {
}
}

// Create Crown Jewel Policy based on K8s object type
func CrownjewelPolicyMain() {
client := cluster.ConnectK8sClient()
deployments, err := client.AppsV1().Deployments("").List(context.Background(), metav1.ListOptions{})
Expand All @@ -118,34 +121,34 @@ func CrownjewelPolicyMain() {
return
}
for _, d := range deployments.Items {
_, err := GetMountPaths(client, d.Name, d.Namespace, d.Spec.Template.Labels)
err := getCrownjewelPolicy(client, d.Name, d.Namespace, d.Spec.Template.Labels)
if err != nil {
log.Error().Msg("Error getting mount paths, err=" + err.Error())
}
}
for _, r := range replicaSets.Items {
_, err := GetMountPaths(client, r.Name, r.Namespace, r.Spec.Template.Labels)
err := getCrownjewelPolicy(client, r.Name, r.Namespace, r.Spec.Template.Labels)
if err != nil {
log.Error().Msg("Error getting mount paths, err=" + err.Error())
}
}
for _, s := range statefulSets.Items {
_, err := GetMountPaths(client, s.Name, s.Namespace, s.Spec.Template.Labels)
err := getCrownjewelPolicy(client, s.Name, s.Namespace, s.Spec.Template.Labels)
if err != nil {
log.Error().Msg("Error getting mount paths, err=" + err.Error())
}
}
for _, rs := range daemonsets.Items {
_, err := GetMountPaths(client, rs.Name, rs.Namespace, rs.Spec.Template.Labels)
err := getCrownjewelPolicy(client, rs.Name, rs.Namespace, rs.Spec.Template.Labels)
if err != nil {
log.Error().Msg("Error getting mount paths, err=" + err.Error())
}
}
}

// var log *zerolog.Logger
type LabelMap = map[string]string

// Get list of running processes from observability data
func getProcessList(client kubernetes.Interface, namespace string, labels types.LabelMap) ([]string, error) {
var processList []string
duplicatePaths := make(map[string]bool)
Expand All @@ -165,12 +168,16 @@ func getProcessList(client kubernetes.Interface, namespace string, labels types.
Type: "process,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())
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 {
if !duplicatePaths[fileData.Source] {
// ignore serviceaccount related process
if strings.Contains(fileData.Destination, "serviceaccount") {
continue
}
processList = append(processList, fileData.Source)
duplicatePaths[fileData.Source] = true
}
Expand All @@ -180,6 +187,28 @@ func getProcessList(client kubernetes.Interface, namespace string, labels types.
return processList, nil
}

// Get all mounted paths
func getVolumeMountPaths(client kubernetes.Interface, labels LabelMap) ([]string, error) {
podList, err := client.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{
LabelSelector: libs.LabelMapToString(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 {
mountPaths = append(mountPaths, volumeMount.MountPath)
}
}
}
return mountPaths, nil
}

// Get used mount paths from observability data
func usedMountPath(client kubernetes.Interface, namespace string, labels types.LabelMap) ([]string, map[string]string, error) {
var sumResponses []string
fromSource := make(map[string]string)
Expand All @@ -200,7 +229,7 @@ func usedMountPath(client kubernetes.Interface, namespace string, labels types.L
Type: "process,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())
log.Warn().Msgf("Error getting summary data for pod %s, container %s, namespace %s: %s", pod.Name, container.Name, pod.Namespace, err.Error())
break
}

Expand All @@ -213,26 +242,7 @@ func usedMountPath(client kubernetes.Interface, namespace string, labels types.L
return sumResponses, fromSource, nil
}

func getVolumeMountPaths(client kubernetes.Interface, labels LabelMap) ([]string, error) {
podList, err := client.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{
LabelSelector: libs.LabelMapToString(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 {
mountPaths = append(mountPaths, volumeMount.MountPath)
}
}
}
return mountPaths, 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)
Expand All @@ -248,19 +258,18 @@ func accessedMountPaths(sumResp, mnt []string) ([]string, error) {
return matchedMountPaths, nil
}

func GetMountPaths(client kubernetes.Interface, name, namespace string, labels LabelMap) ([]string, error) {

// Generate crown jewel policy
func getCrownjewelPolicy(client kubernetes.Interface, cname, namespace string, labels LabelMap) error {
var policies []types.KnoxSystemPolicy

var mountPaths []string
var matchedMountPaths []string
var ms types.MatchSpec
action := "Allow"

// mount paths being used (from observability)
sumResp, fromSrc, _ := usedMountPath(client, namespace, labels)

// total mount paths being used (from k8s cluster)
// 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)
Expand All @@ -269,14 +278,15 @@ func GetMountPaths(client kubernetes.Interface, name, namespace string, labels L
// process paths being used and are present in observability data
matchedProcessPaths, _ := getProcessList(client, namespace, labels)

// filters to check the namespaces to be ignored
nsFilter := config.CurrentCfg.ConfigSysPolicy.NsFilter
nsNotFilter := config.CurrentCfg.ConfigSysPolicy.NsNotFilter

if len(nsFilter) > 0 {
for _, ns := range nsFilter {
if strings.Contains(namespace, ns) {
policy := createCrownjewelPolicy(ms, name, namespace, action, labels, mnt, matchedMountPaths, matchedProcessPaths, fromSrc)

policy := createCrownjewelPolicy(ms, cname, namespace, action, labels, mnt, matchedMountPaths, matchedProcessPaths, fromSrc)
// 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 {
continue
Expand All @@ -287,7 +297,8 @@ func GetMountPaths(client kubernetes.Interface, name, namespace string, labels L
} else if len(nsNotFilter) > 0 {
for _, notns := range nsNotFilter {
if !strings.Contains(namespace, notns) {
policy := createCrownjewelPolicy(ms, name, namespace, action, labels, mnt, matchedMountPaths, matchedProcessPaths, fromSrc)
policy := createCrownjewelPolicy(ms, cname, namespace, action, labels, mnt, matchedMountPaths, matchedProcessPaths, fromSrc)
// 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 {
continue
Expand All @@ -300,26 +311,39 @@ func GetMountPaths(client kubernetes.Interface, name, namespace string, labels L
jsonData, err := json.Marshal(policies)
if err != nil {
log.Error().Msg("Error marshaling" + err.Error())
return nil, nil
return nil
}
yamlData, err := yaml.JSONToYAML(jsonData)
if err != nil {
log.Error().Msg("Error converting JSON to YAML:" + err.Error())
return nil, nil
return nil
}
fmt.Println(string(yamlData))

systempolicy.UpdateSysPolicies(policies)

return mountPaths, nil
return nil
}

func buildSystemPolicy(name, ns, action string, labels LabelMap, matchDirs []types.KnoxMatchDirectories, matchPaths []types.KnoxMatchPaths) types.KnoxSystemPolicy {
// Build Crown jewel System policy structure
func buildSystemPolicy(cname, ns, action string, labels LabelMap, matchDirs []types.KnoxMatchDirectories, matchPaths []types.KnoxMatchPaths) types.KnoxSystemPolicy {
clustername := config.GetCfgClusterName()

// expand the labels to be in string format
var combinedLabels []string
for key, value := range labels {
label := fmt.Sprintf("%s=%s", key, value)
combinedLabels = append(combinedLabels, label)
}
labelsString := strings.Join(combinedLabels, ",")

// create policy name
name := strconv.FormatUint(uint64(common.HashInt(ns+clustername+cname+labelsString)), 10)
return types.KnoxSystemPolicy{
APIVersion: "v1",
Kind: "KubeArmorPolicy",
Metadata: map[string]string{
"name": "autopol-assets-" + name,
"name": "autopol-sensitive-" + name,
"namespace": ns,
},
Spec: types.KnoxSystemSpec{
Expand All @@ -338,11 +362,13 @@ func buildSystemPolicy(name, ns, action string, labels LabelMap, matchDirs []typ
}
}

func createCrownjewelPolicy(ms types.MatchSpec, name, namespace, action string, labels LabelMap, matchedDirPts, matchedMountPts, matchedProcessPts []string, fromSrc map[string]string) types.KnoxSystemPolicy {
func createCrownjewelPolicy(ms types.MatchSpec, cname, namespace, action string, labels LabelMap, matchedDirPts, matchedMountPts, matchedProcessPts []string, fromSrc map[string]string) types.KnoxSystemPolicy {
var matchDirs []types.KnoxMatchDirectories
i := 1
for _, dirpath := range matchedDirPts {
action = "Block"
// TODO: handle serviceaccount token access
// ignore serviceaccount token related accesses
if strings.Contains(dirpath, "serviceaccount") {
continue
}
Expand Down Expand Up @@ -375,7 +401,6 @@ func createCrownjewelPolicy(ms types.MatchSpec, name, namespace, action string,
Dir: dirpath + "/",
Recursive: true,
FromSource: fromSourceVal,
Action: action,
}

if action == "Allow" {
Expand Down Expand Up @@ -404,13 +429,12 @@ func createCrownjewelPolicy(ms types.MatchSpec, name, namespace, action string,
var matchPaths []types.KnoxMatchPaths
for _, processpath := range matchedProcessPts {
matchPath := types.KnoxMatchPaths{
Path: processpath,
Action: "Allow",
Path: processpath,
}
matchPaths = append(matchPaths, matchPath)
}

policy := buildSystemPolicy(name, namespace, action, labels, matchDirs, matchPaths)
policy := buildSystemPolicy(cname, namespace, action, labels, matchDirs, matchPaths)

return policy
}

0 comments on commit b722107

Please sign in to comment.