github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/oci/spec.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package oci
    18  
    19  import (
    20  	"context"
    21  	"path/filepath"
    22  	"runtime"
    23  
    24  	"github.com/containerd/containerd/namespaces"
    25  	"github.com/containerd/containerd/platforms"
    26  
    27  	"github.com/containerd/containerd/containers"
    28  	specs "github.com/opencontainers/runtime-spec/specs-go"
    29  )
    30  
    31  const (
    32  	rwm               = "rwm"
    33  	defaultRootfsPath = "rootfs"
    34  )
    35  
    36  var (
    37  	defaultUnixEnv = []string{
    38  		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    39  	}
    40  )
    41  
    42  // Spec is a type alias to the OCI runtime spec to allow third part SpecOpts
    43  // to be created without the "issues" with go vendoring and package imports
    44  type Spec = specs.Spec
    45  
    46  // GenerateSpec will generate a default spec from the provided image
    47  // for use as a containerd container
    48  func GenerateSpec(ctx context.Context, client Client, c *containers.Container, opts ...SpecOpts) (*Spec, error) {
    49  	return GenerateSpecWithPlatform(ctx, client, platforms.DefaultString(), c, opts...)
    50  }
    51  
    52  // GenerateSpecWithPlatform will generate a default spec from the provided image
    53  // for use as a containerd container in the platform requested.
    54  func GenerateSpecWithPlatform(ctx context.Context, client Client, platform string, c *containers.Container, opts ...SpecOpts) (*Spec, error) {
    55  	var s Spec
    56  	if err := generateDefaultSpecWithPlatform(ctx, platform, c.ID, &s); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	return &s, ApplyOpts(ctx, client, c, &s, opts...)
    61  }
    62  
    63  func generateDefaultSpecWithPlatform(ctx context.Context, platform, id string, s *Spec) error {
    64  	plat, err := platforms.Parse(platform)
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	if plat.OS == "windows" {
    70  		err = populateDefaultWindowsSpec(ctx, s, id)
    71  	} else {
    72  		err = populateDefaultUnixSpec(ctx, s, id)
    73  		if err == nil && runtime.GOOS == "windows" {
    74  			// To run LCOW we have a Linux and Windows section. Add an empty one now.
    75  			s.Windows = &specs.Windows{}
    76  		}
    77  	}
    78  	return err
    79  }
    80  
    81  // ApplyOpts applies the options to the given spec, injecting data from the
    82  // context, client and container instance.
    83  func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *Spec, opts ...SpecOpts) error {
    84  	for _, o := range opts {
    85  		if err := o(ctx, client, c, s); err != nil {
    86  			return err
    87  		}
    88  	}
    89  
    90  	return nil
    91  }
    92  
    93  func defaultUnixCaps() []string {
    94  	return []string{
    95  		"CAP_CHOWN",
    96  		"CAP_DAC_OVERRIDE",
    97  		"CAP_FSETID",
    98  		"CAP_FOWNER",
    99  		"CAP_MKNOD",
   100  		"CAP_NET_RAW",
   101  		"CAP_SETGID",
   102  		"CAP_SETUID",
   103  		"CAP_SETFCAP",
   104  		"CAP_SETPCAP",
   105  		"CAP_NET_BIND_SERVICE",
   106  		"CAP_SYS_CHROOT",
   107  		"CAP_KILL",
   108  		"CAP_AUDIT_WRITE",
   109  	}
   110  }
   111  
   112  func defaultUnixNamespaces() []specs.LinuxNamespace {
   113  	return []specs.LinuxNamespace{
   114  		{
   115  			Type: specs.PIDNamespace,
   116  		},
   117  		{
   118  			Type: specs.IPCNamespace,
   119  		},
   120  		{
   121  			Type: specs.UTSNamespace,
   122  		},
   123  		{
   124  			Type: specs.MountNamespace,
   125  		},
   126  		{
   127  			Type: specs.NetworkNamespace,
   128  		},
   129  	}
   130  }
   131  
   132  func populateDefaultUnixSpec(ctx context.Context, s *Spec, id string) error {
   133  	ns, err := namespaces.NamespaceRequired(ctx)
   134  	if err != nil {
   135  		return err
   136  	}
   137  
   138  	*s = Spec{
   139  		Version: specs.Version,
   140  		Root: &specs.Root{
   141  			Path: defaultRootfsPath,
   142  		},
   143  		Process: &specs.Process{
   144  			Cwd:             "/",
   145  			NoNewPrivileges: true,
   146  			User: specs.User{
   147  				UID: 0,
   148  				GID: 0,
   149  			},
   150  			Capabilities: &specs.LinuxCapabilities{
   151  				Bounding:    defaultUnixCaps(),
   152  				Permitted:   defaultUnixCaps(),
   153  				Inheritable: defaultUnixCaps(),
   154  				Effective:   defaultUnixCaps(),
   155  			},
   156  			Rlimits: []specs.POSIXRlimit{
   157  				{
   158  					Type: "RLIMIT_NOFILE",
   159  					Hard: uint64(1024),
   160  					Soft: uint64(1024),
   161  				},
   162  			},
   163  		},
   164  		Mounts: []specs.Mount{
   165  			{
   166  				Destination: "/proc",
   167  				Type:        "proc",
   168  				Source:      "proc",
   169  				Options:     []string{"nosuid", "noexec", "nodev"},
   170  			},
   171  			{
   172  				Destination: "/dev",
   173  				Type:        "tmpfs",
   174  				Source:      "tmpfs",
   175  				Options:     []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
   176  			},
   177  			{
   178  				Destination: "/dev/pts",
   179  				Type:        "devpts",
   180  				Source:      "devpts",
   181  				Options:     []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
   182  			},
   183  			{
   184  				Destination: "/dev/shm",
   185  				Type:        "tmpfs",
   186  				Source:      "shm",
   187  				Options:     []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
   188  			},
   189  			{
   190  				Destination: "/dev/mqueue",
   191  				Type:        "mqueue",
   192  				Source:      "mqueue",
   193  				Options:     []string{"nosuid", "noexec", "nodev"},
   194  			},
   195  			{
   196  				Destination: "/sys",
   197  				Type:        "sysfs",
   198  				Source:      "sysfs",
   199  				Options:     []string{"nosuid", "noexec", "nodev", "ro"},
   200  			},
   201  			{
   202  				Destination: "/run",
   203  				Type:        "tmpfs",
   204  				Source:      "tmpfs",
   205  				Options:     []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
   206  			},
   207  		},
   208  		Linux: &specs.Linux{
   209  			MaskedPaths: []string{
   210  				"/proc/acpi",
   211  				"/proc/asound",
   212  				"/proc/kcore",
   213  				"/proc/keys",
   214  				"/proc/latency_stats",
   215  				"/proc/timer_list",
   216  				"/proc/timer_stats",
   217  				"/proc/sched_debug",
   218  				"/sys/firmware",
   219  				"/proc/scsi",
   220  			},
   221  			ReadonlyPaths: []string{
   222  				"/proc/bus",
   223  				"/proc/fs",
   224  				"/proc/irq",
   225  				"/proc/sys",
   226  				"/proc/sysrq-trigger",
   227  			},
   228  			CgroupsPath: filepath.Join("/", ns, id),
   229  			Resources: &specs.LinuxResources{
   230  				Devices: []specs.LinuxDeviceCgroup{
   231  					{
   232  						Allow:  false,
   233  						Access: rwm,
   234  					},
   235  				},
   236  			},
   237  			Namespaces: defaultUnixNamespaces(),
   238  		},
   239  	}
   240  	return nil
   241  }
   242  
   243  func populateDefaultWindowsSpec(ctx context.Context, s *Spec, id string) error {
   244  	*s = Spec{
   245  		Version: specs.Version,
   246  		Root:    &specs.Root{},
   247  		Process: &specs.Process{
   248  			Cwd: `C:\`,
   249  		},
   250  		Windows: &specs.Windows{},
   251  	}
   252  	return nil
   253  }