Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support selinux options with bind mounts play/gen #11812

Merged
merged 1 commit into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions libpod/define/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,6 @@ const (

// DefaultRlimitValue is the value set by default for nofile and nproc
const RLimitDefaultValue = uint64(1048576)

// BindMountPrefix distinguishes its annotations from others
const BindMountPrefix = "bind-mount-options:"
53 changes: 33 additions & 20 deletions libpod/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,13 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po

isInit := ctr.IsInitCtr()

ctr, volumes, _, err := containerToV1Container(ctx, ctr)
ctr, volumes, _, annotations, err := containerToV1Container(ctx, ctr)
if err != nil {
return nil, err
}

for k, v := range annotations {
podAnnotations[define.BindMountPrefix+k] = v
}
// Since port bindings for the pod are handled by the
// infra container, wipe them here.
ctr.Ports = nil
Expand All @@ -271,7 +273,7 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
deDupPodVolumes[vol.Name] = &vol
}
} else {
_, _, infraDNS, err := containerToV1Container(ctx, ctr)
_, _, infraDNS, _, err := containerToV1Container(ctx, ctr)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -359,17 +361,19 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
if !ctr.HostNetwork() {
hostNetwork = false
}
kubeCtr, kubeVols, ctrDNS, err := containerToV1Container(ctx, ctr)
kubeCtr, kubeVols, ctrDNS, annotations, err := containerToV1Container(ctx, ctr)
if err != nil {
return nil, err
}
for k, v := range annotations {
kubeAnnotations[define.BindMountPrefix+k] = v
}
if isInit {
kubeInitCtrs = append(kubeInitCtrs, kubeCtr)
} else {
kubeCtrs = append(kubeCtrs, kubeCtr)
}
kubeVolumes = append(kubeVolumes, kubeVols...)

// Combine DNS information in sum'd structure
if ctrDNS != nil {
// nameservers
Expand Down Expand Up @@ -415,42 +419,44 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,

// containerToV1Container converts information we know about a libpod container
// to a V1.Container specification.
func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, error) {
func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, map[string]string, error) {
kubeContainer := v1.Container{}
kubeVolumes := []v1.Volume{}
annotations := make(map[string]string)
kubeSec, err := generateKubeSecurityContext(c)
if err != nil {
return kubeContainer, kubeVolumes, nil, err
return kubeContainer, kubeVolumes, nil, annotations, err
}

// NOTE: a privileged container mounts all of /dev/*.
if !c.Privileged() && len(c.config.Spec.Linux.Devices) > 0 {
// TODO Enable when we can support devices and their names
kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.Spec().Linux.Devices)
return kubeContainer, kubeVolumes, nil, errors.Wrapf(define.ErrNotImplemented, "linux devices")
kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.config.Spec.Linux.Devices)
return kubeContainer, kubeVolumes, nil, annotations, errors.Wrapf(define.ErrNotImplemented, "linux devices")
}

if len(c.config.UserVolumes) > 0 {
volumeMounts, volumes, err := libpodMountsToKubeVolumeMounts(c)
volumeMounts, volumes, localAnnotations, err := libpodMountsToKubeVolumeMounts(c)
if err != nil {
return kubeContainer, kubeVolumes, nil, err
return kubeContainer, kubeVolumes, nil, nil, err
}
annotations = localAnnotations
kubeContainer.VolumeMounts = volumeMounts
kubeVolumes = append(kubeVolumes, volumes...)
}

envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env)
if err != nil {
return kubeContainer, kubeVolumes, nil, err
return kubeContainer, kubeVolumes, nil, annotations, err
}

portmappings, err := c.PortMappings()
if err != nil {
return kubeContainer, kubeVolumes, nil, err
return kubeContainer, kubeVolumes, nil, annotations, err
}
ports, err := ocicniPortMappingToContainerPort(portmappings)
if err != nil {
return kubeContainer, kubeVolumes, nil, err
return kubeContainer, kubeVolumes, nil, annotations, err
}

// Handle command and arguments.
Expand All @@ -469,11 +475,11 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
kubeContainer.Stdin = c.Stdin()
img, _, err := c.runtime.libimageRuntime.LookupImage(image, nil)
if err != nil {
return kubeContainer, kubeVolumes, nil, err
return kubeContainer, kubeVolumes, nil, annotations, err
}
imgData, err := img.Inspect(ctx, false)
if err != nil {
return kubeContainer, kubeVolumes, nil, err
return kubeContainer, kubeVolumes, nil, annotations, err
}
if reflect.DeepEqual(imgData.Config.Cmd, kubeContainer.Command) {
kubeContainer.Command = nil
Expand Down Expand Up @@ -555,7 +561,7 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, []
}
dns.Options = dnsOptions
}
return kubeContainer, kubeVolumes, &dns, nil
return kubeContainer, kubeVolumes, &dns, annotations, nil
}

