Skip to content

Commit

Permalink
Add test for Pod security admission controller
Browse files Browse the repository at this point in the history
Signed-off-by: michal.gubricky <[email protected]>
  • Loading branch information
michal-gubricky committed Sep 24, 2024
1 parent 50b72b7 commit b419044
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Tests/kaas/k8s-cluster-hardening/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ dev-prerequests:


dev-setup: kind-init
kind create cluster --name ${KIND_CLUSTER}
kind create cluster --name ${KIND_CLUSTER} --config kind-config.yaml


dev-build: container-init
Expand Down
15 changes: 15 additions & 0 deletions Tests/kaas/k8s-cluster-hardening/kind-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
kubeadmConfigPatches:
- |
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
metadata:
name: config
apiServer:
extraArgs:
enable-admission-plugins: "NodeRestriction,PodSecurity"
nodes:
- role: control-plane
- role: worker
- role: worker
101 changes: 98 additions & 3 deletions Tests/kaas/k8s-cluster-hardening/scs_0217_cluster_hardening_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func Test_scs_0217_sonobuoy_Kubelet_Webhook_Authorization_Enabled(t *testing.T)
}

// Test_NodeRestriction_Admission_Controller_Enabled checks if the NodeRestriction admission controller is enabled.
func Test_NodeRestriction_Admission_Controller_Enabled_in_KubeAPIServer(t *testing.T) {
func Test_scs_0217_sonobuoy_NodeRestriction_Admission_Controller_Enabled_in_KubeAPIServer(t *testing.T) {
f := features.New("kube-apiserver admission plugins").Assess(
"Check if NodeRestriction admission plugin is enabled in kube-apiserver pods",
func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
Expand Down Expand Up @@ -293,14 +293,14 @@ func Test_NodeRestriction_Admission_Controller_Enabled_in_KubeAPIServer(t *testi
flagFound := false
for _, cmd := range container.Command {
if strings.Contains(cmd, "--enable-admission-plugins=NodeRestriction") {
t.Logf("✅ NodeRestriction admission plugin is enabled in container: %s of pod: %s", container.Name, pod.Name)
t.Logf("✅ NodeRestriction admission plugin is enabled in pod: %s", pod.Name)
flagFound = true
break
}
}

if !flagFound {
t.Errorf("❌ ERROR: NodeRestriction admission plugin is not enabled in container: %s of pod: %s", container.Name, pod.Name)
t.Errorf("❌ ERROR: NodeRestriction admission plugin is not enabled in pod: %s", pod.Name)
}
}
}
Expand All @@ -311,6 +311,34 @@ func Test_NodeRestriction_Admission_Controller_Enabled_in_KubeAPIServer(t *testi
testenv.Test(t, f.Feature())
}

func Test_scs_0217_sonobuoy_PodSecurity_Standards_And_Admission_Controller_Enabled(t *testing.T) {
f := features.New("pod security standards").Assess(
"Pod security admission controller should be enabled and enforce Baseline/Restricted policies",
func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
// Create an in-cluster Kubernetes client configuration
restConf, err := rest.InClusterConfig()
if err != nil {
t.Fatal("failed to create rest config:", err)
}

// Create a Kubernetes clientset
kubeClient, err := kubernetes.NewForConfig(restConf)
if err != nil {
t.Fatal("failed to create Kubernetes client:", err)
}

// Step 1: Check that the PodSecurity admission controller is enabled in the kube-apiserver pods
checkPodSecurityAdmissionControllerEnabled(t, kubeClient)

// Step 2: Verify that Pod Security Standards (Baseline/Restricted) are enforced on namespaces
checkPodSecurityPoliciesEnforced(t, kubeClient)

return ctx
})

testenv.Test(t, f.Feature())
}

// checkPortOpen tries to establish a TCP connection to the given IP and port.
// It returns true if the port is open and false if the connection is refused or times out.
func checkPortOpen(ip, port string, timeout time.Duration) bool {
Expand Down Expand Up @@ -449,3 +477,70 @@ func getNodeEndpoint(client rest.Interface, nodeName, endpoint string) (rest.Res
}
return result, result.Error()
}

// checkPodSecurityAdmissionControllerEnabled checks if the PodSecurity admission controller is enabled in kube-apiserver pods
func checkPodSecurityAdmissionControllerEnabled(t *testing.T, kubeClient *kubernetes.Clientset) {
// List all pods in the kube-system namespace with label "component=kube-apiserver"
podList, err := kubeClient.CoreV1().Pods("kube-system").List(context.TODO(), v1.ListOptions{
LabelSelector: "component=kube-apiserver",
})
if err != nil {
t.Fatal("failed to list kube-apiserver pods:", err)
}

// Check each kube-apiserver pod
for _, pod := range podList.Items {
t.Logf("Checking pod: %s for PodSecurity admission controller", pod.Name)

// Check each container in the pod
for _, container := range pod.Spec.Containers {
admissionPluginsFound := false

// Look for the enable-admission-plugins flag in container command
for _, cmd := range container.Command {
if strings.Contains(cmd, "--enable-admission-plugins=") {
admissionPluginsFound = true

// Extract the plugins list and check if PodSecurity is one of them
plugins := strings.Split(cmd, "=")[1]
if strings.Contains(plugins, "PodSecurity") {
t.Logf("✅ PodSecurity admission plugin is enabled in container: %s of pod: %s", container.Name, pod.Name)
} else {
t.Errorf("❌ ERROR: PodSecurity admission plugin is not enabled in container: %s of pod: %s", container.Name, pod.Name)
}
break
}
}

if !admissionPluginsFound {
t.Errorf("❌ ERROR: --enable-admission-plugins flag not found in container: %s of pod: %s", container.Name, pod.Name)
}
}
}
}

// checkPodSecurityPoliciesEnforced checks if Baseline and Restricted policies are enforced on namespaces
func checkPodSecurityPoliciesEnforced(t *testing.T, kubeClient *kubernetes.Clientset) {
// List all namespaces
namespaceList, err := kubeClient.CoreV1().Namespaces().List(context.TODO(), v1.ListOptions{})
if err != nil {
t.Fatal("failed to list namespaces:", err)
}

// Check for the "pod-security.kubernetes.io/enforce" annotation in each namespace
for _, namespace := range namespaceList.Items {
annotations := namespace.Annotations
enforcePolicy, ok := annotations["pod-security.kubernetes.io/enforce"]
if !ok {
t.Logf("⚠️ Namespace %s does not have an enforce policy annotation", namespace.Name)
continue
}

// Check if the policy is either Baseline or Restricted
if enforcePolicy == "baseline" || enforcePolicy == "restricted" {
t.Logf("✅ Namespace %s enforces the %s policy", namespace.Name, enforcePolicy)
} else {
t.Errorf("❌ ERROR: Namespace %s does not enforce Baseline or Restricted policy, but has %s", namespace.Name, enforcePolicy)
}
}
}

0 comments on commit b419044

Please sign in to comment.