Skip to content

Commit

Permalink
Merge pull request #97 from VedRatan/profile_params_kyverno
Browse files Browse the repository at this point in the history
(feat): added profile params support and labels support
  • Loading branch information
shivaccuknox authored May 2, 2024
2 parents e2fa7b9 + 2bd7802 commit b8330d5
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 49 deletions.
1 change: 1 addition & 0 deletions examples/clusterscoped/escape-to-host-si-sib.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ spec:
id: escapeToHost
description: "A attacker can breach container boundaries and can gain access to the host machine"
action: Block

---
apiVersion: intent.security.nimbus.com/v1
kind: ClusterSecurityIntentBinding
Expand Down
105 changes: 68 additions & 37 deletions pkg/adapter/nimbus-kyverno/processor/kcpbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ package processor

import (
"strings"

v1 "github.com/5GSEC/nimbus/api/v1"
"github.com/5GSEC/nimbus/pkg/adapter/idpool"
"github.com/5GSEC/nimbus/pkg/adapter/nimbus-kyverno/utils"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -20,7 +22,7 @@ func BuildKcpsFrom(logger logr.Logger, cnp *v1.ClusterNimbusPolicy) []kyvernov1.
id := nimbusRule.ID
if idpool.IsIdSupportedBy(id, "kyverno") {
kcp := buildKcpFor(id, cnp)
kcp.Name = cnp.Name + "-" + strings.ToLower(id)+ "-" +strings.ToLower(id)
kcp.Name = cnp.Name + "-" + strings.ToLower(id)
kcp.Annotations = make(map[string]string)
kcp.Annotations["policies.kyverno.io/description"] = nimbusRule.Description
if nimbusRule.Rule.RuleAction == "Block" {
Expand All @@ -42,57 +44,86 @@ func BuildKcpsFrom(logger logr.Logger, cnp *v1.ClusterNimbusPolicy) []kyvernov1.
func buildKcpFor(id string, cnp *v1.ClusterNimbusPolicy) kyvernov1.ClusterPolicy {
switch id {
case idpool.EscapeToHost:
return clusterEscapeToHost(cnp)
return clusterEscapeToHost(cnp, cnp.Spec.NimbusRules[0].Rule)
default:
return kyvernov1.ClusterPolicy{}
}
}

func clusterEscapeToHost(cnp *v1.ClusterNimbusPolicy) kyvernov1.ClusterPolicy {
func clusterEscapeToHost(cnp *v1.ClusterNimbusPolicy, rule v1.Rule) kyvernov1.ClusterPolicy {
var psa_level api.Level = api.LevelBaseline

labelsPerNamespace := make(map[string]map[string]string) //todo: what if we want to apply policy to multiple resources in different namespaces?
if rule.Params["psa_level"] != nil {

// Function to add or update values for a key
addOrUpdate := func(key string, innerMap map[string]string) {
if val, ok := labelsPerNamespace[key]; ok {
// Key exists, update the inner map
for k, v := range innerMap {
val[k] = v
}
labelsPerNamespace[key] = val
} else {
// Key does not exist, add a new entry
labelsPerNamespace[key] = innerMap
switch rule.Params["psa_level"][0] {
case "restricted":
psa_level = api.LevelRestricted

case "privileged":
psa_level = api.LevelPrivileged

default:
psa_level = api.LevelBaseline
}

}

var resourceFilters []kyvernov1.ResourceFilter

for _,resource := range cnp.Spec.Selector.Resources {
namespace := resource.Namespace
addOrUpdate(namespace, resource.MatchLabels)
}
kind := resource.Kind
name := resource.Name
switch kind {
case "Namespace":
resourceFilterForNamespace := kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{
utils.GetGVK("pod"),
},
Namespaces: []string{
name,
},
},
}

var resourceFilters []kyvernov1.ResourceFilter
var resourceFilter kyvernov1.ResourceFilter
resourceFilters = append(resourceFilters, resourceFilterForNamespace)

for namespace, labels := range labelsPerNamespace {
resourceFilter = kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{
"v1/Pod",
},
Namespaces: []string{
namespace,
},
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
},
}
default:
namespace := resource.Namespace
labels := resource.MatchLabels
var resourceFilter kyvernov1.ResourceFilter
if len(labels) != 0 {
resourceFilter = kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{
"v1/Pod",
},
Namespaces: []string{
namespace,
},
Selector: &metav1.LabelSelector{
MatchLabels: labels,
},
},
}
} else {
resourceFilter = kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{
"v1/Pod",
},
Namespaces: []string{
namespace,
},
},
}
}

resourceFilters = append(resourceFilters, resourceFilter)
}

