Skip to content

Commit

Permalink
Adapt k8s-1.30 PSS
Browse files Browse the repository at this point in the history
  • Loading branch information
takara9 committed Jun 4, 2024
1 parent 29ea0f3 commit db80933
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ENVTEST_K8S_VERSION = 1.27.1
ENVTEST_K8S_VERSION = 1.30.0

# Set the shell used to bash for better error handling.
SHELL = /bin/bash
Expand Down
1 change: 1 addition & 0 deletions hooks/ephemeral_container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ metadata:
namespace: %s
name: %s
spec:
hostUsers: false
containers:
- name: ubuntu
image: ghcr.io/cybozu/ubuntu
Expand Down
2 changes: 1 addition & 1 deletion hooks/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ var _ = BeforeSuite(func() {
},
},
}
testEnv.ControlPlane.GetAPIServer().Configure().Append("feature-gates", "ProcMountType=true")
testEnv.ControlPlane.GetAPIServer().Configure().Append("feature-gates", "ProcMountType=true", "UserNamespacesSupport=true")

var err error
k8sConfig, err = testEnv.Start()
Expand Down
20 changes: 20 additions & 0 deletions hooks/testdata/baseline/apparmor-profile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: v1
kind: Pod
metadata:
name: apparmorprofile0
spec:
securityContext:
appArmorProfile:
type: RuntimeDefault
containers:
- image: registry.k8s.io/pause
name: container1
securityContext:
appArmorProfile:
type: RuntimeDefault
initContainers:
- image: registry.k8s.io/pause
name: initcontainer1
securityContext:
appArmorProfile:
type: RuntimeDefault
22 changes: 22 additions & 0 deletions hooks/testdata/privileged/apparmor-profile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: v1
kind: Pod
metadata:
name: apparmorprofile1
spec:
securityContext:
runAsNonRoot: true
appArmorProfile:
type: RuntimeDefault
containers:
- image: registry.k8s.io/pause
name: container1
securityContext:
appArmorProfile:
type: RuntimeDefault
initContainers:
- image: registry.k8s.io/pause
name: initcontainer1
securityContext:
appArmorProfile:
type: Localhost
localhostProfile: k8s-apparmor-example-deny-write
1 change: 1 addition & 0 deletions hooks/testdata/privileged/procmount1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ metadata:
annotations:
test.pod-security.cybozu.com/message: "denied the request: spec.containers[0].securityContext.procMount: Forbidden: ProcMountType Unmasked is not allowed"
spec:
hostUsers: false
securityContext:
runAsNonRoot: true
containers:
Expand Down
1 change: 1 addition & 0 deletions hooks/testdata/privileged/procmount2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ metadata:
annotations:
test.pod-security.cybozu.com/message: "denied the request: spec.initContainers[0].securityContext.procMount: Forbidden: ProcMountType Unmasked is not allowed"
spec:
hostUsers: false
securityContext:
runAsNonRoot: true
containers:
Expand Down
21 changes: 21 additions & 0 deletions hooks/testdata/restricted/apparmor-profile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: v1
kind: Pod
metadata:
name: apparmorprofile2
spec:
securityContext:
runAsNonRoot: true
appArmorProfile:
type: RuntimeDefault
containers:
- image: registry.k8s.io/pause
name: container1
securityContext:
appArmorProfile:
type: RuntimeDefault
initContainers:
- image: registry.k8s.io/pause
name: initcontainer1
securityContext:
appArmorProfile:
type: RuntimeDefault
23 changes: 23 additions & 0 deletions hooks/testdata/restricted/safe-sysctl2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: v1
kind: Pod
metadata:
name: safe-sysctl-2
spec:
securityContext:
runAsNonRoot: true
sysctls:
- name: net.ipv4.ping_group_range
value: "100 100"
- name: net.ipv4.ip_local_reserved_ports
value: "8080,9148"
- name: net.ipv4.tcp_keepalive_time
value: "100"
- name: net.ipv4.tcp_fin_timeout
value: "10"
- name: net.ipv4.tcp_keepalive_intvl
value: "60"
- name: net.ipv4.tcp_keepalive_probes
value: "5"
containers:
- name: ubuntu
image: ghcr.io/cybozu/ubuntu
3 changes: 0 additions & 3 deletions hooks/validate_pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,18 @@ var _ = Describe("validate Pod webhook", func() {
validatePod(filepath.Join("testdata", "baseline"), "privileged", true)
validatePod(filepath.Join("testdata", "restricted"), "privileged", true)
})

It("should deny privileged pods in hostpath namespace", func() {
validatePod(filepath.Join("testdata", "privileged"), "hostpath", false)
validatePod(filepath.Join("testdata", "hostpath"), "hostpath", true)
validatePod(filepath.Join("testdata", "baseline"), "hostpath", true)
validatePod(filepath.Join("testdata", "restricted"), "hostpath", true)
})

