Implement check_dropAllCapabilities.go and test/fixtures_dropAllCapabilities.go

This commit is contained in:
mgutierrez98 2021-07-05 01:07:57 +00:00 committed by Jordan Liggitt
parent b289fbb03d
commit a8793dcb3e
6 changed files with 253 additions and 0 deletions

View File

@ -0,0 +1,89 @@
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package policy
import (
"fmt"
"strings"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/pod-security-admission/api"
)
const (
capabilityAll = "ALL"
capabilityNetBindService = "CAP_NET_BIND_SERVICE"
)
func init() {
addCheck(CheckDropCapabilities)
}
// CheckDropCapabilities returns a restricted level check
// that ensures all capabilities are dropped in 1.22+
func CheckDropCapabilities() Check {
return Check{
ID: "dropCapabilities",
Level: api.LevelRestricted,
Versions: []VersionedCheck{
{
MinimumVersion: api.MajorMinorVersion(1, 22),
CheckPod: dropCapabilities_1_22,
},
},
}
}
func dropCapabilities_1_22(podMetadata *metav1.ObjectMeta, podSpec *corev1.PodSpec) CheckResult {
containers := sets.NewString()
visitContainersWithPath(podSpec, field.NewPath("spec"), func(container *corev1.Container, path *field.Path) {
if container.SecurityContext == nil || container.SecurityContext.Capabilities == nil {
containers.Insert(container.Name)
return
}
found := false
for _, c := range container.SecurityContext.Capabilities.Drop {
if c == capabilityAll {
found = true
break
}
}
if !found {
containers.Insert(container.Name)
return
}
for index, c := range container.SecurityContext.Capabilities.Add {
if c != capabilityNetBindService {
capabilityPath := path.Child("securityContext", "capabilities", "add").Index(index)
msg := fmt.Sprintf("%s=%s", capabilityPath.String(), string(c))
containers.Insert(msg)
}
}
})
if len(containers) > 0 {
return CheckResult{
Allowed: false,
ForbiddenReason: "containers must drop ALL capability",
ForbiddenDetail: strings.Join(containers.List(), ", "),
}
}
return CheckResult{Allowed: true}
}

View File

