系列目录html
pod安全策略是集群级别的用于控制pod安全相关选项的一种资源.PodSecurityPolicy
定义了一系列pod相要进行在系统中必须知足的约束条件,以衣一些默认的约束值.它容许管理员控制如下方面内容node
Control Aspect | Field Names |
---|---|
以特权运行容器 | privileged |
使用宿主名称空间 | hostPID, hostIPC |
使用宿主网络和端口 | hostNetwork, hostPorts |
使用存储卷类型 | volumes |
使用宿主机文件系统 | allowedHostPaths |
flex存储卷白名单 | allowedFlexVolumes |
分配拥有 Pod 数据卷的 FSGroup | fsGroup |
只读root文件系统 | readOnlyRootFilesystem |
容器的用户id和组id | runAsUser, runAsGroup, supplementalGroups |
禁止提高到root权限 | allowPrivilegeEscalation, defaultAllowPrivilegeEscalation |
Linux能力 | defaultAddCapabilities, requiredDropCapabilities, allowedCapabilities |
SELinux上下文 | seLinux |
容许容器加载的proc类型 | allowedProcMountTypes |
The AppArmor profile used by containers | annotations |
The seccomp profile used by containers | annotations |
The sysctl profile used by containers | annotations |
pod安全策略做为可选的(但强烈建议的)admission controller的实现.pod安全策略经过启用admission controller来实现,可是仅仅启用而没有对策略受权则会致使整个集群没法建立pod!docker
因为pod安全策略api(policy/v1beta1/podsecuritypolicy)独立于admission controller
以外启用,对于已经存在的集群建议在启用admission controller
以前添加并受权策略.api
当一个pod安全策略资源被建立(前面说过,psp(PodSecurityPolicy )pod安全策略是一种kubernetes资源),它什么都不会作.为了使用它,请求操做的用户或者目标pod的serviceaccount必须经过策略的use
动词来受权.安全
绝大部分kubernetes pod并非直接由用户直接建立的.相反,典型使用场景是它们经过Deployment
或者ReplicaSet
间接被建立,或者经过控制器管理器的其它模板控制器来建立.对控制器进行策略受权也将对它所建立的全部pod进行策略受权.所以首选的受权方法是对pod的serviceaccount进行策略受权(后面有示例).bash
RBAC是kubernetes标准的受权模式,而且很容易用于受权安全策略使用.网络
首先,一个角色(role)或者集群角色(clusterRole)须要被受权使用(use动词)
它想要的策略.对角色的受权相似下面app
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: <role name> rules: - apiGroups: ['policy'] resources: ['podsecuritypolicies'] verbs: ['use'] resourceNames: - 一系列要进行受权的资源名称
而后把集群角色(或角色)与受权的用户绑定ide
kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: 绑定名称 roleRef: kind: ClusterRole name: 角色名称 apiGroup: rbac.authorization.k8s.io subjects: # Authorize specific service accounts: - kind: ServiceAccount name: 受权的serviceaccount名称 namespace: <authorized pod namespace> # Authorize specific users (not recommended): - kind: User apiGroup: rbac.authorization.k8s.io name: 受权的用户名
若是一个角色绑定(不是集群角色绑定)被使用,它仅对和它处于同一名称空间下的pod才能进行有效策略受权,这样一样适用于用户和用户组工具
# 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
故障排除
控制器管理器必须运行在安全的api端口上,而且不能有超级权限.否则请求就会绕过认证和受权模块,将致使全部的策略均被容许,而且用户能够建立特权pod
除了限制pod的建立和更新,pod安全策略还用于提供它所控制的诸多字段的默认值.当有多个策略时,pod安全策略根据如下因素来选择策略
任何成功经过验证没有警告的策略将被使用
若是是请求建立pod,则按经过验证的策略按字母表顺序被选用
不然,若是是一个更新请求,将会返回错误.由于在更新操做过程当中不容许pod变化
如下示例假定你运行的集群开启了pod安全策略admission controller而且你有集群管理员权限
咱们为示例建立一个名称空间和一个serviceaccount.咱们使用这个serviceaccount来模拟一个非管理员用户
kubectl create namespace psp-example kubectl create serviceaccount -n psp-example fake-user kubectl create rolebinding -n psp-example fake-editor --clusterrole=edit --serviceaccount=psp-example:fake-user
为了方便辨认咱们使用的帐户,咱们建立两个别名
alias kubectl-admin='kubectl -n psp-example' alias kubectl-user='kubectl --as=system:serviceaccount:psp-example:fake-user -n psp-example'
如下定义文件定义了一个简单pod安全策略(PodSecurityPolicy),这个策略仅仅阻止建立特权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: - '*'
咱们使用kubectl命令来应用以上文件.
如今,作为一个非特权用户,咱们建立一个简单pod
kubectl-user create -f- <<EOF apiVersion: v1 kind: Pod metadata: name: pause spec: containers: - name: pause image: k8s.gcr.io/pause EOF Error from server (Forbidden): error when creating "STDIN": pods "pause" is forbidden: unable to validate against any pod security policy: []
发生了什么?尽管pod安全策略已建立,不论是pod的serviceaccount仍是fack-user都没有权限使用这个策略.
kubectl-user auth can-i use podsecuritypolicy/example no
建立一个rolebing
来受权fake-user
来使用example
策略(example是前面建立的策略的名称)
可是请注意这里并非首选方式!后面的示例将介绍首选的方式
kubectl-admin create role psp:unprivileged \ --verb=use \ --resource=podsecuritypolicy \ --resource-name=example role "psp:unprivileged" created kubectl-admin create rolebinding fake-user:psp:unprivileged \ --role=psp:unprivileged \ --serviceaccount=psp-example:fake-user rolebinding "fake-user:psp:unprivileged" created kubectl-user auth can-i use podsecuritypolicy/example yes
此时,再从新尝试建立pod
kubectl-user create -f- <<EOF apiVersion: v1 kind: Pod metadata: name: pause spec: containers: - name: pause image: k8s.gcr.io/pause EOF pod "pause" created
此次正如咱们期待的同样,能够正常工做.可是试图建立特权pod仍然会被阻止(所以策略自己阻止建立特权pod)
kubectl-user create -f- <<EOF apiVersion: v1 kind: Pod metadata: name: privileged spec: containers: - name: pause image: k8s.gcr.io/pause securityContext: privileged: true EOF Error from server (Forbidden): error when creating "STDIN": pods "privileged" is forbidden: unable to validate against any pod security policy: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]
咱们再尝试建立一个pod,此次有一点不一样
ubectl-user run pause --image=k8s.gcr.io/pause deployment "pause" created kubectl-user get pods No resources found. kubectl-user get events | head -n 2 LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON SOURCE MESSAGE 1m 2m 15 pause-7774d79b5 ReplicaSet Warning FailedCreate replicaset-controller Error creating: pods "pause-7774d79b5-" is forbidden: no providers available to validate pod request
从以上能够看到deployment已经成功建立(kubectl run 实际上会建立一个deployment).可是使用kubectl get pod
命令却没有发现pod被建立.这是为何?问题的答案隐藏在replicaset控制器里.Fake-user
成功建立的deployment(deployment又成功建立replicaset),可是当replicaset尝试建立pod的时候,它并无被受权使用example
定义的策略.
为了解决这个问题,须要把psp:unprivileged
角色(前面建立的)绑定到pod的serviceaccount上(前面咱们是绑定在了fake-user上).这里serviceaccount是default
(由于咱们没有指定其它用户)
看到这里若是你仍然以为难以理解,能够回头再看看,仍是没法理解的话则须要补充关于角色,用户和RBAC相关的知识.
kubectl-admin create rolebinding default:psp:unprivileged \ --role=psp:unprivileged \ --serviceaccount=psp-example:default rolebinding "default:psp:unprivileged" created
这时候等待若干分钟,replicaset的控制器最终会成功建立pod
kubectl-user get pods --watch NAME READY STATUS RESTARTS AGE pause-7774d79b5-qrgcb 0/1 Pending 0 1s pause-7774d79b5-qrgcb 0/1 Pending 0 1s pause-7774d79b5-qrgcb 0/1 ContainerCreating 0 1s pause-7774d79b5-qrgcb 1/1 Running 0 2s
删除名称空间以删除绝大部分示例中用到的资源
kubectl-admin delete ns psp-example namespace "psp-example" deleted
注意如今刚刚建立的pod安全策略已经没有了名称空间,而且须要单独被清除
kubectl-admin delete psp example podsecuritypolicy "example" deleted
如下是一个最小限制的策略,和不使用pod安生策略admission controller效果同样
apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: name: privileged annotations: seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*' spec: privileged: true allowPrivilegeEscalation: true allowedCapabilities: - '*' volumes: - '*' hostNetwork: true hostPorts: - min: 0 max: 65535 hostIPC: true hostPID: true runAsUser: rule: 'RunAsAny' seLinux: rule: 'RunAsAny' supplementalGroups: rule: 'RunAsAny' fsGroup: rule: 'RunAsAny'
如下的一个示例有限制性策略,须要用户是一个非特权用户,阻止pod的权限提高
之因此要求是非特权用户,由于特权用户将会绕过限制
apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: name: restricted annotations: seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default' apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default' seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default' apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default' spec: privileged: false # Required to prevent escalations to root. allowPrivilegeEscalation: false # This is redundant with non-root + disallow privilege escalation, # but we can provide it for defense in depth. requiredDropCapabilities: - ALL # Allow core volume types. volumes: - 'configMap' - 'emptyDir' - 'projected' - 'secret' - 'downwardAPI' # Assume that persistentVolumes set up by the cluster admin are safe to use. - 'persistentVolumeClaim' hostNetwork: false hostIPC: false hostPID: false runAsUser: # Require the container to run without root privileges. rule: 'MustRunAsNonRoot' seLinux: # This policy assumes the nodes are using AppArmor rather than SELinux. rule: 'RunAsAny' supplementalGroups: rule: 'MustRunAs' ranges: # Forbid adding the root group. - min: 1 max: 65535 fsGroup: rule: 'MustRunAs' ranges: # Forbid adding the root group. - min: 1 max: 65535 readOnlyRootFilesystem: false
它决定了pod中的全部容器是否被容许以特权方式运行.默认状况下容器不容许访问主机的设备,可是特权容器却被容许访问.这将容许容器有几乎和它所在的进程同样的访问主机的权利.这将很是有用当容器想要使用主机的功能,好比访问网络的设备.
HostPID
- 控制容器是否能够共享主机的进程id名称空间
HostIPC
- 控制容器是否能够共享主机的IPC名称空间
HostNetwork
- 控制容器是否可使用所在节点的网络名称空间.这将容许pod访问回环设备,监听localhost,而且能够窥探同一节点上其它pod的网络活动情况
AllowedHostPaths - 控制容许访问的宿主机路径
Volumes
- 提供了一系列的存储卷类型白名单.这些容许的值和建立存储卷时定义的资源类型相对应.想要获取全部存储卷类型,能够查看存储卷类型列表.此外,*
能够被用来容许全部的存储卷类型
如下是推荐的最小化的容许存储卷类型的安全策略配置
AllowedHostPaths
- 它定义了一个hostPath
类型的存储卷可用的宿主机路径的白名单.空集群意味着对宿主机的path无使用限制.它被定义为一个包含了一系列对象的单个pathPrefix
字段,容许hostpath类型的存储卷挂载以pathPrefix
字段开头的宿主机路径.readonly
字段意味着必须以readonly
方式挂载(即不能写入,只能读)
allowedHostPaths: # This allows "/foo", "/foo/", "/foo/bar" etc., but # disallows "/fool", "/etc/foo" etc. # "/foo/../" is never valid. - pathPrefix: "/foo" readOnly: true # only allow read-only mounts
警告,一个能够无限制访问宿主机文件系统的容器能够有不少方式提高权限,包括读取其它容器内的数据,滥用系统服务的密钥,好比kubecctl
可写的hostpath目录存储卷容许容器写入到宿主机文件系统,而且能够遍历
pathPrefix
之外的文件系统,readOnly: true
在kubernetes 1.11+版本之后才能使用,而且在allowedHostPaths
必须使用以有效限制访问特定的pathPrefix
ReadOnlyRootFilesystem
- 限制容器必须以只读的root文件系统运行(没有可写层)
这个选项控制着容器的allowPrivilegeEscalation
选项.这个布尔值直接控制着no_new_privs
是否设置到容器运行的进程.它将阻止setuid
来改变user ID,而且阻止文件有其它的能力(好比禁止使用ping工具).这个行为须要启用MustRunAsNonRoot
AllowPrivilegeEscalation
- 它决定着容器的安全上下文是否能够设置allowPrivilegeEscalation=true
,为true是默认值.设置为false将使得容器全部的子进程没有比父进程更高的特权
DefaultAllowPrivilegeEscalation
,为allowPrivilegeEscalation
设置默认值,从上面能够看到,默认的值为true.若是这个行为不是咱们期待的,这个字段能够用于把它设置为不容许,可是仍然pod显式请求allowPrivilegeEscalation