mirror of
https://github.com/containers/podman.git
synced 2025-06-28 14:29:04 +08:00
Merge pull request #15692 from giuseppe/pod-spec-userns
kube: plug HostUsers in the pod spec
This commit is contained in:
@ -62,6 +62,7 @@ func (p *Pod) GenerateForKube(ctx context.Context) (*v1.Pod, []v1.ServicePort, e
|
|||||||
|
|
||||||
extraHost := make([]v1.HostAlias, 0)
|
extraHost := make([]v1.HostAlias, 0)
|
||||||
hostNetwork := false
|
hostNetwork := false
|
||||||
|
hostUsers := true
|
||||||
if p.HasInfraContainer() {
|
if p.HasInfraContainer() {
|
||||||
infraContainer, err := p.getInfraContainer()
|
infraContainer, err := p.getInfraContainer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -87,8 +88,9 @@ func (p *Pod) GenerateForKube(ctx context.Context) (*v1.Pod, []v1.ServicePort, e
|
|||||||
return nil, servicePorts, err
|
return nil, servicePorts, err
|
||||||
}
|
}
|
||||||
hostNetwork = infraContainer.NetworkMode() == string(namespaces.NetworkMode(specgen.Host))
|
hostNetwork = infraContainer.NetworkMode() == string(namespaces.NetworkMode(specgen.Host))
|
||||||
|
hostUsers = infraContainer.IDMappings().HostUIDMapping && infraContainer.IDMappings().HostGIDMapping
|
||||||
}
|
}
|
||||||
pod, err := p.podWithContainers(ctx, allContainers, ports, hostNetwork)
|
pod, err := p.podWithContainers(ctx, allContainers, ports, hostNetwork, hostUsers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, servicePorts, err
|
return nil, servicePorts, err
|
||||||
}
|
}
|
||||||
@ -348,7 +350,7 @@ func containersToServicePorts(containers []v1.Container) ([]v1.ServicePort, erro
|
|||||||
return sps, nil
|
return sps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, ports []v1.ContainerPort, hostNetwork bool) (*v1.Pod, error) {
|
func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, ports []v1.ContainerPort, hostNetwork, hostUsers bool) (*v1.Pod, error) {
|
||||||
deDupPodVolumes := make(map[string]*v1.Volume)
|
deDupPodVolumes := make(map[string]*v1.Volume)
|
||||||
first := true
|
first := true
|
||||||
podContainers := make([]v1.Container, 0, len(containers))
|
podContainers := make([]v1.Container, 0, len(containers))
|
||||||
@ -446,10 +448,11 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po
|
|||||||
podVolumes,
|
podVolumes,
|
||||||
&dnsInfo,
|
&dnsInfo,
|
||||||
hostNetwork,
|
hostNetwork,
|
||||||
|
hostUsers,
|
||||||
hostname), nil
|
hostname), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPodObject(podName string, annotations map[string]string, initCtrs, containers []v1.Container, volumes []v1.Volume, dnsOptions *v1.PodDNSConfig, hostNetwork bool, hostname string) *v1.Pod {
|
func newPodObject(podName string, annotations map[string]string, initCtrs, containers []v1.Container, volumes []v1.Volume, dnsOptions *v1.PodDNSConfig, hostNetwork, hostUsers bool, hostname string) *v1.Pod {
|
||||||
tm := v12.TypeMeta{
|
tm := v12.TypeMeta{
|
||||||
Kind: "Pod",
|
Kind: "Pod",
|
||||||
APIVersion: "v1",
|
APIVersion: "v1",
|
||||||
@ -481,6 +484,9 @@ func newPodObject(podName string, annotations map[string]string, initCtrs, conta
|
|||||||
EnableServiceLinks: &enableServiceLinks,
|
EnableServiceLinks: &enableServiceLinks,
|
||||||
AutomountServiceAccountToken: &automountServiceAccountToken,
|
AutomountServiceAccountToken: &automountServiceAccountToken,
|
||||||
}
|
}
|
||||||
|
if !hostUsers {
|
||||||
|
ps.HostUsers = &hostUsers
|
||||||
|
}
|
||||||
if dnsOptions != nil && (len(dnsOptions.Nameservers)+len(dnsOptions.Searches)+len(dnsOptions.Options) > 0) {
|
if dnsOptions != nil && (len(dnsOptions.Nameservers)+len(dnsOptions.Searches)+len(dnsOptions.Options) > 0) {
|
||||||
ps.DNSConfig = dnsOptions
|
ps.DNSConfig = dnsOptions
|
||||||
}
|
}
|
||||||
@ -498,6 +504,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
|
|||||||
kubeCtrs := make([]v1.Container, 0, len(ctrs))
|
kubeCtrs := make([]v1.Container, 0, len(ctrs))
|
||||||
kubeInitCtrs := []v1.Container{}
|
kubeInitCtrs := []v1.Container{}
|
||||||
kubeVolumes := make([]v1.Volume, 0)
|
kubeVolumes := make([]v1.Volume, 0)
|
||||||
|
hostUsers := true
|
||||||
hostNetwork := true
|
hostNetwork := true
|
||||||
podDNS := v1.PodDNSConfig{}
|
podDNS := v1.PodDNSConfig{}
|
||||||
kubeAnnotations := make(map[string]string)
|
kubeAnnotations := make(map[string]string)
|
||||||
@ -527,6 +534,9 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
|
|||||||
if !ctr.HostNetwork() {
|
if !ctr.HostNetwork() {
|
||||||
hostNetwork = false
|
hostNetwork = false
|
||||||
}
|
}
|
||||||
|
if !(ctr.IDMappings().HostUIDMapping && ctr.IDMappings().HostGIDMapping) {
|
||||||
|
hostUsers = false
|
||||||
|
}
|
||||||
kubeCtr, kubeVols, ctrDNS, annotations, err := containerToV1Container(ctx, ctr)
|
kubeCtr, kubeVols, ctrDNS, annotations, err := containerToV1Container(ctx, ctr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -588,6 +598,7 @@ func simplePodWithV1Containers(ctx context.Context, ctrs []*Container) (*v1.Pod,
|
|||||||
kubeVolumes,
|
kubeVolumes,
|
||||||
&podDNS,
|
&podDNS,
|
||||||
hostNetwork,
|
hostNetwork,
|
||||||
|
hostUsers,
|
||||||
hostname), nil
|
hostname), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,6 +355,11 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
|||||||
|
|
||||||
if options.Userns == "" {
|
if options.Userns == "" {
|
||||||
options.Userns = "host"
|
options.Userns = "host"
|
||||||
|
if podYAML.Spec.HostUsers != nil && !*podYAML.Spec.HostUsers {
|
||||||
|
options.Userns = "auto"
|
||||||
|
}
|
||||||
|
} else if podYAML.Spec.HostUsers != nil {
|
||||||
|
logrus.Info("overriding the user namespace mode in the pod spec")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the userns modes supported.
|
// Validate the userns modes supported.
|
||||||
|
@ -1984,6 +1984,18 @@ type PodSpec struct {
|
|||||||
// Default to false.
|
// Default to false.
|
||||||
// +optional
|
// +optional
|
||||||
SetHostnameAsFQDN *bool `json:"setHostnameAsFQDN,omitempty"`
|
SetHostnameAsFQDN *bool `json:"setHostnameAsFQDN,omitempty"`
|
||||||
|
// Use the host's user namespace.
|
||||||
|
// Optional: Default to true.
|
||||||
|
// If set to true or not present, the pod will be run in the host user namespace, useful
|
||||||
|
// for when the pod needs a feature only available to the host user namespace, such as
|
||||||
|
// loading a kernel module with CAP_SYS_MODULE.
|
||||||
|
// When set to false, a new userns is created for the pod. Setting false is useful for
|
||||||
|
// mitigating container breakout vulnerabilities even allowing users to run their
|
||||||
|
// containers as root without actually having root privileges on the host.
|
||||||
|
// This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature.
|
||||||
|
// +k8s:conversion-gen=false
|
||||||
|
// +optional
|
||||||
|
HostUsers *bool `json:"hostUsers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnsatisfiableConstraintAction string
|
type UnsatisfiableConstraintAction string
|
||||||
|
@ -3,6 +3,7 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -270,6 +271,39 @@ var _ = Describe("Podman generate kube", func() {
|
|||||||
Expect(numContainers).To(Equal(1))
|
Expect(numContainers).To(Equal(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman generate kube on pod with user namespace", func() {
|
||||||
|
u, err := user.Current()
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
name := u.Name
|
||||||
|
if name == "root" {
|
||||||
|
name = "containers"
|
||||||
|
}
|
||||||
|
content, err := ioutil.ReadFile("/etc/subuid")
|
||||||
|
if err != nil {
|
||||||
|
Skip("cannot read /etc/subuid")
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(content), name) {
|
||||||
|
Skip("cannot find mappings for the current user")
|
||||||
|
}
|
||||||
|
podSession := podmanTest.Podman([]string{"pod", "create", "--name", "testPod", "--userns=auto"})
|
||||||
|
podSession.WaitWithDefaultTimeout()
|
||||||
|
Expect(podSession).Should(Exit(0))
|
||||||
|
|
||||||
|
session := podmanTest.Podman([]string{"create", "--name", "topcontainer", "--pod", "testPod", ALPINE, "top"})
|
||||||
|
session.WaitWithDefaultTimeout()
|
||||||
|
Expect(session).Should(Exit(0))
|
||||||
|
|
||||||
|
kube := podmanTest.Podman([]string{"generate", "kube", "testPod"})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube).Should(Exit(0))
|
||||||
|
|
||||||
|
pod := new(v1.Pod)
|
||||||
|
err = yaml.Unmarshal(kube.Out.Contents(), pod)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
expected := false
|
||||||
|
Expect(pod.Spec).To(HaveField("HostUsers", &expected))
|
||||||
|
})
|
||||||
|
|
||||||
It("podman generate kube on pod with host network", func() {
|
It("podman generate kube on pod with host network", func() {
|
||||||
podSession := podmanTest.Podman([]string{"pod", "create", "--name", "testHostNetwork", "--network", "host"})
|
podSession := podmanTest.Podman([]string{"pod", "create", "--name", "testHostNetwork", "--network", "host"})
|
||||||
podSession.WaitWithDefaultTimeout()
|
podSession.WaitWithDefaultTimeout()
|
||||||
|
@ -380,6 +380,9 @@ spec:
|
|||||||
restartPolicy: {{ .RestartPolicy }}
|
restartPolicy: {{ .RestartPolicy }}
|
||||||
hostname: {{ .Hostname }}
|
hostname: {{ .Hostname }}
|
||||||
hostNetwork: {{ .HostNetwork }}
|
hostNetwork: {{ .HostNetwork }}
|
||||||
|
{{ if .HostUsers }}
|
||||||
|
hostUsers: {{ .HostUsers }}
|
||||||
|
{{ end }}
|
||||||
hostAliases:
|
hostAliases:
|
||||||
{{ range .HostAliases }}
|
{{ range .HostAliases }}
|
||||||
- hostnames:
|
- hostnames:
|
||||||
@ -844,6 +847,7 @@ type Pod struct {
|
|||||||
RestartPolicy string
|
RestartPolicy string
|
||||||
Hostname string
|
Hostname string
|
||||||
HostNetwork bool
|
HostNetwork bool
|
||||||
|
HostUsers *bool
|
||||||
HostAliases []HostAlias
|
HostAliases []HostAlias
|
||||||
Ctrs []*Ctr
|
Ctrs []*Ctr
|
||||||
InitCtrs []*Ctr
|
InitCtrs []*Ctr
|
||||||
@ -968,6 +972,12 @@ func withHostNetwork() podOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func withHostUsers(val bool) podOption {
|
||||||
|
return func(pod *Pod) {
|
||||||
|
pod.HostUsers = &val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Deployment describes the options a kube yaml can be configured at deployment level
|
// Deployment describes the options a kube yaml can be configured at deployment level
|
||||||
type Deployment struct {
|
type Deployment struct {
|
||||||
Name string
|
Name string
|
||||||
@ -3783,8 +3793,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
|
|||||||
Expect((inspect.InspectContainerToJSON()[0]).HostConfig.LogConfig.Tag).To(Equal("{{.ImageName}}"))
|
Expect((inspect.InspectContainerToJSON()[0]).HostConfig.LogConfig.Tag).To(Equal("{{.ImageName}}"))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Check that --userns=auto creates a user namespace
|
It("podman play kube using a user namespace", func() {
|
||||||
It("podman play kube --userns=auto", func() {
|
|
||||||
u, err := user.Current()
|
u, err := user.Current()
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
name := u.Name
|
name := u.Name
|
||||||
@ -3831,6 +3840,26 @@ ENV OPENJ9_JAVA_OPTIONS=%q
|
|||||||
usernsInCtr.WaitWithDefaultTimeout()
|
usernsInCtr.WaitWithDefaultTimeout()
|
||||||
Expect(usernsInCtr).Should(Exit(0))
|
Expect(usernsInCtr).Should(Exit(0))
|
||||||
Expect(string(usernsInCtr.Out.Contents())).To(Not(Equal(string(initialUsernsConfig))))
|
Expect(string(usernsInCtr.Out.Contents())).To(Not(Equal(string(initialUsernsConfig))))
|
||||||
|
|
||||||
|
// Now try with hostUsers in the pod spec
|
||||||
|
for _, hostUsers := range []bool{true, false} {
|
||||||
|
pod = getPod(withHostUsers(hostUsers))
|
||||||
|
err = generateKubeYaml("pod", pod, kubeYaml)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
|
kube = podmanTest.PodmanNoCache([]string{"play", "kube", "--replace", kubeYaml})
|
||||||
|
kube.WaitWithDefaultTimeout()
|
||||||
|
Expect(kube).Should(Exit(0))
|
||||||
|
|
||||||
|
usernsInCtr = podmanTest.Podman([]string{"exec", getCtrNameInPod(pod), "cat", "/proc/self/uid_map"})
|
||||||
|
usernsInCtr.WaitWithDefaultTimeout()
|
||||||
|
Expect(usernsInCtr).Should(Exit(0))
|
||||||
|
if hostUsers {
|
||||||
|
Expect(string(usernsInCtr.Out.Contents())).To(Equal(string(initialUsernsConfig)))
|
||||||
|
} else {
|
||||||
|
Expect(string(usernsInCtr.Out.Contents())).To(Not(Equal(string(initialUsernsConfig))))
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Check the block devices are exposed inside container
|
// Check the block devices are exposed inside container
|
||||||
|
Reference in New Issue
Block a user