k8s上で、コンテナをroot権限以外のユーザーで動作させる方法ー調査の記録(調査途中)


## 環境
1. minikube version: v1.16.0

## 検証1:「busybox」での検証

## 手順

busypodをapplyする為のyamlを作る。

```
kubectl run busybox --image=busybox --restart=Never --dry-run=client -o=yaml -- sleep 3600 > pod_busybox3600.yaml
```

出来上がったyamlファイルをテキストエディタで修正する。

```
apiVersion: v1kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: busybox
  name: busybox
spec:
  containers:
  - args:
    - sleep
    - "3600"
    image: busybox
    name: busybox
    resources: {​​​​​​​}​​​​​​​
  securityContext:            ←ここを追記
    runAsUser: 1000            ←ここを追記
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {​​​​​​​​​​​​​​}​​​​​​​​​​​​​​
```
作ったyamlが正しくかを確認する。

```
kubectl apply -f pod_busybox3600.yaml --dry-run=client -o=yaml
```

```
apiVersion: v1
kind: Pod
metadata:
  annotations:
    {​​​​​​​​​​​​​​​記載省略}​​​​​​​​​​​​​​​
  creationTimestamp: null
  labels:
    run: busybox
  name: busybox
  namespace: default
spec:
  containers:
  - args:
    - sleep
    - "3600"
    image: busybox
    name: busybox
    resources: {​​​​​​​​​​​​​​​}​​​​​​​​​​​​​​​
  dnsPolicy: ClusterFirst
  restartPolicy: Never
  securityContext:          ←ここをチェック
    runAsUser: 1000          ←ここをチェック
status: {​​​​​​​​​​​​​​​}​​​​​​​​​​​​​​​
```

作ったyamlでbusyboxをapplyする。

```
kubectl apply -f pod_busybox3600.yaml
```
Podの状態を確認

```
>kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
busybox   1/1     Running   0          7s
```

起動までに問題がなかったかを確認

```
>kubectl describe pod busybox
Name:         busybox
Namespace:    default
Priority:     0

{記載省略}

Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  47s   default-scheduler  Successfully assigned default/busybox to minikube
  Normal  Pulling    46s   kubelet            Pulling image "busybox"
  Normal  Pulled     43s   kubelet            Successfully pulled image "busybox" in 3.178333781s
  Normal  Created    43s   kubelet            Created container busybox
  Normal  Started    43s   kubelet            Started container busybox
```

実行ユーザーを確認

```
>kubectl exec -it busybox -- sh
/ $ whoami
whoami: unknown uid 1000    ←　意図したユーザーで実行されている事を確認
```

各プロセスの実行ユーザーを確認

```
/ $ ps
PID   USER     TIME  COMMAND
    1 1000      0:00 sleep 3600
    9 1000      0:00 sh
   17 1000      0:00 ps
/ $
```

busyboxのユーザー一覧を確認

```
/ $ cat etc/passwd
root:x:0:0:root:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/false
bin:x:2:2:bin:/bin:/bin/false
sys:x:3:3:sys:/dev:/bin/false
sync:x:4:100:sync:/bin:/bin/sync
mail:x:8:8:mail:/var/spool/mail:/bin/false
www-data:x:33:33:www-data:/var/www:/bin/false
operator:x:37:37:Operator:/var:/bin/false
nobody:x:65534:65534:nobody:/home:/bin/false
/ $
```

ここまでの検証結果まとめ。
busyboxの場合は、存在しないユーザー(UID)を設定してもコンテナは正常に起動し、且つ、そのUIDで動作出来た。

## 検証2:「nginx」での検証

## 手順

nginxをapplyする為のyamlを作る。

```
kubectl run nginx --image=nginx --restart=Never --dry-run=client -o=yaml > pod_nginx.yaml
```

出来上がったyamlファイルをテキストエディタで修正する。

```
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    resources: {}
  securityContext:            ←ここを追記
    runAsUser: 1000            ←ここを追記
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {}
```
作ったyamlが正しくかを確認する。

```
kubectl apply -f pod_nginx.yaml --dry-run=client -o=yaml
```

```
apiVersion: v1
kind: Pod
metadata:
  annotations:

{記載省略}

  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
  namespace: default
spec:
  containers:
  - image: nginx
    name: nginx
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Never
  securityContext:          ←ここをチェック
    runAsUser: 1000          ←ここをチェック
status: {}
```

作ったyamlでbusyboxをapplyする。

```
>kubectl apply -f pod_nginx.yaml
pod/nginx created
```
Podの状態を確認 。。。Errorになっている。

```
>kubectl get pod
NAME    READY   STATUS   RESTARTS   AGE
nginx   0/1     Error    0          29s
```

起動までに問題がなかったかを確認

```
>kubectl describe pod nginx
Name:         nginx
Namespace:    default
Priority:     0

{記載省略}

Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  2m5s  default-scheduler  Successfully assigned default/nginx to minikube
  Normal  Pulling    2m4s  kubelet            Pulling image "nginx"
  Normal  Pulled     2m1s  kubelet            Successfully pulled image "nginx" in 3.162750793s
  Normal  Created    2m1s  kubelet            Created container nginx
  Normal  Started    2m1s  kubelet            Started container nginx
```

実行ユーザーを確認。エラーなのでコンテナに入れず。

```
>kubectl exec -it nginx -- sh
error: cannot exec into a container in a completed pod; current phase is Failed
```

ログを確認

```
>kubectl logs nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: can not modify /etc/nginx/conf.d/default.conf (read-only file system?)
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/01/08 14:33:02 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
2021/01/08 14:33:02 [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)

```

