默认情况下,Kubernetes 允许创建一个有特权容器的 Pod,这些容器很可能会危机系统安全,而 Pod 安全策略(PSP)则通过确保请求者有权限按配置来创建 Pod,从而来保护集群免受特权 Pod 的影响。
为了更精细地控制Pod对资源的使用方式,Kubernetes从1.4版本开始引入了PodSecurityPolicy资源对象对Pod的安全策略进行管理。
PodSecurityPolicy 是 Kubernetes API 对象,你可以在不对 Kubernetes 进行任何修改的情况下创建它们,但是,默认情况下不会强制执行我们创建的一些策略,我们需要一个准入控制器、kube-controller-manager 配置以及 RBAC 权限配置。
PodSecurityPolicy 类型的对象能够控制,是否可以向 Pod 发送请求,该 Pod 能够影响被应用到 Pod 和容器的 SecurityContext。
Pod 安全策略 是集群级别的资源,它能够控制 Pod 运行的行为,以及它具有访问什么的能力。 PodSecurityPolicy 对象定义了一组Pod运行时必须遵循的条件及相关字段的默认值,只有 Pod 满足这些条件才会被系统接受。 它们允许管理员控制如下方面:
控制面 | 字段名称 |
---|---|
特权容器 | privileged |
使用宿主名字空间 | hostPID,hostIPC |
使用宿主的网络和端口 | hostNetwork,hostPorts |
控制卷类型的使用 | wolumes |
使用宿主文件系统 | allowHostPaths |
允许使用特定的FlesVolume驱动 | allowFlexVolumes |
分配拥有Pod卷的FSGroup | fsGroup |
以只读的方式访问根文件系统 | readOnlyRootFilesystem |
设置容器的用户和组ID | runAsUser,runAsGroup,supplementalGroups |
限制root账号特提升 | allowPrivilegeEscalation,defaultAllowPrivateEscalation |
设置容器的 SELinux 上下文 | seLinux |
指定容器可以挂载的proc类型 | alloweProcMountTypes |
指定容器使用的AppArmor模板 | annotations |
指定容器使用的seccomp | annotations |
指定容器使用的sysctl模板 | forbiddenSysctls,allowedUnsafeSysctls |
Pod 安全策略 由设置和策略组成,它们能够控制 Pod 访问的安全特征。这些设置分为如下三类:
包含 PodSecurityPolicy 的 许可控制,允许控制集群资源的创建和修改,基于这些资源在集群范围内被许可的能力。
许可使用如下的方式为 Pod 创建最终的安全上下文:
如果某个策略能够匹配上,该 Pod 就被接受。如果请求与 PSP 不匹配,则 Pod 被拒绝。
Pod 必须基于 PSP 验证每个字段。
如果需要开启PodSecurityPolicy,需要在kube-apiserver的启动参数中设置如下参数
--enable-admission-plugins=PodSecurityPolicy
在开启PodSecurityPolicy准入控制器后,k8s默认不允许创建任何Pod,需要创建PodSecurityPolicy和RBAC授权策略,Pod才能创建成功。
注:修改kube-apiserver配置文件/etc/kubernetes/manifests/kube-apiserver.yaml,由于是static
pod,所以修改就会生效。
系统默认此参数为:
--enable-admission-plugins=NodeRestriction
创建PodSecurityPolicy对象之后,就可以成功创建pod资源了
下列PodSecurityPolicy表示是不允许创建特权模式的Pod
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: psp-non-privileged
spec:
privileged: false #不允许特权模式的Pod
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
volumes:
- '*'
获取已存在策略列表,使用 kubectl get:
$ kubectl get psp
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP READONLYROOTFS VOLUMES
permissive false [] RunAsAny RunAsAny RunAsAny RunAsAny false [*]
privileged true [] RunAsAny RunAsAny RunAsAny RunAsAny false [*]
restricted false [] RunAsAny MustRunAsNonRoot RunAsAny RunAsAny false [emptyDir secret downwardAPI configMap persistentVolumeClaim projected]
通过交互方式修改策略,使用 kubectl edit:
$ kubectl edit psp permissive
该命令将打开一个默认文本编辑器,在这里能够修改策略。
一旦不再需要一个策略,很容易通过 kubectl 删除它:
$ kubectl delete psp permissive
podsecuritypolicy "permissive" deleted
上面的PodSecurytiPolicy是设置了不允许创建特权模式的Pod,例如,在下面的YAML配置文件pod-privileged.yaml中为Pod设置了特权模式:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
securityContext:
privileged: true
创建的时候会报如下错误:
unable to validate against any pod security policy
在PodSecurityPolicy对象中可以设置下列字段来控制Pod运行时的各种安全策略
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: all-hostpath-volumes
spec:
volumes:
- hostPath
allowedHostPaths:
- pathPrefix: "/foo"
readOnly: true
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: allowedflexvolumes
spec:
volumes:
- flexVolume
allowedFlexVolumes:
- driver: example/lvm
- driver: example/cifs
1.基本没有限制的安全策略,允许创建任意安全设置的Pod。
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: privileged
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: "*"
spec:
privileged: true #不允许创建特权模式的Pod
allowPrivilegeEscalation: true #设置子进程是否可以提升权限,配置MustRunAsNonRoot
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'
2.要求Pod运行用户为非特权用户;禁止提升权限;不允许使用宿主机网络、端口号、IPC等资源;限制可以使用的Volume类型,等等
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: retricted
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
seccomp.security.alpha.kubernetes.io/defaultProfileNames: 'docker/default'
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
apparmor.security.beta.kubernetes.io/defaultProfileNames: 'runtime/default'
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'MustRunAsRoot'
ranges:
- min: 1
max: 65535
fsGroup:
rule: 'MustRunAsRoot'
ranges:
- min: 1
max: 65535
readOnlyRootFilesystem: false
Kubernetes建议使用RBAC授权机制来设置针对Pod安全策略的授权,通常应该对Pod的ServiceAccount进行授权。
例如,可以创建如下ClusterRole(也可以创建Role)并将其设置为允许使用PodSecurityPolicy:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: role-name
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames:
- #允许使用的PodSecurityPolicy列表
然后创建一个ClusterRoleBinding与用户和ServiceAccount进行绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: bind-name
ruleRef:
kind: ClusterRole
name: role-name
apiGroup: rabc.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: serviceaccount
namespace:
- kind: User
name: username
apiGroup: rbac.authorization.k8s.io
也可以创建RoleBinding对与该RoleBinding相同的Namespace中的Pod进行授权,通常可以与某个系统级别的Group关联配置,例如:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: bind-name
namespace: namespace #该RoleBinding所属的namespace
roleRef:
kind: Role
name:
apiGroup: rabc.authorization.k8s.io
subjects:
#授权该Namespace中的全部ServiceAccount
- kind: Group
apiGroup: rabc.authorization.k8s.io
name: system:serviceaccounts
#授权该Namespace的全部用户
- kind: User
apiGroup: rabc.authorization.k8s.io
name: system:authenticated
Pod和容器的安全策略可以在Pod或Container的securityContext字段中设置,如果在Pod和Container级别都设置了相同的安全类型字段,容器将使用Container级别的设置。
在Pod级别可以设置的安全措施如下:
runAsUser:容器内运行程序的用户ID。
例如:Pod级别的安全设置,作用于该Pod内的全部容器
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: nginx
volumeMounts:
- name: sec-ctx-demo
mountPath: /data/demo
securityContext:
allowPrivilegeEscalation: false
Container级别的安全设置,作用于特定的容器。
apiVersion: v1
kind: Pod
metadata:
name: scd-2
spec:
securityContext:
runAsUser: 1000
containers:
- name: scd-2
image: nginx:latest
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 2000
allowPrivilegeEscalation: false
为Container设置可用的Linux能力,为容器设置允许使用的Linux能力包括NET_ADMIN和SYS_TIME。
apiVersion: v1
kind: Pod
metadata:
name: scd-3
spec:
containers:
- name: scd-3
image: nginx
securityContext:
capabilities:
add: ["NET_ADMIN","SYS_TIME"]