在k8s上,以非root权限的用户运行容器的方法 – 调查记录(调查中)

环境。

    Minikube版本:v1.16.0。

第一项验证:使用“busybox”进行验证。

步骤

创建一个用于申请使用busypod的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。

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的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的状态…出现错误。

>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文件的第二行。

>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
    在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: {}
    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,也无法正常运行。

bannerAds