最初の警告メッセージを見てみる。
the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
↓
「user」ディレクティブは、マスタープロセスがスーパーユーザー権限で実行されている場合にのみ意味があり、/ etc / nginx / nginx.conf：2では無視されます。


うーん。
root実行に戻して、/etc/nginx/nginx.confの2行目を見てみる。


```
>kubectl delete -f pod_nginx.yaml
pod "nginx" deleted

>kubectl run nginx --image=nginx --restart=Never
pod/nginx created

>kubectl exec -it nginx -- sh
# cat /etc/nginx/nginx.conf
                       ←ここが1行目
user  nginx;           ←ここが2行目
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

{以下、記載省略}
```

nginxっていうユーザーでないとダメ？なのかもしれない。
nginxというユーザーがあるのか調べる。

```
# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
{記載省略}
nginx:x:101:101:nginx user,,,:/nonexistent:/bin/false　　　←いた！
```

いったんnginxのpodを削除して、pod_nginx.yamlのrunAsUserを101に変えて再トライ。

```
# exit
command terminated with exit code 127

>kubectl delete pod nginx
pod "nginx" deleted
```

```
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    resources: {}
  securityContext:
    runAsUser: 101　　　　← ここを1000から101に変更。
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {}
```

```
>kubectl apply -f pod_nginx.yaml
pod/nginx created

>kubectl get pod
NAME    READY   STATUS   RESTARTS   AGE
nginx   0/1     Error    0          10s

>kubectl logs nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: can not modify /etc/nginx/conf.d/default.conf (read-only file system?)
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2021/01/08 15:05:53 [warn] 1#1: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:2
2021/01/08 15:05:53 [emerg] 1#1: mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
nginx: [emerg] mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)
```

やはり、Errorになってしまった。結局最後のログで　ディレクトリ作りたいけれど権限足らないってことみたい。
つまりは元のコンテナで適切に仕事が出来るユーザーを作っておいた上で、runAsUserに指定しないとダメって事かなー。

## 検証3:「node」での検証

最初にDockerHubの公式イメージからnodejsのコンテナイメージを取得し、kubernetesのPod内のコンテナとして起動する。
DockerHubのnodejs公式イメージ(https://hub.docker.com/_/node)

```
>kubectl run mynodejs --image=node -- /bin/sh -c "sleep 3600"
pod/mynodejs created

>kubectl get pod mynodejs
NAME       READY   STATUS    RESTARTS   AGE
mynodejs   1/1     Running   0          15s
```

起動したコンテナにログインして以下の事を確認する。
1. ログイン時のユーザーは何になるか？
2. 各プロセスは、どのユーザーで起動しているか？
3. 登録されているユーザーにはどんなものがあるか？

```
>kubectl exec -it mynodejs -- /bin/sh
# whoami
root
# ps -aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0   4280   696 ?        Ss   03:13   0:00 /bin/sh -c sleep 3600
root           8  0.0  0.0   4188   640 ?        S    03:13   0:00 sleep 3600
root           9  0.0  0.0   4280   736 pts/0    Ss   03:14   0:00 /bin/sh
root          17  0.0  0.1  36636  2732 pts/0    R+   03:14   0:00 ps -aux
# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
{中略}
_apt:x:100:65534::/nonexistent:/bin/false
node:x:1000:1000::/home/node:/bin/bash  ← node というユーザーが存在。UID:GIDともに1000
#
```

起動ユーザーを指定するyamlを作ってnodejsコンテナを、kubernetesのPod内のコンテナとして起動する。
1. yamlファイルを生成。

```
>kubectl run mynodejs --image=node --dry-run=client -o=yaml -- /bin/sh -c "node; sleep 3600" > mynodejs.yaml
```

2. securityContextで、ユーザーとグループを指定。またrootでの起動を抑止。

```
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: mynodejs
  name: mynodejs
spec:
  securityContext:      ←ここを追加
    runAsUser: 1000     ←ここを追加
    runAsGroup: 1000    ←ここを追加
    runAsNonRoot: True  ←ここを追加
  containers:
  - args:
    - /bin/sh
    - -c
    - node; sleep 3600
    image: node
    name: mynodejs
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
```
3. kubernetesのPod内のコンテナとして起動する。

```
>kubectl apply -f mynodejs.yaml
pod/mynodejs created
```


起動したコンテナにログインして以下の事を確認する。
1. ログイン時のユーザーは何になるか？
2. nodeコマンドが動くか？
3. 各プロセスは、どのユーザーで起動しているか？

```
>kubectl apply -f mynodejs.yaml
pod/mynodejs created

>kubectl exec -it mynodejs -- sh
$ whoami
node
$ ps -aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
node           1  0.0  0.0   4280   696 ?        Ss   03:31   0:00 /bin/sh -c node; sleep 3600
node          19  0.0  0.0   4188   668 ?        S    03:31   0:00 sleep 3600
node          20  0.0  0.0   4280   700 pts/0    Ss   03:32   0:00 sh
node          27  0.0  0.1  36636  2856 pts/0    R+   03:33   0:00 ps -aux
$ node
Welcome to Node.js v15.5.1.
Type ".help" for more information.
>
```


結果。
まずコンテナ自体がrootユーザー以外で動作できるアプリケーションのかたまりである事が必要。
今回のようにnodeユーザーで動作する前提のコンテナなら、Podでユーザーを指定して動作させる事が可能。
nginxのように実行するユーザーに制限があるままだと、適用なユーザーIDを指定してもうまくはいかない。