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