// ocicniPortMappingToContainerPort takes an ocicni portmapping and converts
Expand Down Expand Up @@ -606,16 +612,23 @@ func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) {
}

// libpodMountsToKubeVolumeMounts converts the containers mounts to a struct kube understands
func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, error) {
func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, map[string]string, error) {
namedVolumes, mounts := c.sortUserVolumes(c.config.Spec)
vms := make([]v1.VolumeMount, 0, len(mounts))
vos := make([]v1.Volume, 0, len(mounts))
annotations := make(map[string]string)

var suffix string
for index, m := range mounts {
for _, opt := range m.Options {
if opt == "Z" || opt == "z" {
annotations[m.Source] = opt
break
}
}
vm, vo, err := generateKubeVolumeMount(m)
if err != nil {
return vms, vos, err
return vms, vos, annotations, err
}
// Name will be the same, so use the index as suffix
suffix = fmt.Sprintf("-%d", index)
Expand All @@ -629,7 +642,7 @@ func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume
vms = append(vms, vm)
vos = append(vos, vo)
}
return vms, vos, nil
return vms, vos, annotations, nil
}

// generateKubePersistentVolumeClaim converts a ContainerNamedVolume to a Kubernetes PersistentVolumeClaim
Expand Down
2 changes: 1 addition & 1 deletion pkg/domain/infra/abi/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,8 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
if err != nil {
return nil, err
}

specgenOpts := kube.CtrSpecGenOptions{
Annotations: annotations,
Container: initCtr,
Image: pulledImage,
Volumes: volumes,
Expand Down
11 changes: 11 additions & 0 deletions pkg/specgen/generate/kube/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/containers/common/pkg/parse"
"github.com/containers/common/pkg/secrets"
"github.com/containers/image/v5/manifest"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/network/types"
ann "github.com/containers/podman/v3/pkg/annotations"
"github.com/containers/podman/v3/pkg/domain/entities"
Expand Down Expand Up @@ -86,6 +87,8 @@ func ToPodOpt(ctx context.Context, podName string, p entities.PodCreateOptions,
}

type CtrSpecGenOptions struct {
// Annotations from the Pod
Annotations map[string]string
// Container as read from the pod yaml
Container v1.Container
// Image available to use (pulled or found local)
Expand Down Expand Up @@ -289,6 +292,14 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
volume.MountPath = dest
switch volumeSource.Type {
case KubeVolumeTypeBindMount:
// If the container has bind mounts, we need to check if
// a selinux mount option exists for it
for k, v := range opts.Annotations {
// Make sure the z/Z option is not already there (from editing the YAML)
if strings.Replace(k, define.BindMountPrefix, "", 1) == volumeSource.Source && !util.StringInSlice("z", options) && !util.StringInSlice("Z", options) {
options = append(options, v)
}
}
mount := spec.Mount{
Destination: volume.MountPath,
Source: volumeSource.Source,
Expand Down
11 changes: 11 additions & 0 deletions test/e2e/generate_kube_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"path/filepath"
"strconv"

"github.com/containers/podman/v3/libpod/define"

"github.com/containers/podman/v3/pkg/util"
. "github.com/containers/podman/v3/test/utils"
"github.com/ghodss/yaml"
Expand Down Expand Up @@ -555,6 +557,15 @@ var _ = Describe("Podman generate kube", func() {
kube.WaitWithDefaultTimeout()
Expect(kube).Should(Exit(0))

b, err := ioutil.ReadFile(outputFile)
Expect(err).ShouldNot(HaveOccurred())
pod := new(v1.Pod)
err = yaml.Unmarshal(b, pod)
Expect(err).To(BeNil())
val, found := pod.Annotations[define.BindMountPrefix+vol1]
Expect(found).To(BeTrue())
Expect(val).To(HaveSuffix("z"))

rm := podmanTest.Podman([]string{"pod", "rm", "-f", "test1"})
rm.WaitWithDefaultTimeout()
Expect(rm).Should(Exit(0))
Expand Down