简介
因为有时候对 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是很强大很复杂的一个系统,还需多深入研究。




