diff --git a/libpod/kube.go b/libpod/kube.go index 0552973ff0..240ab4e322 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -230,7 +230,7 @@ func ConvertV1PodToYAMLPod(pod *v1.Pod) *YAMLPod { continue } selinuxOpts := ctr.SecurityContext.SELinuxOptions - if selinuxOpts.User == "" && selinuxOpts.Role == "" && selinuxOpts.Type == "" && selinuxOpts.Level == "" { + if selinuxOpts.User == "" && selinuxOpts.Role == "" && selinuxOpts.Type == "" && selinuxOpts.Level == "" && selinuxOpts.FileType == "" { ctr.SecurityContext.SELinuxOptions = nil } } @@ -1043,27 +1043,33 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, bool, error sc.Capabilities = capabilities } var selinuxOpts v1.SELinuxOptions - opts := strings.SplitN(c.config.Spec.Annotations[define.InspectAnnotationLabel], ":", 2) - switch len(opts) { - case 2: - switch opts[0] { - case "type": - selinuxOpts.Type = opts[1] - sc.SELinuxOptions = &selinuxOpts - scHasData = true - case "level": - selinuxOpts.Level = opts[1] - sc.SELinuxOptions = &selinuxOpts - scHasData = true - } - case 1: - if opts[0] == "disable" { - selinuxOpts.Type = "spc_t" - sc.SELinuxOptions = &selinuxOpts - scHasData = true + selinuxHasData := false + for _, label := range strings.Split(c.config.Spec.Annotations[define.InspectAnnotationLabel], ",label=") { + opts := strings.SplitN(label, ":", 2) + switch len(opts) { + case 2: + switch opts[0] { + case "filetype": + selinuxOpts.FileType = opts[1] + selinuxHasData = true + case "type": + selinuxOpts.Type = opts[1] + selinuxHasData = true + case "level": + selinuxOpts.Level = opts[1] + selinuxHasData = true + } + case 1: + if opts[0] == "disable" { + selinuxOpts.Type = "spc_t" + selinuxHasData = true + } } } - + if selinuxHasData { + sc.SELinuxOptions = &selinuxOpts + scHasData = true + } if !allowPrivEscalation { scHasData = true sc.AllowPrivilegeEscalation = &allowPrivEscalation diff --git a/pkg/k8s.io/api/core/v1/types.go b/pkg/k8s.io/api/core/v1/types.go index 2020cbe4b9..7d72693af4 100644 --- a/pkg/k8s.io/api/core/v1/types.go +++ b/pkg/k8s.io/api/core/v1/types.go @@ -4403,6 +4403,9 @@ type SELinuxOptions struct { // Type is a SELinux type label that applies to the container. // +optional Type string `json:"type,omitempty"` + // FileType is a SELinux file type label that applies to the container. + // +optional + FileType string `json:"filetype,omitempty"` // Level is SELinux level label that applies to the container. // +optional Level string `json:"level,omitempty"` diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index 1e6314fb76..4a3d6648e8 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -719,6 +719,9 @@ func setupSecurityContext(s *specgen.SpecGenerator, securityContext *v1.Security if seopt.Level != "" { s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("level:%s", seopt.Level)) } + if seopt.FileType != "" { + s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("filetype:%s", seopt.FileType)) + } } if caps := securityContext.Capabilities; caps != nil { for _, capability := range caps.Add { diff --git a/test/system/700-play.bats b/test/system/700-play.bats index 248bdec27a..12b9b356a1 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -72,7 +72,7 @@ RELABEL="system_u:object_r:container_file_t:s0" echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml run_podman kube play - < $PODMAN_TMPDIR/test.yaml - if [ -e /usr/sbin/selinuxenabled -a /usr/sbin/selinuxenabled ]; then + if selinux_enabled; then run ls -Zd $TESTDIR is "$output" "${RELABEL} $TESTDIR" "selinux relabel should have happened" fi @@ -94,7 +94,7 @@ RELABEL="system_u:object_r:container_file_t:s0" mkdir -p $TESTDIR echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml run_podman play kube $PODMAN_TMPDIR/test.yaml - if [ -e /usr/sbin/selinuxenabled -a /usr/sbin/selinuxenabled ]; then + if selinux_enabled; then run ls -Zd $TESTDIR is "$output" "${RELABEL} $TESTDIR" "selinux relabel should have happened" fi @@ -549,3 +549,19 @@ EOF run_podman kube down $yaml_source } + +@test "podman kube generate filetype" { + YAML=$PODMAN_TMPDIR/test.yml + run_podman create --pod new:pod1 --security-opt label=level:s0:c1,c2 --security-opt label=filetype:usr_t --name test1 $IMAGE true + run_podman kube generate pod1 -f $YAML + run cat $YAML + is "$output" ".*filetype: usr_t" "Generated YAML file should contain filetype usr_t" + run_podman pod rm --force pod1 + + run_podman kube play $YAML + if selinux_enabled; then + run_podman inspect pod1-test1 --format "{{ .MountLabel }}" + is "$output" "system_u:object_r:usr_t:s0:c1,c2" "Generated container should use filetype usr_t" + fi + run_podman kube down $YAML +} diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 7c9af79cb4..f1b415eec2 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -347,6 +347,10 @@ function is_aarch64() { [ "$(uname -m)" == "aarch64" ] } +function selinux_enabled() { + /usr/sbin/selinuxenabled 2> /dev/null +} + # Returns the OCI runtime *basename* (typically crun or runc). Much as we'd # love to cache this result, we probably shouldn't. function podman_runtime() {