验证kubernetes的pod安全策略
最近有客户提出需要对业务集群的pod做安全限制,不允许使用pod拥有privileged的权限,研究一番,刚好k8s的Pod Security Policies可以实现该需求。
什么是pod安全策略
Pod Security Policy(简称psp)是集群级别的资源,该资源控制pod的spec中安全相关的方面,具体的方面参考下表:
Control Aspect | Field Names |
---|---|
Running of privileged containers | privileged |
Usage of host namespaces | hostPID, hostIPC |
Usage of host networking and ports | hostNetwork, hostPorts |
Usage of volume types | volumes |
Usage of the host filesystem | allowedHostPaths |
White list of Flexvolume drivers | allowedFlexVolumes |
Allocating an FSGroup that owns the pod’s volumes | fsGroup |
Requiring the use of a read only root file system | readOnlyRootFilesystem |
The user and group IDs of the container | runAsUser, runAsGroup, supplementalGroups |
The SELinux context of the container | seLinux |
如何开启Pod Security Policy
- Enable API extensions
For Kubernetes < 1.6.0, the API Server must enable the extensions/v1beta1/podsecuritypolicy API extensions group (–runtime-config=extensions/v1beta1/podsecuritypolicy=true).
- Enable PodSecurityPolicy admission control policy
The following parameter needs to be added to the API server startup argument: –admission-control=PodSecurityPolicy
默认psp是不开启的,若要开启,需要配置上述apiserver启动参数,默认的apiserver的yaml文件为/etc/kubernetes/manifests/kube-apiserver.yaml
...
spec:
containers:
- command:
- kube-apiserver
- --authorization-mode=Node,RBAC
- --enable-admission-plugins=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,ResourceQuota,PodSecurityPolicy
- --runtime-config=extensions/v1beta1/podsecuritypolicy=true
...
配置默认的psp
由于已有打开了pod创建的安全策略,但此时还未创建任何的policy,所以任何pod都无法被创建,此时如果尝试去创建一个pod,会发现pod无法进行调度,
[root@build-master apiserver]# kubectl run --image=nginx yxli
deployment.apps/yxli created
[root@build-master apiserver]# kubectl get deploy yxli
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
yxli 1 0 0 0 4m
查看controller的日志会发现报错forbidden: no providers available to validate pod request
[root@build-master ~]# kubectl logs --tail=10 -f kube-controller-manager-build-master -n kube-system
E0318 03:01:17.321184 1 replica_set.go:450] Sync "default/yxli-6978dddc9d" failed with pods "yxli-6978dddc9d-" is forbidden: no providers available to validate pod request
I0318 03:01:17.321302 1 event.go:221] Event(v1.ObjectReference{Kind:"ReplicaSet", Namespace:"default", Name:"yxli-6978dddc9d", UID:"0d11050f-492a-11e9-8ef0-00163e004fd2", APIVersion:"apps/v1", ResourceVersion:"764927", FieldPath:""}): type: 'Warning' reason: 'FailedCreate' Error creating: pods "yxli-6978dddc9d-" is forbidden: no providers available to validate pod request
E0318 03:01:37.807060 1 replica_set.go:450] Sync "default/yxli-6978dddc9d" failed with pods "yxli-6978dddc9d-" is forbidden: no providers available to validate pod request
I0318 03:01:37.807046 1 event.go:221] Event(v1.ObjectReference{Kind:"ReplicaSet", Namespace:"default", Name:"yxli-6978dddc9d", UID:"0d11050f-492a-11e9-8ef0-00163e004fd2", APIVersion:"apps/v1", ResourceVersion:"764927", FieldPath:""}): type: 'Warning' reason: 'FailedCreate' Error creating: pods "yxli-6978dddc9d-" is forbidden: no providers available to validate pod request
E0318 03:02:18.773092 1 replica_set.go:450] Sync "default/yxli-6978dddc9d" failed with pods "yxli-6978dddc9d-" is forbidden: no providers available to validate pod request
而由于我们修改了apiserver的参数,pod受kubelet管理,自动触发了重建,此时apiserver的pod也是因为缺少权限没法创建出来
[root@build-master apiserver]# journalctl -fu kubelet
-- Logs begin at Tue 2019-03-12 20:33:59 CST. --
Mar 18 11:25:29 build-master kubelet[4013]: E0318 11:25:29.016416 4013 kubelet.go:1594] Failed creating a mirror pod for "kube-apiserver-build-master_kube-system(77a7d13c654e7233306d4e2948aaaa78)": pods "kube-apiserver-build-master" is forbidden: no providers available to validate pod request
Mar 18 11:25:30 build-master kubelet[4013]: W0318 11:25:30.113587 4013 kubelet.go:1579] Deleting mirror pod "kube-apiserver-build-master_kube-system(e48d84cd-46f0-11e9-8ef0-00163e004fd2)" because it is outdated
Mar 18 11:25:30 build-master kubelet[4013]: E0318 11:25:30.117242 4013 kubelet.go:1594] Failed creating a mirror pod for "kube-apiserver-build-master_kube-system(77a7d13c654e7233306d4e2948aaaa78)": pods "kube-apiserver-build-master" is forbidden: no providers available to validate pod request
所以我们需要创建一个policy,为我们需要的受kubelet管理的静态pod以及kube-system命名空间下的pod提供权限,否则pod一旦发生重建,都将因为缺少权限导致无法正常创建出来。
首先新建文件 privileged.policy.yaml,权限不受限制,
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: privileged
spec:
allowedCapabilities:
- '*'
allowPrivilegeEscalation: true
fsGroup:
rule: 'RunAsAny'
hostIPC: true
hostNetwork: true
hostPID: true
hostPorts:
- min: 0
max: 65535
privileged: true
readOnlyRootFilesystem: false
runAsUser:
rule: 'RunAsAny'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
volumes:
- '*'
创建并查看该policy
[root@build-master apiserver]# kubectl create -f privileged.policy.yaml
podsecuritypolicy.policy/privileged created
[root@build-master apiserver]# kubectl get psp
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP READONLYROOTFS VOLUMES
privileged true * RunAsAny RunAsAny RunAsAny RunAsAny false *
然后还需要创建一个clusterrole,并且赋予该role对上述psp对使用权
# Cluster role which grants access to the privileged pod security policy
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: privileged-psp
rules:
- apiGroups:
- policy
resourceNames:
- privileged
resources:
- podsecuritypolicies
verbs:
- use
然后把clusterrole赋予serviceaccount或者对应的user、group,针对kube-system命名空间下的pod来说,都使用了kube-system下的serviceaccount或者由kubelet管理,kubelet是使用system:nodes这个组来管理的pod,所以只需要做如下binding即可为kube-system下的所有pod提供权限,
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kube-system-psp
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: privileged-psp
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:nodes
namespace: kube-system
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:serviceaccounts:kube-system
都创建好之后,查看kube-system下的pod,发现apiserver已经创建成功
[root@build-master apiserver]# kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-68f5b48ccb-9hjvr 1/1 Running 0 5d
coredns-68f5b48ccb-qrjnr 1/1 Running 0 5d
etcd-build-master 1/1 Running 0 5d
kube-apiserver-build-master 1/1 Running 0 18s
上面的binding只是为kube-system空间赋予了权限,若想要为别的命名空间赋予权限,可以使用ClusterRoleBinding的方式为多个namespace绑定privileged-psp的clusterrole,或者像如下方式,为所有合法的serviceaccounts和user绑定权限,当然前提是pod使用了namespace下的serviceAccount
# Authorize all service accounts in a namespace:
- kind: Group
apiGroup: rbac.authorization.k8s.io
name: system:serviceaccounts
# Or equivalently, all authenticated users in a namespace:
- kind: Group
apiGroup: rbac.authorization.k8s.io
name: system:authenticated
验证psp的privileged限制
该章节会创建一个名为psp-namespace的namespace做测试,来验证psp中对privileged的pod的限制
[root@build-master apiserver]# kubectl create namespace psp-example
namespace/psp-example created
[root@build-master apiserver]# kubectl create serviceaccount fake-user -n psp-example
serviceaccount/fake-user created
[root@build-master apiserver]# kubectl run --image=nginx psp-pod-nginx-1 -n psp-example --serviceaccount=fake-user
deployment.apps/psp-pod-nginx-1 created
[root@build-master apiserver]# kubectl get po -n psp-example
No resources found.
[root@build-master apiserver]# kubectl get deploy -n psp-example
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
psp-pod-nginx-1 1 0 0 0 23s
如上所示,新的psp-example命名空间由于没有任何权限,所以无法创建新pod,接下来我们创建一个policy并给psp-example做authorize,但是policy中会限制无法创建privileged的pod
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: example
spec:
privileged: false # Don't allow privileged pods!
# The rest fills in some required fields.
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
volumes:
- '*'
然后创建role和rolebinding,并验证fake-user是否有权限使用example的policy
[root@build-master psp-example]# kubectl -n psp-example create role psp:unprivileged --verb=use --resource=podsecuritypolicy --resource-name=example
role.rbac.authorization.k8s.io/psp:unprivileged created
[root@build-master psp-example]# kubectl -n psp-example create rolebinding fake-user:psp:unprivileged --role=psp:unprivileged --serviceaccount=psp-example:fake-user
rolebinding.rbac.authorization.k8s.io/fake-user:psp:unprivileged created
[root@build-master psp-example]# kubectl --as=system:serviceaccount:psp-example:fake-user -n psp-example auth can-i use podsecuritypolicy/example
yes
等待片刻,再次查看刚才创建的deploy,发现已经调度成功
[root@build-master psp-example]# kubectl get deploy -n psp-example psp-pod-nginx-1
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
psp-pod-nginx-1 1 1 1 1 22m
此时我们尝试在psp-example下创建一个privileged的特权容器,
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
run: psp-pod-nginx-privileged
name: psp-pod-nginx-privileged
namespace: psp-example
spec:
selector:
matchLabels:
run: psp-pod-nginx-privileged
template:
metadata:
labels:
run: psp-pod-nginx-privileged
spec:
containers:
- image: nginx
imagePullPolicy: Always
name: psp-pod-nginx-privileged
securityContext:
privileged: true
serviceAccount: fake-user
创建并查看结果
[root@build-master psp-example]# kubectl create -f privileged-pod.yaml
deployment.extensions/psp-pod-nginx-privileged created
[root@build-master psp-example]# kubectl get deploy -n psp-example psp-pod-nginx-privileged
psp-pod-nginx-privileged 1 0 0 0 24s
[root@build-master ~]# kubectl logs --tail=1 -f kube-controller-manager-build-master -n kube-system
I0318 04:32:42.777200 1 event.go:221] Event(v1.ObjectReference{Kind:"ReplicaSet", Namespace:"psp-example", Name:"psp-pod-nginx-privileged-d7f8dbd75", UID:"c66fb10f-4936-11e9-9c58-00163e004fd2", APIVersion:"apps/v1", ResourceVersion:"773292", FieldPath:""}): type: 'Warning' reason: 'FailedCreate' Error creating: pods "psp-pod-nginx-privileged-d7f8dbd75-" is forbidden: unable to validate against any pod security policy: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]
查看controller-manager的日志,发现Privileged containers are not allowed