简介
因为有时候对 ServiceAccount(SA)、SecurityContextConstriant (SCC)、securityContext(SC) 有些混乱,所以感觉有必要做下实验加深下理解,不少初学者在运行应用的时候都遇到的关于SA和SCC的问题。我将先部署一个简单的应用作为测试环境。我使用的是openshift 3.9
部署应用
我使用的是busybox,一个轻量级的工具镜像,尤其在测试网络连通性的时候非常有用。
- 使用镜像进行部署
oc new-app --docker-image=docker.io/busybox --name=busybox923
- 修改DC yaml文件的启动命令,因为busybox默认是以bash启动,会一直重启,我将它改为sleep
spec:
containers:
- image: 'docker.io/busybox:latest'
command:
- sleep
- 30d
- 查看pod状态已经正常运行了
# oc get pod
NAME READY STATUS RESTARTS AGE
busybox923-3-qk7hj 1/1 Running 0 17m
分析现在busybox相关内容
- 查看busybox的DC yaml文件,截取相关内容
# oc get dc/busybox923 -o yaml
apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
...
spec:
...
template:
metadata:
annotations:
openshift.io/generated-by: OpenShiftNewApp
creationTimestamp: null
labels:
app: busybox923
deploymentconfig: busybox923
spec:
containers:
- command:
- sleep
- 30d
image: docker.io/busybox:latest
imagePullPolicy: IfNotPresent
name: busybox923
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
...
- 查看busybox的pod yaml文件,截取相关内容
# oc get pod busybox923-3-qk7hj -o yaml
apiVersion: v1
kind: Pod
····
name: busybox923-3-qk7hj
namespace: default
···
spec:
containers:
- command:
- sleep
- 30d
image: docker.io/busybox:latest
imagePullPolicy: IfNotPresent
name: busybox923
resources: {}
securityContext:
capabilities:
drop:
- KILL
- MKNOD
- SETGID
- SETUID
runAsUser: 1000000000
···
securityContext:
fsGroup: 1000000000
seLinuxOptions:
level: s0:c1,c0
serviceAccount: default
serviceAccountName: default
···
- 查看pod运行的用户
# oc rsh busybox923-3-qk7hj
/ $ whoami
whoami: unknown uid 1000000000
- 分析:可以看到DC关于是没有定于关于sa与sc的配置,而pod则定义了使用default的serviceAccount,并在securityContext定义了runAsUser: 1000000000(查看container字段的securityContext,并且进入busybox的pod看到的用户id为1000000000,这些都是openshift的默认参数,这个时候在容器以非root权限启动时去访问须有root权限时容易报错。
- 试着在DC内添加runAsUser: 1000000000为0,0即root
# oc get pod
NAME READY STATUS RESTARTS AGE
busybox923-5-bm5t7 1/1 Running 0 1m
busybox923-6-deploy 1/1 Running 0 22s
- 一直无法生产新的pod,即版本6的pod,查看下deploy pod的日志
# oc log busybox923-6-deploy
W1026 10:12:37.477358 36823 cmd.go:358] log is DEPRECATED and will be removed in a future version. Use logs instead.
--> Scaling up busybox923-6 from 0 to 1, scaling down busybox923-5 from 1 to 0 (keep 1 pods available, don't exceed 2 pods)
Scaling busybox923-6 up to 1
- 因此将DC给runAsUser给删了就可以了
# oc get pod
NAME READY STATUS RESTARTS AGE
busybox923-5-bm5t7 1/1 Terminating 0 4m
busybox923-6-deploy 0/1 Terminating 0 3m
busybox923-7-deploy 1/1 Running 0 9s
busybox923-7-qtnvn 1/1 Running 0 5s
SA、SCC、SC介绍及使用
SA是用来定义 pod 启动时的用户,注意这个用户不是指 pod 容器里头的Linux用户,只是这个pod能干什么的用户;SCC就是具体的权限角色了,需要将SCC的角色分配给SA用户,系统默认就定义好了很多SCC,我们直接拿来用就可以了;而SC就是分配好,管理员再在pod定义具体使用那些权限的。
- 查看系统默认的SCC,常用的是privileged,它能够以root用户运行,并且访问宿主机上的文件系统
# oc get scc
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP PRIORITY READONLYROOTFS VOLUMES
anyuid false [] MustRunAs RunAsAny RunAsAny RunAsAny 10 false [configMap downwardAPI emptyDir persistentVolumeClaim projected secret]
hostaccess false [] MustRunAs MustRunAsRange MustRunAs RunAsAny <none> false [configMap downwardAPI emptyDir hostPath persistentVolumeClaim projected secret]
hostmount-anyuid false [] MustRunAs RunAsAny RunAsAny RunAsAny <none> false [configMap downwardAPI emptyDir hostPath nfs persistentVolumeClaim projected secret]
hostnetwork false [] MustRunAs MustRunAsRange MustRunAs MustRunAs <none> false [configMap downwardAPI emptyDir persistentVolumeClaim projected secret]
nonroot false [] MustRunAs MustRunAsNonRoot RunAsAny RunAsAny <none> false [configMap downwardAPI emptyDir persistentVolumeClaim projected secret]
privileged true [*] RunAsAny RunAsAny RunAsAny RunAsAny <none> false [*]
restricted false [] MustRunAs MustRunAsRange MustRunAs RunAsAny <none> false [configMap downwardAPI emptyDir persistentVolumeClaim projected secret]
- 我部署的应用是在default这个project下面,每个项目都有default这个sa,注意在页面上是看不到default这个sa的。
# oc get sa
NAME SECRETS AGE
builder 2 131d
default 3 131d
deployer 2 131d
registry 3 131d
router 2 131d
- 现在我给default这个sa分配privileged的权限
# oc adm policy add-scc-to-user privileged -z default
scc "privileged" added to: ["system:serviceaccount:default:default"]
- 把pod杀了,让它自动新建一个,登录进pod的uid还是不变,并且dc和pod的yaml文件关于sa和sc字段还是不变。
- 在dc的container字段内添加sc配置 privileged: true
containers:
- command:
- sleep
- 30d
image: docker.io/busybox:latest
imagePullPolicy: IfNotPresent
name: busybox923
resources: {}
securityContext:
capabilities: {}
privileged: true
- 查看pod的yaml文件,默认定义在securityContext字段的参数变了
spec:
containers:
- command:
- sleep
- 30d
image: docker.io/busybox:latest
imagePullPolicy: IfNotPresent
name: busybox923
resources: {}
securityContext:
capabilities: {}
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-xthkz
readOnly: true
dnsPolicy: ClusterFirst
imagePullSecrets:
- name: default-dockercfg-6h8bz
nodeName: local2-ocp3.9-node1-test.com
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
- 查看pod运行的用户,这时候为root了
# oc rsh busybox923-8-59hvm
/ # whoami
root
- 试着将privileged: true参数定义在外面的securityContext,而不是container字段内定义,试了一下不会生效,还是为securityContext: {};接下来的测试都不在外面的securityContext测试了,默认都在container字段内测试。
- 将privileged: true修改为自定义的用户id,如:runAsUser: 123,忽然发现使用id命令也能看到当前用户属于哪个组,可以看到属于root组。
# oc rsh busybox923-10-p69mg
/ $ whoami
whoami: unknown uid 123
/ $ id
uid=123 gid=0(root)
- 将securityContext全部删除,测试下是id命令的结果,多了个groups。
# oc rsh busybox923-11-tblhh
/ $ id
uid=1000000000 gid=0(root) groups=1000000000
- 配置securityContext的runAsUser为0,查看pod的用户id 为root
# oc rsh busybox923-12-cq5qt
/ # id
uid=0(root) gid=0(root) groups=10(wheel)
- 测试未在DC的yaml文件中配置 privileged: true 权限下挂载宿主机的docker可执行文件及docker配置文件
spec:
containers:
- command:
- sleep
- 30d
...
volumeMounts:
- mountPath: /usr/bin/docker
name: docker
- mountPath: /etc/sysconfig/docker
name: docker-config
...
securityContext: {}
...
volumes:
- hostPath:
path: /usr/bin/docker
type: ''
name: docker
- hostPath:
path: /etc/sysconfig/docker
type: ''
name: docker-config
- 进入pod,可以看到是root用户,并且docker文件已经挂载进来了
# oc rsh busybox923-17-vb94f
/ # id
/ # ls -l /etc/sysconfig/docker
-rw-r--r-- 1 root root 1243 Mar 19 2018 /etc/sysconfig/docker
uid=0(root) gid=0(root) groups=10(wheel)
/ # ls -l /usr/bin/docker
-rwxr-xr-x 1 root root 735 Mar 19 2018 /usr/bin/docker
- 我也看了dc及pod的yaml文件,都没有关于sc的定义,所以应该是在使用宿主机volume的时候就开启了privileged: true
- 给sa分配scc为privileged权限很大了,在有些时候只需要分配让pod以root用户启动即可,即修改privileged为anyuid
oc adm policy remove-scc-from-user privileged -z default
oc adm policy add-scc-to-user anyuid -z default
- 这时候删除pod,不会启动新的pod,怀疑目前因为挂载的宿主机的volume,并且因为scc权限低,所以pod无法创建,所以在dc内删除volume相关的配置,触发新的部署,新pod就被创建了,我再次将volume的配置添加进dc,查看一下,虽然新的部署被触发,但是新的pod没有被创建,说明在没有足够大的权限下,pod无法创建。
[root@local2-ocp3.9-master1-test.com ~]# oc get pod
NAME READY STATUS RESTARTS AGE
busybox923-21-cktj5 1/1 Running 0 2m
busybox923-22-deploy 1/1 Running 0 10s
- 再次将volume相关配置删除,触发新的部署,进入pod看下用户为root
# oc rsh busybox923-23-nmk7h
/ # id
uid=0(root) gid=0(root) groups=10(wheel)
/ # whoami
root
创建新的sa,并且使用它
- 前面pod启动时,使用的是project 默认的default sa,我们可以自己新建一个作为测试
# oc create sa busybox
serviceaccount "busybox" created
- 在DC内定义使用busybox这个sa去启动
serviceAccount: busybox
serviceAccountName: busybox
- 进入pod,用户跟sa 为 default时没差
# oc rsh busybox923-24-l5szd
/ $ id
uid=1000000000 gid=0(root) groups=1000000000
/ $ whoami
whoami: unknown uid 1000000000
- 给busybox分配scc为anyuid进行测试,用户为root
# oc adm policy add-scc-to-user anyuid -z busybox
scc "anyuid" added to: ["system:serviceaccount:default:busybox"]
# oc rsh busybox923-24-fjkrb
/ # id
uid=0(root) gid=0(root) groups=10(wheel)
/ # whoami
root
总结
以上只是对sa、scc、sc常用的一些配置使用做了测试和介绍,更深入和灵活的用法还需在具体环境及需求中进行测试验证,openshift/kubernetes是很强大很复杂的一个系统,还需多深入研究。