It("should deny privileged and hostpath pods in baseline namespace", func() {
validatePod(filepath.Join("testdata", "privileged"), "baseline", false)
validatePod(filepath.Join("testdata", "hostpath"), "baseline", false)
validatePod(filepath.Join("testdata", "baseline"), "baseline", true)
validatePod(filepath.Join("testdata", "restricted"), "baseline", true)
})

It("should deny privileged, hostpath, and baseline pods in restricted namespace", func() {
validatePod(filepath.Join("testdata", "privileged"), "restricted", false)
validatePod(filepath.Join("testdata", "hostpath"), "restricted", false)
Expand Down
40 changes: 40 additions & 0 deletions hooks/validators/deny_unsafe_apparmor.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,45 @@ func (v DenyUnsafeAppArmor) Validate(ctx context.Context, pod *corev1.Pod) field
errs = append(errs, field.Forbidden(p.Key(k), fmt.Sprintf("%s is not an allowed AppArmor profile", v)))
}
}

p0 := field.NewPath("spec").Child("SecurityContext")
hasPodAppArmorProfile := pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.AppArmorProfile != nil
if hasPodAppArmorProfile {
isTypeUnconfined := pod.Spec.SecurityContext.AppArmorProfile.Type == corev1.AppArmorProfileTypeUnconfined
isTypeRuntimeDefault := pod.Spec.SecurityContext.AppArmorProfile.Type == corev1.AppArmorProfileTypeRuntimeDefault
isTypeLocalhost := pod.Spec.SecurityContext.AppArmorProfile.Type == corev1.AppArmorProfileTypeLocalhost
hasNotAllowedType := !(isTypeUnconfined || isTypeRuntimeDefault || isTypeLocalhost)
if hasNotAllowedType {
errs = append(errs, field.Forbidden(p0.Child("AppArmorProfile"), "not an allowed *** AppArmor *** profile"))
}
}

p1 := p.Child("containers")
for i, co := range pod.Spec.Containers {
hasPodAppArmorProfile := co.SecurityContext != nil && co.SecurityContext.AppArmorProfile != nil
if hasPodAppArmorProfile {
isTypeUnconfined := co.SecurityContext.AppArmorProfile.Type == corev1.AppArmorProfileTypeUnconfined
isTypeRuntimeDefault := co.SecurityContext.AppArmorProfile.Type == corev1.AppArmorProfileTypeRuntimeDefault
isTypeLocalhost := co.SecurityContext.AppArmorProfile.Type == corev1.AppArmorProfileTypeLocalhost
hasNotAllowedType := !(isTypeUnconfined || isTypeRuntimeDefault || isTypeLocalhost)
if hasNotAllowedType {
errs = append(errs, field.Forbidden( p1.Index(i), fmt.Sprintf("%s not an allowed *** AppArmor *** profile", "any" )))
}
}
}

p2 := p.Child("initContainers")
for i, co := range pod.Spec.Containers {
hasPodAppArmorProfile := co.SecurityContext != nil && co.SecurityContext.AppArmorProfile != nil
if hasPodAppArmorProfile {
isTypeUnconfined := co.SecurityContext.AppArmorProfile.Type == corev1.AppArmorProfileTypeUnconfined
isTypeRuntimeDefault := co.SecurityContext.AppArmorProfile.Type == corev1.AppArmorProfileTypeRuntimeDefault
isTypeLocalhost := co.SecurityContext.AppArmorProfile.Type == corev1.AppArmorProfileTypeLocalhost
hasNotAllowedType := !(isTypeUnconfined || isTypeRuntimeDefault || isTypeLocalhost)
if hasNotAllowedType {
errs = append(errs, field.Forbidden( p2.Index(i), fmt.Sprintf("%s not an allowed *** AppArmor *** profile", "any" )))
}
}
}
return errs
}
5 changes: 5 additions & 0 deletions hooks/validators/deny_unsafe_sysctls.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ var allowedSysctls = map[string]struct{}{
"net.ipv4.tcp_syncookies": {},
"net.ipv4.ping_group_range": {},
"net.ipv4.ip_unprivileged_port_start": {},
"net.ipv4.ip_local_reserved_ports": {}, // since Kubernetes 1.27
"net.ipv4.tcp_keepalive_time": {}, // since Kubernetes 1.29
"net.ipv4.tcp_fin_timeout": {}, // since Kubernetes 1.29
"net.ipv4.tcp_keepalive_intvl": {}, // since Kubernetes 1.29
"net.ipv4.tcp_keepalive_probes": {}, // since Kubernetes 1.29
}

// DenyUnsafeSysctls is a Validator that denies usage of unsafe sysctls
Expand Down

0 comments on commit db80933

Please sign in to comment.