resourceFilters = append(resourceFilters, resourceFilter)

}
}
background := true
return kyvernov1.ClusterPolicy{
Spec: kyvernov1.Spec{
Expand All @@ -105,7 +136,7 @@ func clusterEscapeToHost(cnp *v1.ClusterNimbusPolicy) kyvernov1.ClusterPolicy {
},
Validation: kyvernov1.Validation{
PodSecurity : &kyvernov1.PodSecurity{
Level: api.LevelRestricted,
Level: psa_level,
Version: "latest",
},
},
Expand Down
58 changes: 46 additions & 12 deletions pkg/adapter/nimbus-kyverno/processor/kpbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ package processor

import (
"strings"

v1 "github.com/5GSEC/nimbus/api/v1"
"github.com/5GSEC/nimbus/pkg/adapter/idpool"
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"k8s.io/pod-security-admission/api"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "github.com/5GSEC/nimbus/api/v1"
"github.com/5GSEC/nimbus/pkg/adapter/idpool"
"k8s.io/pod-security-admission/api"
)

func BuildKpsFrom(logger logr.Logger, np *v1.NimbusPolicy) []kyvernov1.Policy {
Expand Down Expand Up @@ -43,17 +44,46 @@ func BuildKpsFrom(logger logr.Logger, np *v1.NimbusPolicy) []kyvernov1.Policy {
func buildKpFor(id string, np *v1.NimbusPolicy) kyvernov1.Policy {
switch id {
case idpool.EscapeToHost:
return escapeToHost(np)
return escapeToHost(np, np.Spec.NimbusRules[0].Rule)
default:
return kyvernov1.Policy{}
}
}

func escapeToHost(np *v1.NimbusPolicy) kyvernov1.Policy {
func escapeToHost(np *v1.NimbusPolicy, rule v1.Rule) kyvernov1.Policy {
background := true
return kyvernov1.Policy{
var psa_level api.Level = api.LevelBaseline

if rule.Params["psa_level"] != nil {

switch rule.Params["psa_level"][0] {
case "restricted":
psa_level = api.LevelRestricted

case "privileged":
psa_level = api.LevelPrivileged

default:
psa_level = api.LevelBaseline
}

}

labels := np.Spec.Selector.MatchLabels
lis := rule.Params["exclude_resources"]
exclusionLables := make(map[string]string)
for _, item := range lis {
parts := strings.Split(item, ":")
if len(parts) == 2 {
key := parts[0]
value := parts[1]
exclusionLables[key] = value
}
}

kp := kyvernov1.Policy{
Spec: kyvernov1.Spec{
Background: &background ,
Background: &background,
Rules: []kyvernov1.Rule{
{
Name: "restricted",
Expand All @@ -68,23 +98,27 @@ func escapeToHost(np *v1.NimbusPolicy) kyvernov1.Policy {
MatchLabels: np.Spec.Selector.MatchLabels,
},
},

},

},
},
Validation: kyvernov1.Validation{
PodSecurity : &kyvernov1.PodSecurity{
Level: api.LevelRestricted,
PodSecurity: &kyvernov1.PodSecurity{
Level: psa_level,
Version: "latest",
},
},
},
},
},
}

if len(labels) > 0 {
kp.Spec.Rules[0].MatchResources.Any[0].ResourceDescription.Selector.MatchLabels = labels
}

return kp
}

func addManagedByAnnotation(kp *kyvernov1.Policy) {
kp.Annotations["app.kubernetes.io/managed-by"] = "nimbus-kyverno"
}
}
2 changes: 2 additions & 0 deletions pkg/adapter/nimbus-kyverno/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ func GetGVK(kind string) string {
kind = "StatefulSet"
case "daemonset" :
kind = "DaemonSet"
default:
kind = Title(kind)
}

// Combine API version and kind to form the GroupVersionKind string
Expand Down

0 comments on commit b8330d5

Please sign in to comment.