github.com/rigado/snapd@v2.42.5-go-mod+incompatible/interfaces/builtin/kubernetes_support.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017-2018 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package builtin
    21  
    22  import (
    23  	"fmt"
    24  	"strings"
    25  
    26  	"github.com/snapcore/snapd/interfaces"
    27  	"github.com/snapcore/snapd/interfaces/apparmor"
    28  	"github.com/snapcore/snapd/interfaces/kmod"
    29  	"github.com/snapcore/snapd/interfaces/seccomp"
    30  	"github.com/snapcore/snapd/interfaces/udev"
    31  	"github.com/snapcore/snapd/snap"
    32  )
    33  
    34  const kubernetesSupportSummary = `allows operating as the Kubernetes service`
    35  
    36  const kubernetesSupportBaseDeclarationPlugs = `
    37    kubernetes-support:
    38      allow-installation: false
    39      deny-auto-connection: true
    40  `
    41  
    42  const kubernetesSupportBaseDeclarationSlots = `
    43    kubernetes-support:
    44      allow-installation:
    45        slot-snap-type:
    46          - core
    47      deny-auto-connection: true
    48  `
    49  
    50  const kubernetesSupportConnectedPlugAppArmorCommon = `
    51  # Common rules for running as a kubernetes node
    52  
    53  # reading cgroups
    54  capability sys_resource,
    55  /sys/fs/cgroup/{,**} r,
    56  
    57  # Allow adjusting the OOM score for containers. Note, this allows adjusting for
    58  # all processes, not just containers.
    59  @{PROC}/@{pid}/oom_score_adj rw,
    60  @{PROC}/sys/vm/overcommit_memory rw,
    61  /sys/kernel/mm/hugepages/{,**} r,
    62  /sys/kernel/mm/transparent_hugepage/{,**} r,
    63  
    64  capability dac_override,
    65  
    66  /usr/bin/systemd-run Cxr -> systemd_run,
    67  profile systemd_run (attach_disconnected,mediate_deleted) {
    68    # Common rules for kubernetes use of systemd_run
    69    #include <abstractions/base>
    70  
    71    /{,usr/}bin/systemd-run rm,
    72    owner @{PROC}/@{pid}/stat r,
    73    owner @{PROC}/@{pid}/environ r,
    74    @{PROC}/cmdline r,
    75    @{PROC}/sys/kernel/osrelease r,
    76    @{PROC}/1/sched r,
    77  
    78    # setsockopt()
    79    capability net_admin,
    80  
    81    # ptrace 'trace' is coarse and not required for using the systemd private
    82    # socket, and while the child profile omits 'capability sys_ptrace', skip
    83    # for now since it isn't strictly required.
    84    ptrace read peer=unconfined,
    85    deny ptrace trace peer=unconfined,
    86    /run/systemd/private rw,
    87  
    88    /{,usr/}bin/true ixr,
    89    @{INSTALL_DIR}/{@{SNAP_NAME},@{SNAP_INSTANCE_NAME}}/@{SNAP_REVISION}/{,usr/}bin/true ixr,
    90  ###KUBERNETES_SUPPORT_SYSTEMD_RUN###
    91  }
    92  `
    93  
    94  const kubernetesSupportConnectedPlugAppArmorKubelet = `
    95  # Allow running as the kubelet service
    96  
    97  # Ideally this would be snap-specific
    98  /run/dockershim.sock rw,
    99  
   100  # Ideally this would be snap-specific (it could if the control plane was a
   101  # snap), but in deployments where the control plane is not a snap, it will tell
   102  # flannel to use this path.
   103  /run/flannel/{,**} rw,
   104  /run/flannel/** k,
   105  
   106  # allow managing pods' cgroups
   107  /sys/fs/cgroup/*/kubepods/{,**} rw,
   108  
   109  # Allow tracing our own processes. Note, this allows seccomp sandbox escape on
   110  # kernels < 4.8
   111  capability sys_ptrace,
   112  ptrace (trace) peer=snap.@{SNAP_NAME}.*,
   113  
   114  # Allow ptracing other processes (as part of ps-style process lookups). Note,
   115  # the peer needs a corresponding tracedby rule. As a special case, disallow
   116  # ptracing unconfined.
   117  ptrace (trace),
   118  deny ptrace (trace) peer=unconfined,
   119  
   120  @{PROC}/[0-9]*/attr/ r,
   121  @{PROC}/[0-9]*/fdinfo/ r,
   122  @{PROC}/[0-9]*/map_files/ r,
   123  @{PROC}/[0-9]*/ns/ r,
   124  
   125  # kubernetes will verify and set panic and panic_on_oops to values it considers
   126  # sane
   127  @{PROC}/sys/kernel/panic w,
   128  @{PROC}/sys/kernel/panic_on_oops w,
   129  @{PROC}/sys/kernel/keys/root_maxbytes r,
   130  @{PROC}/sys/kernel/keys/root_maxkeys r,
   131  
   132  /dev/kmsg r,
   133  
   134  # kubelet calls out to systemd-run for some mounts, but not all of them and not
   135  # unmounts...
   136  capability sys_admin,
   137  mount /var/snap/@{SNAP_NAME}/common/{,**} -> /var/snap/@{SNAP_NAME}/common/{,**},
   138  mount options=(rw, rshared) -> /var/snap/@{SNAP_NAME}/common/{,**},
   139  
   140  /{,usr/}bin/mount ixr,
   141  /{,usr/}bin/umount ixr,
   142  deny /run/mount/utab rw,
   143  umount /var/snap/@{SNAP_INSTANCE_NAME}/common/**,
   144  `
   145  
   146  const kubernetesSupportConnectedPlugAppArmorKubeletSystemdRun = `
   147    # kubelet mount rules
   148    capability sys_admin,
   149    /{,usr/}bin/mount ixr,
   150    mount fstype="tmpfs" tmpfs -> /var/snap/@{SNAP_INSTANCE_NAME}/common/**,
   151    deny /run/mount/utab rw,
   152  `
   153  
   154  const kubernetesSupportConnectedPlugSeccompKubelet = `
   155  # Allow running as the kubelet service
   156  mount
   157  umount
   158  umount2
   159  
   160  unshare
   161  setns - CLONE_NEWNET
   162  `
   163  
   164  var kubernetesSupportConnectedPlugUDevKubelet = []string{
   165  	`KERNEL=="kmsg"`,
   166  }
   167  
   168  const kubernetesSupportConnectedPlugAppArmorKubeproxy = `
   169  # Allow running as the kubeproxy service
   170  
   171  # managing our own cgroup
   172  /sys/fs/cgroup/*/kube-proxy/{,**} rw,
   173  
   174  # Allow reading the state of modules kubernetes needs
   175  /sys/module/libcrc32c/initstate r,
   176  /sys/module/llc/initstate r,
   177  /sys/module/stp/initstate r,
   178  /sys/module/ip_vs/initstate r,
   179  /sys/module/ip_vs_rr/initstate r,
   180  /sys/module/ip_vs_sh/initstate r,
   181  /sys/module/ip_vs_wrr/initstate r,
   182  `
   183  
   184  var kubernetesSupportConnectedPlugKmodKubeProxy = []string{
   185  	`ip_vs_rr`,
   186  	`ip_vs_sh`,
   187  	`ip_vs_wrr`,
   188  	`libcrc32c`,
   189  	`llc`,
   190  	`stp`,
   191  }
   192  
   193  type kubernetesSupportInterface struct {
   194  	commonInterface
   195  }
   196  
   197  func k8sFlavor(plug *interfaces.ConnectedPlug) string {
   198  	var flavor string
   199  	_ = plug.Attr("flavor", &flavor)
   200  	return flavor
   201  }
   202  
   203  func (iface *kubernetesSupportInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   204  	snippet := kubernetesSupportConnectedPlugAppArmorCommon
   205  	systemd_run_extra := ""
   206  
   207  	switch k8sFlavor(plug) {
   208  	case "kubelet":
   209  		systemd_run_extra = kubernetesSupportConnectedPlugAppArmorKubeletSystemdRun
   210  		snippet += kubernetesSupportConnectedPlugAppArmorKubelet
   211  		spec.SetUsesPtraceTrace()
   212  	case "kubeproxy":
   213  		snippet += kubernetesSupportConnectedPlugAppArmorKubeproxy
   214  	default:
   215  		systemd_run_extra = kubernetesSupportConnectedPlugAppArmorKubeletSystemdRun
   216  		snippet += kubernetesSupportConnectedPlugAppArmorKubelet
   217  		snippet += kubernetesSupportConnectedPlugAppArmorKubeproxy
   218  		spec.SetUsesPtraceTrace()
   219  	}
   220  
   221  	old := "###KUBERNETES_SUPPORT_SYSTEMD_RUN###"
   222  	spec.AddSnippet(strings.Replace(snippet, old, systemd_run_extra, -1))
   223  	return nil
   224  }
   225  
   226  func (iface *kubernetesSupportInterface) SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   227  	flavor := k8sFlavor(plug)
   228  	if flavor == "kubelet" || flavor == "" {
   229  		snippet := kubernetesSupportConnectedPlugSeccompKubelet
   230  		spec.AddSnippet(snippet)
   231  	}
   232  	return nil
   233  }
   234  
   235  func (iface *kubernetesSupportInterface) UDevConnectedPlug(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   236  	flavor := k8sFlavor(plug)
   237  	if flavor == "kubelet" || flavor == "" {
   238  		for _, rule := range kubernetesSupportConnectedPlugUDevKubelet {
   239  			spec.TagDevice(rule)
   240  		}
   241  	}
   242  	return nil
   243  }
   244  
   245  func (iface *kubernetesSupportInterface) KModConnectedPlug(spec *kmod.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   246  	flavor := k8sFlavor(plug)
   247  	if flavor == "kubeproxy" || flavor == "" {
   248  		for _, m := range kubernetesSupportConnectedPlugKmodKubeProxy {
   249  			if err := spec.AddModule(m); err != nil {
   250  				return err
   251  			}
   252  		}
   253  	}
   254  	return nil
   255  }
   256  
   257  func (iface *kubernetesSupportInterface) BeforePreparePlug(plug *snap.PlugInfo) error {
   258  	// It's fine if flavor isn't specified, but if it is, it needs to be
   259  	// either "kubelet" or "kubeproxy"
   260  	if t, ok := plug.Attrs["flavor"]; ok && t != "kubelet" && t != "kubeproxy" {
   261  		return fmt.Errorf(`kubernetes-support plug requires "flavor" to be either "kubelet" or "kubeproxy"`)
   262  	}
   263  
   264  	return nil
   265  }
   266  
   267  func init() {
   268  	registerIface(&kubernetesSupportInterface{commonInterface{
   269  		name:                 "kubernetes-support",
   270  		summary:              kubernetesSupportSummary,
   271  		implicitOnClassic:    true,
   272  		implicitOnCore:       true,
   273  		baseDeclarationPlugs: kubernetesSupportBaseDeclarationPlugs,
   274  		baseDeclarationSlots: kubernetesSupportBaseDeclarationSlots,
   275  	}})
   276  }