mirror of
https://github.com/containers/podman.git
synced 2025-10-13 17:26:13 +08:00
Pass on securityOpts from podInfraContainer to container added to pod.
This is an incomplete fix, as it would be best for the libpod library to be in charge of coordinating the container's dependencies on the infra container. A TODO was left as such. UTS is a special case, because the docker library that namespace handling is based off of doesn't recognize a UTS based on another container as valid, despite the library being able to handle it correctly. Thus, it is left in the old way. Signed-off-by: haircommander <pehunt@redhat.com> Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Closes: #1347 Approved by: mheon
This commit is contained in:

committed by
Atomic Bot

parent
123de3087e
commit
d9580ec62b
@ -16,7 +16,7 @@ import (
|
||||
ann "github.com/containers/libpod/pkg/annotations"
|
||||
"github.com/containers/libpod/pkg/apparmor"
|
||||
"github.com/containers/libpod/pkg/inspect"
|
||||
"github.com/containers/libpod/pkg/namespaces"
|
||||
ns "github.com/containers/libpod/pkg/namespaces"
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
cc "github.com/containers/libpod/pkg/spec"
|
||||
"github.com/containers/libpod/pkg/util"
|
||||
@ -357,6 +357,33 @@ func configureEntrypoint(c *cli.Context, data *inspect.ImageData) []string {
|
||||
return entrypoint
|
||||
}
|
||||
|
||||
func configurePod(c *cli.Context, runtime *libpod.Runtime, namespaces map[string]string) (map[string]string, error) {
|
||||
pod, err := runtime.LookupPod(c.String("pod"))
|
||||
if err != nil {
|
||||
return namespaces, err
|
||||
}
|
||||
podInfraID, err := pod.InfraContainerID()
|
||||
if err != nil {
|
||||
return namespaces, err
|
||||
}
|
||||
if (namespaces["pid"] == cc.Pod) || (!c.IsSet("pid") && pod.SharesPID()) {
|
||||
namespaces["pid"] = fmt.Sprintf("container:%s", podInfraID)
|
||||
}
|
||||
if (namespaces["net"] == cc.Pod) || (!c.IsSet("net") && pod.SharesNet()) {
|
||||
namespaces["net"] = fmt.Sprintf("container:%s", podInfraID)
|
||||
}
|
||||
if (namespaces["user"] == cc.Pod) || (!c.IsSet("user") && pod.SharesUser()) {
|
||||
namespaces["user"] = fmt.Sprintf("container:%s", podInfraID)
|
||||
}
|
||||
if (namespaces["ipc"] == cc.Pod) || (!c.IsSet("ipc") && pod.SharesIPC()) {
|
||||
namespaces["ipc"] = fmt.Sprintf("container:%s", podInfraID)
|
||||
}
|
||||
if (namespaces["uts"] == cc.Pod) || (!c.IsSet("uts") && pod.SharesUTS()) {
|
||||
namespaces["uts"] = fmt.Sprintf("container:%s", podInfraID)
|
||||
}
|
||||
return namespaces, nil
|
||||
}
|
||||
|
||||
// Parses CLI options related to container creation into a config which can be
|
||||
// parsed into an OCI runtime spec
|
||||
func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*cc.CreateConfig, error) {
|
||||
@ -444,56 +471,48 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
|
||||
}
|
||||
|
||||
// Kernel Namespaces
|
||||
var pod *libpod.Pod
|
||||
// TODO Fix handling of namespace from pod
|
||||
// Instead of integrating here, should be done in libpod
|
||||
// However, that also involves setting up security opts
|
||||
// when the pod's namespace is integrated
|
||||
namespaces := map[string]string{
|
||||
"pid": c.String("pid"),
|
||||
"net": c.String("net"),
|
||||
"ipc": c.String("ipc"),
|
||||
"user": c.String("userns"),
|
||||
"uts": c.String("uts"),
|
||||
}
|
||||
|
||||
if c.IsSet("pod") {
|
||||
pod, err = runtime.LookupPod(c.String("pod"))
|
||||
namespaces, err = configurePod(c, runtime, namespaces)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
pidModeStr := c.String("pid")
|
||||
if !c.IsSet("pid") && pod != nil && pod.SharesPID() {
|
||||
pidModeStr = cc.POD
|
||||
}
|
||||
pidMode := namespaces.PidMode(pidModeStr)
|
||||
pidMode := ns.PidMode(namespaces["pid"])
|
||||
if !cc.Valid(string(pidMode), pidMode) {
|
||||
return nil, errors.Errorf("--pid %q is not valid", c.String("pid"))
|
||||
}
|
||||
|
||||
usernsModeStr := c.String("userns")
|
||||
if !c.IsSet("userns") && pod != nil && pod.SharesUser() {
|
||||
usernsModeStr = cc.POD
|
||||
}
|
||||
usernsMode := namespaces.UsernsMode(usernsModeStr)
|
||||
usernsMode := ns.UsernsMode(namespaces["user"])
|
||||
if !cc.Valid(string(usernsMode), usernsMode) {
|
||||
return nil, errors.Errorf("--userns %q is not valid", c.String("userns"))
|
||||
return nil, errors.Errorf("--userns %q is not valid", namespaces["user"])
|
||||
}
|
||||
|
||||
utsModeStr := c.String("uts")
|
||||
if !c.IsSet("uts") && pod != nil && pod.SharesUTS() {
|
||||
utsModeStr = cc.POD
|
||||
}
|
||||
utsMode := namespaces.UTSMode(utsModeStr)
|
||||
utsMode := ns.UTSMode(namespaces["uts"])
|
||||
if !cc.Valid(string(utsMode), utsMode) {
|
||||
return nil, errors.Errorf("--uts %q is not valid", c.String("uts"))
|
||||
return nil, errors.Errorf("--uts %q is not valid", namespaces["uts"])
|
||||
}
|
||||
|
||||
ipcModeStr := c.String("ipc")
|
||||
if !c.IsSet("ipc") && pod != nil && pod.SharesIPC() {
|
||||
ipcModeStr = cc.POD
|
||||
}
|
||||
ipcMode := namespaces.IpcMode(ipcModeStr)
|
||||
ipcMode := ns.IpcMode(namespaces["ipc"])
|
||||
if !cc.Valid(string(ipcMode), ipcMode) {
|
||||
return nil, errors.Errorf("--ipc %q is not valid", ipcMode)
|
||||
}
|
||||
netModeStr := c.String("network")
|
||||
if !c.IsSet("network") && pod != nil && pod.SharesNet() {
|
||||
netModeStr = cc.POD
|
||||
}
|
||||
|
||||
// Make sure if network is set to container namespace, port binding is not also being asked for
|
||||
netMode := namespaces.NetworkMode(netModeStr)
|
||||
if netMode.IsContainer() || cc.IsPod(netModeStr) {
|
||||
netMode := ns.NetworkMode(namespaces["net"])
|
||||
if netMode.IsContainer() {
|
||||
if len(c.StringSlice("publish")) > 0 || c.Bool("publish-all") {
|
||||
return nil, errors.Errorf("cannot set port bindings on an existing container network namespace")
|
||||
}
|
||||
|
@ -549,94 +549,6 @@ func WithExitCommand(exitCommand []string) CtrCreateOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithIPCNSFromPod indicates the the container should join the IPC namespace of
|
||||
// its pod
|
||||
func WithIPCNSFromPod(p *Pod) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return ErrCtrFinalized
|
||||
}
|
||||
|
||||
if err := validPodNSOption(p, ctr.config.Pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infraContainer, err := p.InfraContainerID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctr.config.IPCNsCtr = infraContainer
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithMountNSFromPod indicates the the container should join the Mount namespace of
|
||||
// its pod
|
||||
func WithMountNSFromPod(p *Pod) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return ErrCtrFinalized
|
||||
}
|
||||
|
||||
if err := validPodNSOption(p, ctr.config.Pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infraContainer, err := p.InfraContainerID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctr.config.MountNsCtr = infraContainer
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithNetNSFromPod indicates the the container should join the network namespace of
|
||||
// its pod
|
||||
func WithNetNSFromPod(p *Pod) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return ErrCtrFinalized
|
||||
}
|
||||
|
||||
if err := validPodNSOption(p, ctr.config.Pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infraContainer, err := p.InfraContainerID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctr.config.NetNsCtr = infraContainer
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPIDNSFromPod indicates the the container should join the PID namespace of
|
||||
// its pod
|
||||
func WithPIDNSFromPod(p *Pod) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return ErrCtrFinalized
|
||||
}
|
||||
|
||||
if err := validPodNSOption(p, ctr.config.Pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infraContainer, err := p.InfraContainerID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctr.config.PIDNsCtr = infraContainer
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithUTSNSFromPod indicates the the container should join the UTS namespace of
|
||||
// its pod
|
||||
func WithUTSNSFromPod(p *Pod) CtrCreateOption {
|
||||
@ -659,50 +571,6 @@ func WithUTSNSFromPod(p *Pod) CtrCreateOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithUserNSFromPod indicates the the container should join the User namespace of
|
||||
// its pod
|
||||
func WithUserNSFromPod(p *Pod) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return ErrCtrFinalized
|
||||
}
|
||||
|
||||
if err := validPodNSOption(p, ctr.config.Pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infraContainer, err := p.InfraContainerID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctr.config.UserNsCtr = infraContainer
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithCgroupNSFromPod indicates the the container should join the Cgroup namespace of
|
||||
// its pod
|
||||
func WithCgroupNSFromPod(p *Pod) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return ErrCtrFinalized
|
||||
}
|
||||
|
||||
if err := validPodNSOption(p, ctr.config.Pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
infraContainer, err := p.InfraContainerID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctr.config.CgroupNsCtr = infraContainer
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithIPCNSFrom indicates the the container should join the IPC namespace of
|
||||
// the given container.
|
||||
// If the container has joined a pod, it can only join the namespaces of
|
||||
|
@ -385,8 +385,6 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
|
||||
return nil, errors.Wrapf(err, "container %q not found", c.NetMode.ConnectedContainer())
|
||||
}
|
||||
options = append(options, libpod.WithNetNSFrom(connectedCtr))
|
||||
} else if IsPod(string(c.NetMode)) {
|
||||
options = append(options, libpod.WithNetNSFromPod(pod))
|
||||
} else if !c.NetMode.IsHost() && !c.NetMode.IsNone() {
|
||||
isRootless := rootless.IsRootless()
|
||||
postConfigureNetNS := isRootless || (len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0) && !c.UsernsMode.IsHost()
|
||||
@ -404,9 +402,6 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
|
||||
|
||||
options = append(options, libpod.WithPIDNSFrom(connectedCtr))
|
||||
}
|
||||
if IsPod(string(c.PidMode)) {
|
||||
options = append(options, libpod.WithPIDNSFromPod(pod))
|
||||
}
|
||||
|
||||
if c.IpcMode.IsContainer() {
|
||||
connectedCtr, err := c.Runtime.LookupContainer(c.IpcMode.Container())
|
||||
@ -416,9 +411,6 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
|
||||
|
||||
options = append(options, libpod.WithIPCNSFrom(connectedCtr))
|
||||
}
|
||||
if IsPod(string(c.IpcMode)) {
|
||||
options = append(options, libpod.WithIPCNSFromPod(pod))
|
||||
}
|
||||
|
||||
if IsPod(string(c.UtsMode)) {
|
||||
options = append(options, libpod.WithUTSNSFromPod(pod))
|
||||
|
@ -8,9 +8,9 @@ import (
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
// POD signifies a kernel namespace is being shared
|
||||
// Pod signifies a kernel namespace is being shared
|
||||
// by a container with the pod it is associated with
|
||||
const POD = "pod"
|
||||
const Pod = "pod"
|
||||
|
||||
// weightDevice is a structure that holds device:weight pair
|
||||
type weightDevice struct {
|
||||
@ -36,7 +36,7 @@ func IsNS(s string) bool {
|
||||
|
||||
// IsPod returns if the specified string is pod
|
||||
func IsPod(s string) bool {
|
||||
return s == POD
|
||||
return s == Pod
|
||||
}
|
||||
|
||||
// Valid checks the validity of a linux namespace
|
||||
|
@ -113,6 +113,30 @@ var _ = Describe("Podman pod create", func() {
|
||||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||
})
|
||||
|
||||
It("podman pod correctly sets up IPCNS", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create", "--share", "ipc"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
podID := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "start", podID})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
podmanTest.RestoreArtifact(fedoraMinimal)
|
||||
session = podmanTest.Podman([]string{"run", "--pod", podID, fedoraMinimal, "/bin/sh", "-c", "'touch /dev/shm/hi'"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
if session.ExitCode() != 0 {
|
||||
Skip("ShmDir not initialized, skipping...")
|
||||
}
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--pod", podID, fedoraMinimal, "/bin/sh", "-c", "'ls /dev/shm'"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
Expect(session.OutputToString()).To(Equal("hi"))
|
||||
})
|
||||
|
||||
It("podman pod correctly sets up PIDNS", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create", "--share", "pid", "--name", "test-pod"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
|
89
test/e2e/pod_pod_namespaces.go
Normal file
89
test/e2e/pod_pod_namespaces.go
Normal file
@ -0,0 +1,89 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Podman pod create", func() {
|
||||
var (
|
||||
tempdir string
|
||||
err error
|
||||
podmanTest PodmanTest
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
podmanTest = PodmanCreate(tempdir)
|
||||
podmanTest.RestoreAllArtifacts()
|
||||
podmanTest.RestoreArtifact(infra)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
podmanTest.CleanupPod()
|
||||
f := CurrentGinkgoTestDescription()
|
||||
timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())
|
||||
GinkgoWriter.Write([]byte(timedResult))
|
||||
})
|
||||
|
||||
It("podman pod container share Namespaces", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
podID := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "start", podID})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--pod", podID, "-d", ALPINE, "top"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
check := podmanTest.Podman([]string{"ps", "-a", "--ns", "--format", "{{.IPC}} {{.UTS}} {{.NET}}"})
|
||||
check.WaitWithDefaultTimeout()
|
||||
Expect(check.ExitCode()).To(Equal(0))
|
||||
outputArray := check.OutputToStringArray()
|
||||
Expect(len(outputArray)).To(Equal(2))
|
||||
|
||||
NAMESPACE1 := outputArray[0]
|
||||
fmt.Println("NAMESPACE1:", NAMESPACE1)
|
||||
NAMESPACE2 := outputArray[1]
|
||||
fmt.Println("NAMESPACE2:", NAMESPACE2)
|
||||
Expect(NAMESPACE1).To(Equal(NAMESPACE2))
|
||||
})
|
||||
|
||||
It("podman pod container dontshare PIDNS", func() {
|
||||
session := podmanTest.Podman([]string{"pod", "create"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
podID := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"pod", "start", podID})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--pod", podID, "-d", ALPINE, "top"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
|
||||
check := podmanTest.Podman([]string{"ps", "-a", "--ns", "--format", "{{.PIDNS}}"})
|
||||
check.WaitWithDefaultTimeout()
|
||||
Expect(check.ExitCode()).To(Equal(0))
|
||||
outputArray := check.OutputToStringArray()
|
||||
Expect(len(outputArray)).To(Equal(2))
|
||||
|
||||
NAMESPACE1 := outputArray[0]
|
||||
fmt.Println("NAMESPACE1:", NAMESPACE1)
|
||||
NAMESPACE2 := outputArray[1]
|
||||
fmt.Println("NAMESPACE2:", NAMESPACE2)
|
||||
Expect(NAMESPACE1).To(Not(Equal(NAMESPACE2)))
|
||||
})
|
||||
|
||||
})
|
@ -235,10 +235,10 @@ var _ = Describe("Podman run", func() {
|
||||
})
|
||||
|
||||
It("podman run with cidfile", func() {
|
||||
session := podmanTest.Podman([]string{"run", "--cidfile", "/tmp/cidfile", ALPINE, "ls"})
|
||||
session := podmanTest.Podman([]string{"run", "--cidfile", tempdir + "cidfile", ALPINE, "ls"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
err := os.Remove("/tmp/cidfile")
|
||||
err := os.Remove(tempdir + "cidfile")
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
@ -317,7 +317,7 @@ var _ = Describe("Podman run", func() {
|
||||
|
||||
It("podman test hooks", func() {
|
||||
hcheck := "/run/hookscheck"
|
||||
hooksDir := "/tmp/hooks"
|
||||
hooksDir := tempdir + "/hooks"
|
||||
os.Mkdir(hooksDir, 0755)
|
||||
fileutils.CopyFile("hooks/hooks.json", hooksDir)
|
||||
os.Setenv("HOOK_OPTION", fmt.Sprintf("--hooks-dir-path=%s", hooksDir))
|
||||
@ -347,7 +347,7 @@ var _ = Describe("Podman run", func() {
|
||||
err = ioutil.WriteFile(secretsFile, []byte(secretsString), 0755)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
targetDir := "/tmp/symlink/target"
|
||||
targetDir := tempdir + "/symlink/target"
|
||||
err = os.MkdirAll(targetDir, 0755)
|
||||
Expect(err).To(BeNil())
|
||||
keyFile := filepath.Join(targetDir, "key.pem")
|
||||
|
Reference in New Issue
Block a user