本連載では、エンタープライズシステムでコンテナやKubernetesを活用した業務システムを開発・運用するエンジニアに向けて、知っておくべきKubernetesセキュリティの基礎知識、Microsoftが提供するパブリッククラウド「Azure」を使ったクラウドでのKubernetesセキュリティ対策のポイント、気を付けておきたい注意点などの実践的なノウハウを紹介します。

今回も引き続き、コンテナセキュリティの基礎となるコンテナ技術について説明します。前回と前前回は、コンテナの基礎になっているLinuxカーネルの機能「namespace」「cgroup」「Capability」について説明しました。

コンテナ技術の基礎の最終回である第3回では、これらの技術がKubernetesとどのような関係があるのかを説明していきます。

Kubeneresとnamespace

まずは、Kubeneresのノードの中にどのようなnamespaceがあるのかを見てみます。ノードの中を探索するための特権を持ったDaemonSetをデプロイします。DaemonSetのイメージの素になるDockerfileは以下にしました。


FROM ubuntu:20.04

ENTRYPOINT ["tail","-f", "/etc/profile"]

DaemonSetを定義するyamlは以下です。securityContextで特権を与えており、hostPIDとhostNetworkをtrueにし、hostPathのルートをマウントする極めて危険なものです。この中にkubectl exec -it root-daemon-xxxxx -- bashで入り、ノードの中を探索します。


apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: root-daemon
spec:
  selector:
    matchLabels:
      app: root-daemon
  template:
    metadata:
      labels:
        app: root-daemon
    spec:
      hostPID: true
      hostNetwork: true
      containers:
      - name: network-collect
        image: xxxxxxxxxxxxxxxxxx.azurecr.io/root-daemon:v0.0.1
        securityContext:
          privileged: true
        resources:
          limits:
            cpu: 50m
            memory: 50Mi
          requests:
            cpu: 50m
            memory: 50Mi
        volumeMounts:
        - mountPath: /hostroot
          name: hostroot
      volumes:
      - name: hostroot
        hostPath:
          path: /

ベーシックなnginxのDeploymentも適用してみます。


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-seccomp
spec:
  selector:
    matchLabels:
      app: nginx-seccomp
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx-seccomp
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 100m
            memory: 125Mi
          requests:
            cpu: 90m
            memory: 115Mi

kubectl exec -it root-daemon-xxxxx -- bashでノードの中を探索する前に、同じノードのnginxのContainer IDを確認しておきます。今回は、f66dd3c1e442f0da10aaf0d6954fcafa4d3533da5f3bb597ca7003c66bbb437dがContainer IDです。


$ kubectl get pods -o wide
NAME                                        READY   STATUS    RESTARTS   AGE    IP             NODE                                NOMINATED NODE   READINESS GATES
nginx-deployment-seccomp-55449744c7-g4zp9   1/1     Running   0          124m   10.240.0.104   aks-agentpool-23069546-vmss000000              
nginx-deployment-seccomp-55449744c7-z2zd5   1/1     Running   0          124m   10.240.0.200   aks-agentpool-23069546-vmss000002              
root-daemon-gzcrq                           1/1     Running   0          149m   10.240.0.115   aks-agentpool-23069546-vmss000002              
root-daemon-jbzcd                           1/1     Running   0          149m   10.240.0.4     aks-agentpool-23069546-vmss000000              
$ kubectl describe pod nginx-deployment-seccomp-55449744c7-z2zd5 | grep "Container ID"
    Container ID:   containerd://f66dd3c1e442f0da10aaf0d6954fcafa4d3533da5f3bb597ca7003c66bbb437d

次に、nginxのnamespaceがどうなっているのかを確認してみます。


# ls -l /proc/14611/ns
lrwxrwxrwx 1 root root 0 Nov 30 01:57 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Nov 30 01:57 ipc -> 'ipc:[4026532474]'
lrwxrwxrwx 1 root root 0 Nov 30 01:57 mnt -> 'mnt:[4026532476]'
lrwxrwxrwx 1 root root 0 Nov 30 01:57 net -> 'net:[4026532402]'
lrwxrwxrwx 1 root root 0 Nov 30 01:57 pid -> 'pid:[4026532477]'
lrwxrwxrwx 1 root root 0 Nov 30 01:57 pid_for_children -> 'pid:[4026532477]'
lrwxrwxrwx 1 root root 0 Nov 30 01:57 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Nov 30 01:57 uts -> 'uts:[4026532473]'