mirror of
https://github.com/containers/podman.git
synced 2025-06-24 19:42:56 +08:00
networking, userNS: configure the network namespace after create
so that the OCI runtime creates the network namespace from the correct userNS. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com> Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Closes: #690 Approved by: mheon
This commit is contained in:

committed by
Atomic Bot

parent
b51d737998
commit
73078fabcf
@ -167,6 +167,7 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
|
||||
cgroupPerm := "ro"
|
||||
g := generate.New()
|
||||
g.HostSpecific = true
|
||||
addCgroup := true
|
||||
if config.Privileged {
|
||||
cgroupPerm = "rw"
|
||||
g.RemoveMount("/sys")
|
||||
@ -177,7 +178,19 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
|
||||
Options: []string{"nosuid", "noexec", "nodev", "rw"},
|
||||
}
|
||||
g.AddMount(sysMnt)
|
||||
} else if !config.UsernsMode.IsHost() && config.NetMode.IsHost() {
|
||||
addCgroup = false
|
||||
g.RemoveMount("/sys")
|
||||
sysMnt := spec.Mount{
|
||||
Destination: "/sys",
|
||||
Type: "bind",
|
||||
Source: "/sys",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "ro", "rbind"},
|
||||
}
|
||||
g.AddMount(sysMnt)
|
||||
}
|
||||
|
||||
if addCgroup {
|
||||
cgroupMnt := spec.Mount{
|
||||
Destination: "/sys/fs/cgroup",
|
||||
Type: "cgroup",
|
||||
@ -185,6 +198,7 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
|
||||
Options: []string{"nosuid", "noexec", "nodev", "relatime", cgroupPerm},
|
||||
}
|
||||
g.AddMount(cgroupMnt)
|
||||
}
|
||||
g.SetProcessCwd(config.WorkDir)
|
||||
g.SetProcessArgs(config.Command)
|
||||
g.SetProcessTerminal(config.Tty)
|
||||
@ -697,8 +711,9 @@ func (c *createConfig) GetContainerCreateOptions() ([]libpod.CtrCreateOption, er
|
||||
}
|
||||
options = append(options, libpod.WithNetNSFrom(connectedCtr))
|
||||
} else if !c.NetMode.IsHost() && !c.NetMode.IsNone() {
|
||||
options = append(options, libpod.WithNetNS([]ocicni.PortMapping{}))
|
||||
options = append(options, libpod.WithNetNS(portBindings))
|
||||
postConfigureNetNS := (len(c.IDMappings.UIDMap) > 0 || len(c.IDMappings.GIDMap) > 0) && !c.UsernsMode.IsHost()
|
||||
options = append(options, libpod.WithNetNS([]ocicni.PortMapping{}, postConfigureNetNS))
|
||||
options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS))
|
||||
}
|
||||
|
||||
if c.PidMode.IsContainer() {
|
||||
|
@ -285,6 +285,8 @@ type ContainerConfig struct {
|
||||
// File containing the conmon PID
|
||||
ConmonPidFile string `json:"conmonPidFile,omitempty"`
|
||||
// TODO log options for log drivers
|
||||
|
||||
PostConfigureNetNS bool `json:"postConfigureNetNS"`
|
||||
}
|
||||
|
||||
// ContainerStatus returns a string representation for users
|
||||
|
@ -416,6 +416,16 @@ func (c *Container) checkDependenciesRunningLocked(depCtrs map[string]*Container
|
||||
return notRunning, nil
|
||||
}
|
||||
|
||||
func (c *Container) completeNetworkSetup() error {
|
||||
if !c.config.PostConfigureNetNS {
|
||||
return nil
|
||||
}
|
||||
if err := c.syncContainer(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.runtime.setupNetNS(c)
|
||||
}
|
||||
|
||||
// Initialize a container, creating it in the runtime
|
||||
func (c *Container) init(ctx context.Context) error {
|
||||
if err := c.makeBindMounts(); err != nil {
|
||||
@ -442,7 +452,11 @@ func (c *Container) init(ctx context.Context) error {
|
||||
|
||||
c.state.State = ContainerStateCreated
|
||||
|
||||
return c.save()
|
||||
if err := c.save(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.completeNetworkSetup()
|
||||
}
|
||||
|
||||
// Reinitialize a container
|
||||
@ -626,7 +640,7 @@ func (c *Container) prepare() (err error) {
|
||||
}
|
||||
|
||||
// Set up network namespace if not already set up
|
||||
if c.config.CreateNetNS && c.state.NetNS == nil {
|
||||
if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS {
|
||||
if err := c.runtime.createNetNS(c); err != nil {
|
||||
// Tear down storage before exiting to make sure we
|
||||
// don't leak mounts
|
||||
@ -913,8 +927,12 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
|
||||
|
||||
// If network namespace was requested, add it now
|
||||
if c.config.CreateNetNS {
|
||||
if c.config.PostConfigureNetNS {
|
||||
g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, "")
|
||||
} else {
|
||||
g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path())
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the default /dev/shm mount to ensure we overwrite it
|
||||
g.RemoveMount("/dev/shm")
|
||||
|
@ -1,7 +1,12 @@
|
||||
package libpod
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
cnitypes "github.com/containernetworking/cni/pkg/types/current"
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
@ -9,7 +14,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectatomic/libpod/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
"strings"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Get an OCICNI network config
|
||||
@ -24,20 +29,7 @@ func getPodNetwork(id, name, nsPath string, ports []ocicni.PortMapping) ocicni.P
|
||||
}
|
||||
|
||||
// Create and configure a new network namespace for a container
|
||||
func (r *Runtime) createNetNS(ctr *Container) (err error) {
|
||||
ctrNS, err := ns.NewNS()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID())
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err2 := ctrNS.Close(); err2 != nil {
|
||||
logrus.Errorf("Error closing partially created network namespace for container %s: %v", ctr.ID(), err2)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID())
|
||||
func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (err error) {
|
||||
podNetwork := getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.PortMappings)
|
||||
|
||||
result, err := r.netPlugin.SetUpPod(podNetwork)
|
||||
@ -74,6 +66,57 @@ func (r *Runtime) createNetNS(ctr *Container) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create and configure a new network namespace for a container
|
||||
func (r *Runtime) createNetNS(ctr *Container) (err error) {
|
||||
ctrNS, err := ns.NewNS()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID())
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err2 := ctrNS.Close(); err2 != nil {
|
||||
logrus.Errorf("Error closing partially created network namespace for container %s: %v", ctr.ID(), err2)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID())
|
||||
return r.configureNetNS(ctr, ctrNS)
|
||||
}
|
||||
|
||||
// Configure the network namespace using the container process
|
||||
func (r *Runtime) setupNetNS(ctr *Container) (err error) {
|
||||
nsProcess := fmt.Sprintf("/proc/%d/ns/net", ctr.state.PID)
|
||||
|
||||
b := make([]byte, 16)
|
||||
|
||||
if _, err := rand.Reader.Read(b); err != nil {
|
||||
return errors.Wrapf(err, "failed to generate random netns name")
|
||||
}
|
||||
|
||||
nsPath := fmt.Sprintf("/var/run/netns/cni-%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(nsPath), 0711); err != nil {
|
||||
return errors.Wrapf(err, "cannot create %s", filepath.Dir(nsPath))
|
||||
}
|
||||
|
||||
mountPointFd, err := os.Create(nsPath)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot open %s", nsPath)
|
||||
}
|
||||
mountPointFd.Close()
|
||||
|
||||
if err := unix.Mount(nsProcess, nsPath, "none", unix.MS_BIND, ""); err != nil {
|
||||
return errors.Wrapf(err, "cannot mount %s", nsPath)
|
||||
}
|
||||
|
||||
netNS, err := ns.GetNS(nsPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.configureNetNS(ctr, netNS)
|
||||
}
|
||||
|
||||
// iptablesDNS accepts an arg (-I|-D) and IP address of the container and then
|
||||
// generates an iptables command to either add or subtract the needed rule
|
||||
func iptablesDNS(arg, ip string) error {
|
||||
|
@ -707,7 +707,7 @@ func WithDependencyCtrs(ctrs []*Container) CtrCreateOption {
|
||||
// namespace with a minimal configuration.
|
||||
// An optional array of port mappings can be provided.
|
||||
// Conflicts with WithNetNSFrom().
|
||||
func WithNetNS(portMappings []ocicni.PortMapping) CtrCreateOption {
|
||||
func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return ErrCtrFinalized
|
||||
@ -717,6 +717,7 @@ func WithNetNS(portMappings []ocicni.PortMapping) CtrCreateOption {
|
||||
return errors.Wrapf(ErrInvalidArg, "container is already set to join another container's net ns, cannot create a new net ns")
|
||||
}
|
||||
|
||||
ctr.config.PostConfigureNetNS = postConfigureNetNS
|
||||
ctr.config.CreateNetNS = true
|
||||
ctr.config.PortMappings = portMappings
|
||||
|
||||
|
Reference in New Issue
Block a user