系列目錄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