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

basic support for running in an user namespace #1729

Merged
merged 7 commits into from Aug 17, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 14 additions & 4 deletions cmd/crio/config.go
Expand Up @@ -34,6 +34,13 @@ var commentedConfigTemplate = template.Must(template.New("config").Parse(`
#storage_option = [
{{ range $opt := .StorageOptions }}{{ printf "#\t%q,\n" $opt }}{{ end }}#]

# file_locking is whether file-based locking will be used instead of
# in-memory locking
file_locking = {{ .FileLocking }}

# file_locking_path is the file used for file-based locking
file_locking_path = "{{ .FileLockingPath }}"

# The "crio.api" table contains settings for the kubelet/gRPC interface.
[crio.api]

Expand Down Expand Up @@ -62,10 +69,6 @@ stream_tls_key = "{{ .StreamTLSKey }}"
# This file can change, and CRIO will automatically pick up the changes within 5 minutes.
stream_tls_ca = "{{ .StreamTLSCA }}"

# file_locking is whether file-based locking will be used instead of
# in-memory locking
file_locking = {{ .FileLocking }}

# The "crio.runtime" table contains settings pertaining to the OCI
# runtime used and options for how to set up and manage the OCI runtime.
[crio.runtime]
Expand Down Expand Up @@ -163,6 +166,13 @@ pids_limit = {{ .PidsLimit }}
# Negative values indicate that no limit is imposed.
log_size_max = {{ .LogSizeMax }}

# container_exits_dir is the directory in which container exit files are
# written to by conmon.
container_exits_dir = "{{ .ContainerExitsDir }}"

# container_attach_socket_dir is the location for container attach sockets.
container_attach_socket_dir = "{{ .ContainerAttachSocketDir }}"

# read-only indicates whether all containers will run in read-only mode
read_only = {{ .ReadOnly }}

Expand Down
42 changes: 25 additions & 17 deletions lib/config.go
Expand Up @@ -96,6 +96,9 @@ type RootConfig struct {
// File-based locking is required when multiple users of lib are
// present on the same system
FileLocking bool `toml:"file_locking"`

// FileLockingPath specifies the path to use for the locking.
FileLockingPath string `toml:"file_locking_path"`
}

// RuntimeConfig represents the "crio.runtime" TOML config table.
Expand Down Expand Up @@ -177,6 +180,9 @@ type RuntimeConfig struct {
// written to by conmon.
ContainerExitsDir string `toml:"container_exits_dir"`

// ContainerAttachSocketDir is the location for container attach sockets.
ContainerAttachSocketDir string `toml:"container_attach_socket_dir"`

// ManageNetworkNSLifecycle determines whether we pin and remove network namespace
// and manage its lifecycle
ManageNetworkNSLifecycle bool `toml:"manage_network_ns_lifecycle"`
Expand Down Expand Up @@ -313,12 +319,13 @@ func DefaultConfig() *Config {
insecureRegistries, _ := sysregistries.GetInsecureRegistries(&types.SystemContext{})
return &Config{
RootConfig: RootConfig{
Root: storage.DefaultStoreOptions.GraphRoot,
RunRoot: storage.DefaultStoreOptions.RunRoot,
Storage: storage.DefaultStoreOptions.GraphDriverName,
StorageOptions: storage.DefaultStoreOptions.GraphDriverOptions,
LogDir: "/var/log/crio/pods",
FileLocking: true,
Root: storage.DefaultStoreOptions.GraphRoot,
RunRoot: storage.DefaultStoreOptions.RunRoot,
Storage: storage.DefaultStoreOptions.GraphDriverName,
StorageOptions: storage.DefaultStoreOptions.GraphDriverOptions,
LogDir: "/var/log/crio/pods",
FileLocking: true,
FileLockingPath: lockPath,
},
RuntimeConfig: RuntimeConfig{
Runtime: "/usr/bin/runc",
Expand All @@ -329,17 +336,18 @@ func DefaultConfig() *Config {
ConmonEnv: []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
},
SELinux: selinuxEnabled(),
SeccompProfile: seccompProfilePath,
ApparmorProfile: apparmorProfileName,
CgroupManager: cgroupManager,
PidsLimit: DefaultPidsLimit,
ContainerExitsDir: containerExitsDir,
HooksDirPath: hooks.DefaultDir,
LogSizeMax: DefaultLogSizeMax,
DefaultMountsFile: "",
DefaultCapabilities: DefaultCapabilities,
LogLevel: "error",
SELinux: selinuxEnabled(),
SeccompProfile: seccompProfilePath,
ApparmorProfile: apparmorProfileName,
CgroupManager: cgroupManager,
PidsLimit: DefaultPidsLimit,
ContainerExitsDir: containerExitsDir,
ContainerAttachSocketDir: oci.ContainerAttachSocketDir,
HooksDirPath: hooks.DefaultDir,
LogSizeMax: DefaultLogSizeMax,
DefaultMountsFile: "",
DefaultCapabilities: DefaultCapabilities,
LogLevel: "error",
},
ImageConfig: ImageConfig{
DefaultTransport: defaultTransport,
Expand Down
4 changes: 2 additions & 2 deletions lib/container_server.go
Expand Up @@ -129,14 +129,14 @@ func New(ctx context.Context, config *Config) (*ContainerServer, error) {
return nil, err
}

runtime, err := oci.New(config.Runtime, config.RuntimeUntrustedWorkload, config.DefaultWorkloadTrust, config.Conmon, config.ConmonEnv, config.CgroupManager, config.ContainerExitsDir, config.LogSizeMax, config.NoPivot)
runtime, err := oci.New(config.Runtime, config.RuntimeUntrustedWorkload, config.DefaultWorkloadTrust, config.Conmon, config.ConmonEnv, config.CgroupManager, config.ContainerExitsDir, config.ContainerAttachSocketDir, config.LogSizeMax, config.NoPivot)
if err != nil {
return nil, err
}

var lock sync.Locker
if config.FileLocking {
fileLock, err := cstorage.GetLockfile(lockPath)
fileLock, err := cstorage.GetLockfile(config.FileLockingPath)
if err != nil {
return nil, fmt.Errorf("error obtaining lockfile: %v", err)
}
Expand Down
46 changes: 25 additions & 21 deletions oci/oci.go
Expand Up @@ -53,35 +53,38 @@ func New(runtimeTrustedPath string,
conmonEnv []string,
cgroupManager string,
containerExitsDir string,
containerAttachSocketDir string,
logSizeMax int64,
noPivot bool) (*Runtime, error) {
r := &Runtime{
name: filepath.Base(runtimeTrustedPath),
trustedPath: runtimeTrustedPath,
untrustedPath: runtimeUntrustedPath,
trustLevel: trustLevel,
conmonPath: conmonPath,
conmonEnv: conmonEnv,
cgroupManager: cgroupManager,
containerExitsDir: containerExitsDir,
logSizeMax: logSizeMax,
noPivot: noPivot,
name: filepath.Base(runtimeTrustedPath),
trustedPath: runtimeTrustedPath,
untrustedPath: runtimeUntrustedPath,
trustLevel: trustLevel,
conmonPath: conmonPath,
conmonEnv: conmonEnv,
cgroupManager: cgroupManager,
containerExitsDir: containerExitsDir,
containerAttachSocketDir: containerAttachSocketDir,
logSizeMax: logSizeMax,
noPivot: noPivot,
}
return r, nil
}

// Runtime stores the information about a oci runtime
type Runtime struct {
name string
trustedPath string
untrustedPath string
trustLevel string
conmonPath string
conmonEnv []string
cgroupManager string
containerExitsDir string
logSizeMax int64
noPivot bool
name string
trustedPath string
untrustedPath string
trustLevel string
conmonPath string
conmonEnv []string
cgroupManager string
containerExitsDir string
containerAttachSocketDir string
logSizeMax int64
noPivot bool
}

// syncInfo is used to return data from monitor process to daemon
Expand Down Expand Up @@ -173,7 +176,7 @@ func (r *Runtime) CreateContainer(c *Container, cgroupParent string) (err error)
args = append(args, "-p", filepath.Join(c.bundlePath, "pidfile"))
args = append(args, "-l", c.logPath)
args = append(args, "--exit-dir", r.containerExitsDir)
args = append(args, "--socket-dir-path", ContainerAttachSocketDir)
args = append(args, "--socket-dir-path", r.containerAttachSocketDir)
args = append(args, "--log-level", logrus.GetLevel().String())
if r.logSizeMax >= 0 {
args = append(args, "--log-size-max", fmt.Sprintf("%v", r.logSizeMax))
Expand Down Expand Up @@ -206,6 +209,7 @@ func (r *Runtime) CreateContainer(c *Container, cgroupParent string) (err error)
// 0, 1 and 2 are stdin, stdout and stderr
cmd.Env = append(r.conmonEnv, fmt.Sprintf("_OCI_SYNCPIPE=%d", 3))
cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_STARTPIPE=%d", 4))
cmd.Env = append(cmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", os.Getenv("XDG_RUNTIME_DIR")))

err = cmd.Start()
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions oci/oci_linux.go
Expand Up @@ -27,6 +27,7 @@ func (r *Runtime) createContainerPlatform(c *Container, cgroupParent string, pid
control, err := cgroups.New(cgroups.V1, cgroups.StaticPath(filepath.Join(cgroupParent, "/crio-conmon-"+c.id)), &rspec.LinuxResources{})
if err != nil {
logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
return nil
}

// Here we should defer a crio-connmon- cgroup hierarchy deletion, but it will
Expand Down
2 changes: 1 addition & 1 deletion server/container_attach.go
Expand Up @@ -72,7 +72,7 @@ func (ss streamService) Attach(containerID string, inputStream io.Reader, output
}
})

attachSocketPath := filepath.Join(oci.ContainerAttachSocketDir, c.ID(), "attach")
attachSocketPath := filepath.Join(ss.runtimeServer.Config().ContainerAttachSocketDir, c.ID(), "attach")
conn, err := net.DialUnix("unixpacket", nil, &net.UnixAddr{Name: attachSocketPath, Net: "unixpacket"})
if err != nil {
return fmt.Errorf("failed to connect to container %s attach socket: %v", c.ID(), err)
Expand Down
6 changes: 6 additions & 0 deletions server/container_create_linux.go
Expand Up @@ -874,6 +874,12 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
}()
}

if os.Getenv("_CRIO_ROOTLESS") != "" {
if err := makeOCIConfigurationRootless(&specgen); err != nil {
return nil, err
}
}

saveOptions := generate.ExportOptions{}
if err = specgen.SaveToFile(filepath.Join(containerInfo.RunDir, "config.json"), saveOptions); err != nil {
return nil, err
Expand Down
48 changes: 48 additions & 0 deletions server/rootless.go
@@ -0,0 +1,48 @@
package server

import (
"strings"

rspec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
)

func hasNamespace(config *rspec.Spec, ns string) bool {
for _, n := range config.Linux.Namespaces {
if string(n.Type) == ns {
return true
}
}
return false
}
func makeOCIConfigurationRootless(g *generate.Generator) error {
g.Config.Linux.Resources = nil
g.Config.Process.OOMScoreAdj = nil
g.Config.Process.ApparmorProfile = ""

for i := range g.Config.Mounts {
var newOptions []string
for _, o := range g.Config.Mounts[i].Options {
if strings.HasPrefix(o, "gid=") {
continue
}
newOptions = append(newOptions, o)
}
g.Config.Mounts[i].Options = newOptions
}

if !hasNamespace(g.Config, rspec.NetworkNamespace) {
g.RemoveMount("/sys")
sysMnt := rspec.Mount{
Destination: "/sys",
Type: "bind",
Source: "/sys",
Options: []string{"nosuid", "noexec", "nodev", "ro", "rbind"},
}
g.AddMount(sysMnt)
}

g.SetLinuxCgroupsPath("")

return nil
}
6 changes: 6 additions & 0 deletions server/sandbox_run_linux.go
Expand Up @@ -544,6 +544,12 @@ func (s *Server) runPodSandbox(ctx context.Context, req *pb.RunPodSandboxRequest
g.SetRootPath(mountPoint)
}

if os.Getenv("_CRIO_ROOTLESS") != "" {
if err := makeOCIConfigurationRootless(&g); err != nil {
return nil, err
}
}

container.SetSpec(g.Spec())

sb.SetInfraContainer(container)
Expand Down
2 changes: 0 additions & 2 deletions server/server.go
Expand Up @@ -278,8 +278,6 @@ func New(ctx context.Context, config *Config) (*Server, error) {
return nil, err
}

config.ContainerExitsDir = oci.ContainerExitsDir

// This is used to monitor container exits using inotify
if err := os.MkdirAll(config.ContainerExitsDir, 0755); err != nil {
return nil, err
Expand Down