Switched to profile-based AppArmor configuration (#4008)

Co-authored-by: qwerty287 <80460567+qwerty287@users.noreply.github.com>
This commit is contained in:
Thomas Anderson 2024-08-06 20:05:04 +03:00 committed by GitHub
parent dc10fb95ad
commit ca41540151
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 38 additions and 53 deletions

View file

@ -197,7 +197,7 @@ backend_options:
``` ```
:::note :::note
AppArmor syntax follows [KEP-24](https://github.com/kubernetes/enhancements/blob/fddcbb9cbf3df39ded03bad71228265ac6e5215f/keps/sig-node/24-apparmor/README.md). The feature requires Kubernetes v1.30 or above.
::: :::
### Annotations and labels ### Annotations and labels

View file

@ -84,7 +84,7 @@ func podMeta(step *types.Step, config *config, options BackendOptions, podName s
meta := meta_v1.ObjectMeta{ meta := meta_v1.ObjectMeta{
Name: podName, Name: podName,
Namespace: config.Namespace, Namespace: config.Namespace,
Annotations: podAnnotations(config, options, podName), Annotations: podAnnotations(config, options),
} }
meta.Labels, err = podLabels(step, config, options) meta.Labels, err = podLabels(step, config, options)
@ -126,7 +126,7 @@ func stepLabel(step *types.Step) (string, error) {
return toDNSName(step.Name) return toDNSName(step.Name)
} }
func podAnnotations(config *config, options BackendOptions, podName string) map[string]string { func podAnnotations(config *config, options BackendOptions) map[string]string {
annotations := make(map[string]string) annotations := make(map[string]string)
if len(options.Annotations) > 0 { if len(options.Annotations) > 0 {
@ -141,13 +141,6 @@ func podAnnotations(config *config, options BackendOptions, podName string) map[
log.Trace().Msgf("using annotations from the configuration: %v", config.PodAnnotations) log.Trace().Msgf("using annotations from the configuration: %v", config.PodAnnotations)
maps.Copy(annotations, config.PodAnnotations) maps.Copy(annotations, config.PodAnnotations)
} }
securityContext := options.SecurityContext
if securityContext != nil {
key, value := apparmorAnnotation(podName, securityContext.ApparmorProfile)
if key != nil && value != nil {
annotations[*key] = *value
}
}
return annotations return annotations
} }
@ -377,11 +370,12 @@ func toleration(backendToleration Toleration) v1.Toleration {
func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, stepPrivileged bool) *v1.PodSecurityContext { func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, stepPrivileged bool) *v1.PodSecurityContext {
var ( var (
nonRoot *bool nonRoot *bool
user *int64 user *int64
group *int64 group *int64
fsGroup *int64 fsGroup *int64
seccomp *v1.SeccompProfile seccomp *v1.SeccompProfile
apparmor *v1.AppArmorProfile
) )
if secCtxConf.RunAsNonRoot { if secCtxConf.RunAsNonRoot {
@ -410,6 +404,7 @@ func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, s
} }
seccomp = seccompProfile(sc.SeccompProfile) seccomp = seccompProfile(sc.SeccompProfile)
apparmor = apparmorProfile(sc.ApparmorProfile)
} }
if nonRoot == nil && user == nil && group == nil && fsGroup == nil && seccomp == nil { if nonRoot == nil && user == nil && group == nil && fsGroup == nil && seccomp == nil {
@ -417,11 +412,12 @@ func podSecurityContext(sc *SecurityContext, secCtxConf SecurityContextConfig, s
} }
securityContext := &v1.PodSecurityContext{ securityContext := &v1.PodSecurityContext{
RunAsNonRoot: nonRoot, RunAsNonRoot: nonRoot,
RunAsUser: user, RunAsUser: user,
RunAsGroup: group, RunAsGroup: group,
FSGroup: fsGroup, FSGroup: fsGroup,
SeccompProfile: seccomp, SeccompProfile: seccomp,
AppArmorProfile: apparmor,
} }
log.Trace().Msgf("pod security context that will be used: %v", securityContext) log.Trace().Msgf("pod security context that will be used: %v", securityContext)
return securityContext return securityContext
@ -443,6 +439,22 @@ func seccompProfile(scp *SecProfile) *v1.SeccompProfile {
return seccompProfile return seccompProfile
} }
func apparmorProfile(scp *SecProfile) *v1.AppArmorProfile {
if scp == nil || len(scp.Type) == 0 {
return nil
}
log.Trace().Msgf("using AppArmor profile: %v", scp)
apparmorProfile := &v1.AppArmorProfile{
Type: v1.AppArmorProfileType(scp.Type),
}
if len(scp.LocalhostProfile) > 0 {
apparmorProfile.LocalhostProfile = &scp.LocalhostProfile
}
return apparmorProfile
}
func containerSecurityContext(sc *SecurityContext, stepPrivileged bool) *v1.SecurityContext { func containerSecurityContext(sc *SecurityContext, stepPrivileged bool) *v1.SecurityContext {
if !stepPrivileged { if !stepPrivileged {
return nil return nil
@ -471,36 +483,6 @@ func containerSecurityContext(sc *SecurityContext, stepPrivileged bool) *v1.Secu
return nil return nil
} }
func apparmorAnnotation(containerName string, scp *SecProfile) (*string, *string) {
if scp == nil {
return nil, nil
}
log.Trace().Msgf("using AppArmor profile: %v", scp)
var (
profileType string
profilePath string
)
if scp.Type == SecProfileTypeRuntimeDefault {
profileType = "runtime"
profilePath = "default"
}
if scp.Type == SecProfileTypeLocalhost {
profileType = "localhost"
profilePath = scp.LocalhostProfile
}
if len(profileType) == 0 {
return nil, nil
}
key := v1.DeprecatedAppArmorBetaContainerAnnotationKeyPrefix + containerName
value := profileType + "/" + profilePath
return &key, &value
}
func mapToEnvVars(m map[string]string) []v1.EnvVar { func mapToEnvVars(m map[string]string) []v1.EnvVar {
var ev []v1.EnvVar var ev []v1.EnvVar
for k, v := range m { for k, v := range m {

View file

@ -162,7 +162,6 @@ func TestFullPod(t *testing.T) {
}, },
"annotations": { "annotations": {
"apps.kubernetes.io/pod-index": "0", "apps.kubernetes.io/pod-index": "0",
"container.apparmor.security.beta.kubernetes.io/wp-01he8bebctabr3kgk0qj36d2me-0": "localhost/k8s-apparmor-example-deny-write",
"kubernetes.io/limit-ranger": "LimitRanger plugin set: cpu, memory request and limit for container" "kubernetes.io/limit-ranger": "LimitRanger plugin set: cpu, memory request and limit for container"
} }
}, },
@ -250,9 +249,13 @@ func TestFullPod(t *testing.T) {
"runAsGroup": 101, "runAsGroup": 101,
"runAsNonRoot": true, "runAsNonRoot": true,
"fsGroup": 101, "fsGroup": 101,
"appArmorProfile": {
"type": "Localhost",
"localhostProfile": "k8s-apparmor-example-deny-write"
},
"seccompProfile": { "seccompProfile": {
"type": "Localhost", "type": "Localhost",
"localhostProfile": "profiles/audit.json" "localhostProfile": "profiles/audit.json"
} }
}, },
"imagePullSecrets": [ "imagePullSecrets": [