@ -49,6 +49,13 @@ func init() {
fixtureData_1_0 := fixtureGenerator{
expectErrorSubstring: "forbidden capabilities",
generatePass: func(p *corev1.Pod) []*corev1.Pod {
// don't generate fixtures if minimal valid pod drops ALL
for _, capability := range p.Spec.Containers[0].SecurityContext.Capabilities.Drop {
if capability == corev1.Capability("ALL") {
return nil
}
}
p = ensureCapabilities(p)
return []*corev1.Pod{
// all allowed capabilities

View File

@ -0,0 +1,102 @@
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/pod-security-admission/api"
)
/*
TODO: include field paths in reflect-based unit test
containerFields: []string{
`securityContext.capabilities.drop`,
},
*/
func init() {
fixtureData_1_22 := fixtureGenerator{
expectErrorSubstring: "drop all",
generatePass: func(p *corev1.Pod) []*corev1.Pod {
return []*corev1.Pod{
tweak(p, func(p *corev1.Pod) {
p.Spec.Containers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"}
p.Spec.InitContainers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"}
}),
tweak(p, func(p *corev1.Pod) {
p.Spec.Containers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"}
p.Spec.InitContainers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"}
p.Spec.Containers[0].SecurityContext.Capabilities.Add = []corev1.Capability{"CAP_NET_BIND_SERVICE"}
p.Spec.InitContainers[0].SecurityContext.Capabilities.Add = []corev1.Capability{"CAP_NET_BIND_SERVICE"}
}),
}
},
generateFail: func(p *corev1.Pod) []*corev1.Pod {
p = ensureCapabilities(p)
return []*corev1.Pod{
tweak(p, func(p *corev1.Pod) {
p.Spec.Containers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{}
p.Spec.InitContainers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{}
}),
tweak(p, func(p *corev1.Pod) {
p.Spec.Containers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{
"CAP_SYS_TIME", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_NICE",
"CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_AUDIT_WRITE",
"CAP_AUDIT_CONTROL", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_NET_ADMIN", "CAP_SYSLOG",
"CAP_CHOWN", "CAP_NET_RAW", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_DAC_READ_SEARCH",
"CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE",
"CAP_NET_BROADCAST", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE",
"CAP_SYS_BOOT", "CAP_LEASE", "CAP_SETFCAP", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND",
}
p.Spec.InitContainers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{
"CAP_SYS_TIME", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_NICE",
"CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_AUDIT_WRITE",
"CAP_AUDIT_CONTROL", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_NET_ADMIN", "CAP_SYSLOG",
"CAP_CHOWN", "CAP_NET_RAW", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_DAC_READ_SEARCH",
"CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_LINUX_IMMUTABLE", "CAP_NET_BIND_SERVICE",
"CAP_NET_BROADCAST", "CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE",
"CAP_SYS_BOOT", "CAP_LEASE", "CAP_SETFCAP", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND",
}
}),
tweak(p, func(p *corev1.Pod) {
p.Spec.Containers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"}
p.Spec.InitContainers[0].SecurityContext.Capabilities.Drop = []corev1.Capability{"ALL"}
p.Spec.Containers[0].SecurityContext.Capabilities.Add = []corev1.Capability{
"CAP_SYS_TIME", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_NICE",
"CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_AUDIT_WRITE",
"CAP_AUDIT_CONTROL", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_NET_ADMIN", "CAP_SYSLOG",
"CAP_CHOWN", "CAP_NET_RAW", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_DAC_READ_SEARCH",
"CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_LINUX_IMMUTABLE", "CAP_NET_BROADCAST",
"CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_BOOT", "CAP_LEASE",
"CAP_SETFCAP", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND",
}
p.Spec.InitContainers[0].SecurityContext.Capabilities.Add = []corev1.Capability{
"CAP_SYS_TIME", "CAP_SYS_MODULE", "CAP_SYS_RAWIO", "CAP_SYS_PACCT", "CAP_SYS_ADMIN", "CAP_SYS_NICE",
"CAP_SYS_RESOURCE", "CAP_SYS_TIME", "CAP_SYS_TTY_CONFIG", "CAP_MKNOD", "CAP_AUDIT_WRITE",
"CAP_AUDIT_CONTROL", "CAP_MAC_OVERRIDE", "CAP_MAC_ADMIN", "CAP_NET_ADMIN", "CAP_SYSLOG",
"CAP_CHOWN", "CAP_NET_RAW", "CAP_DAC_OVERRIDE", "CAP_FOWNER", "CAP_DAC_READ_SEARCH",
"CAP_FSETID", "CAP_KILL", "CAP_SETGID", "CAP_SETUID", "CAP_LINUX_IMMUTABLE", "CAP_NET_BROADCAST",
"CAP_IPC_LOCK", "CAP_IPC_OWNER", "CAP_SYS_CHROOT", "CAP_SYS_PTRACE", "CAP_SYS_BOOT", "CAP_LEASE",
"CAP_SETFCAP", "CAP_WAKE_ALARM", "CAP_BLOCK_SUSPEND",
}
}),
}
},
}
registerFixtureGenerator(
fixtureKey{level: api.LevelRestricted, version: api.MajorMinorVersion(1, 22), check: "dropCapabilities"},
fixtureData_1_22,
)
}

View File

@ -0,0 +1,19 @@
apiVersion: v1
kind: Pod
metadata:
name: dropcapabilities0
spec:
containers:
- image: k8s.gcr.io/pause
name: container1
securityContext:
allowPrivilegeEscalation: false
capabilities: {}
initContainers:
- image: k8s.gcr.io/pause
name: initcontainer1
securityContext:
allowPrivilegeEscalation: false
capabilities: {}
securityContext:
runAsNonRoot: true

View File

@ -0,0 +1,19 @@
apiVersion: v1
kind: Pod
metadata:
name: dropcapabilities1
spec:
containers:
- image: k8s.gcr.io/pause
name: container1
securityContext:
allowPrivilegeEscalation: false
capabilities: {}
initContainers:
- image: k8s.gcr.io/pause
name: initcontainer1
securityContext:
allowPrivilegeEscalation: false
capabilities: {}
securityContext:
runAsNonRoot: true

View File

@ -0,0 +1,17 @@
apiVersion: v1
kind: Pod
metadata:
name: dropcapabilities0
spec:
containers:
- image: k8s.gcr.io/pause
name: container1
securityContext:
allowPrivilegeEscalation: false
initContainers:
- image: k8s.gcr.io/pause
name: initcontainer1
securityContext:
allowPrivilegeEscalation: false
securityContext:
runAsNonRoot: true