kubernetes高級之pod安全策略

系列目錄html

什麼是pod安全策略

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安全策略

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受權

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

如下定義文件定義了一個簡單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

咱們再嘗試建立一個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中的全部容器是否被容許以特權方式運行.默認狀況下容器不容許訪問主機的設備,可是特權容器卻被容許訪問.這將容許容器有幾乎和它所在的進程同樣的訪問主機的權利.這將很是有用當容器想要使用主機的功能,好比訪問網絡的設備.

Host名稱空間

HostPID - 控制容器是否能夠共享主機的進程id名稱空間

HostIPC - 控制容器是否能夠共享主機的IPC名稱空間

HostNetwork - 控制容器是否可使用所在節點的網絡名稱空間.這將容許pod訪問迴環設備,監聽localhost,而且能夠窺探同一節點上其它pod的網絡活動情況

AllowedHostPaths - 控制容許訪問的宿主機路徑

存儲卷和文件系統

Volumes - 提供了一系列的存儲卷類型白名單.這些容許的值和建立存儲卷時定義的資源類型相對應.想要獲取全部存儲卷類型,能夠查看存儲卷類型列表.此外,*能夠被用來容許全部的存儲卷類型

如下是推薦的最小化的容許存儲卷類型的安全策略配置

  • configMap
  • downwardAPI
  • emptyDir
  • persistentVolumeClaim
  • secret
  • projected

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

相關文章
相關標籤/搜索