深刻淺出 Kubernetes 安全機制

《深刻淺出 Kubernetes 安全機制》最先發布在 blog.hdls.me/15432142284…html

在 Kubernetes 中,全部資源的訪問和變動都是圍繞 APIServer 展開的。好比說 kubectl 命令、客戶端 HTTP RESTFUL 請求,都是去 call APIServer 的 API 進行的,本文就重點解讀 k8s 爲了集羣安全,都作了些什麼。node

首先,Kubernetes 官方文檔給出了上面這張圖。描述了用戶在訪問或變動資源的以前,須要通過 APIServer 的認證機制、受權機制以及准入控制機制。這三個機制能夠這樣理解,先檢查是否合法用戶,再檢查該請求的行爲是否有權限,最後作進一步的驗證或添加默認參數。web

用戶

Kubernetes 中有兩種用戶,一種是內置「用戶」 ServiceAccount,另外一種我稱之爲天然人。json

所謂天然人就是指區別於 pod 等資源概念的「人」,能夠理解成實際操做 "kubectl" 命令的人。admin 能夠分發私鑰,但天然人能夠儲存相似 KeyStone 甚至包含帳號密碼的文件,因此 k8s 中沒有對天然人以 API 對象描述之。bootstrap

在典型的 Kubernetes 集羣中,API 一般服務在 443 端口,APIServer 提供自簽名證書。當你使用 kube-up.sh 建立集羣用戶時,證書會自動在 $USER/.kube/config 中建立出來,然後續用 kubectl 命令訪問 APIServer 時,都是用這個證書。api

與之相反,k8s 中以 API 對象的形式描述和管理 ServiceAccount。它們被綁定在某個具體的 namespace 中,能夠由 APIServer 自動建立出來或手動 call k8s API。安全

認證機制(Authentication)

k8s 中的認證機制,是在用戶訪問 APIServer 的第一步。一般是一個完整的 HTTP 請求打過來,可是這一步每每只檢測請求頭或客戶端證書。bash

認證機制目前有客戶端證書、bearer tokens、authenticating proxy、HTTP basic auth 這幾種模式。使用方式一般有如下幾種:ide

  1. X509 Client Certs: 客戶端證書模式須要在 kubectl 命令中加入 --client-ca-file=<SOMEFILE> 參數,指明證書所在位置。ui

  2. Static Token File: --token-auth-file=<SOMEFILE> 參數指明 bearer tokens 所在位置。

  3. bearer tokens: 在 HTTP 請求頭中加入 Authorization: Bearer <TOKEN>

  4. Bootstrap Tokens: 與 bearer tokens 一致,但 TOKEN 格式爲 [a-z0-9]{6}.[a-z0-9]{16}。該方式稱爲 dynamically-managed Bearer token,以 secret 的方式保存在 kube-system namespace 中,能夠被動態的建立和管理。同時,啓用這種方式還須要在 APIServer 中打開 --enable-bootstrap-token-auth ,這種方式還處於 alpha 階段。

  5. Static Password File: 以參數 --basic-auth-file=<SOMEFILE> 指明 basic auth file 的位置。這個 basic auth file 以 csv 文件的形式存在,裏面至少包含三個信息:password、username、user id,同時該模式在使用時須要在請求頭中加入 Authorization: Basic BASE64ENCODED(USER:PASSWORD)

  6. Service Account Tokens: 該方式一般被 pod 所使用,在 PodSpec 中指明 ServiceAccount 來訪問 ApiServer。

除了以上列出來的幾種方式外,還有一些比較特殊的訪問方式,這裏再也不詳細解讀。

受權機制(Authorization)

當用戶經過認證後,k8s 的受權機制將對用戶的行爲等進行受權檢查。換句話說,就是對這個請求自己,是否對某資源、某 namespace、某操做有權限限制。

受權機制目前有 4 種模式:RBAC、ABAC、Node、Webhook。下面對這 4 種模式分別作分析。

RBAC

Role-based access control (RBAC) 是基於角色的權限訪問控制,一般是對於「內置用戶」而言的。該模式是在 k8s v1.6 開發出來的。若要開啓該模式,須要在 APIServer 啓動時,設置參數 --authorization-mode=RBAC

RBAC 所使用的 API Group 是 rbac.authorization.k8s.io/v1beta1,直到 Kubernetes v1.8 後,RBAC 模塊達到穩定水平,所使用的 API Group 爲 rbac.authorization.k8s.io/v1

所謂基於角色的權限訪問控制,就是對某個用戶賦予某個角色,而這個角色一般決定了對哪些資源擁有怎樣的權限。

ServiceAccount

首先來看看這個 「內置用戶」,在大多時候咱們都不使用 「天然人」 這個功能,而是使用 ServiceAccount,再對其餘資源授予某個 ServiceAccount,就使得其可以以 「內置用戶」 的身份去訪問 APIServer。

建立一個 ServiceAccount 很簡單,只須要指定其所在 namespace 和 name 便可。舉個例子:

apiVersion: v1
kind: ServiceAccount
metadata:
 namespace: hdls
 name: hdls-sa
複製代碼

Role & Rolebinding

RBAC 中最重要的概念就是 RoleRoleBindingRole 定義了一組對 Kubernetes API 對象的操做權限,而 RoleBinding 則定義的是具體的 ServiceAccount 和 Role 的對應關係。

舉個 Role 的例子以下:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
	namespace: hdls
	name: hdls-role
rules:
- apiGroups: [""]
 resources: ["pods"]
 verbs: ["get", "list"]
複製代碼

其中: namespace: 在這裏僅限於邏輯上的「隔離」,並不會提供任何實際的隔離或者多租戶能力; rules:定義的是權限規則,容許「被做用者」,對 hdls 下面的 Pod 對象,進行 GET 和 LIST 操做; apiGroups:爲 "" 表明 core API Group; resources:指的是資源類型,對此還能夠進行詳細的劃分,指定能夠操做的資源的名字,好比:

rules:
- apiGroups: [""]
 resources: ["configmaps"]
 resourceNames: ["my-config"]
 verbs: ["get"]
複製代碼

verbs: 指的是具體的操做,當前 Kubernetes(v1.11)裏可以對 API 對象進行的全部操做有 "get", "list", "watch", "create", "update", "patch", "delete"。

再看 RoleBinding 的例子:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
	name: hdls-rolebinding
	namespace: hdls
subjects:
- kind: ServiceAccount
	name: hdls-sa
	apiGroup: rbac.authorization.k8s.io
roleRef:
	kind: Role
	name: hdls-role
	apiGroup: rbac.authorization.k8s.io
複製代碼

能夠看到,這個 RoleBinding 對象裏定義了一個 subjects 字段,即「被做用者」。它的類型是 ServiceAccount,就是上面建立的 sa。這個 subjects 還能夠是 User 和 Group,User 是指 k8s 裏的用戶,而 Group 是指 ServiceAccounts。

roleRef 字段是用來直接經過名字,引用咱們前面定義的 Role 對象(hdls-role),從而定義了 Subject 和 Role 之間的綁定關係。

此時,咱們再用 kubectl get sa -n hdls -o yaml 命令查看以前的 ServiceAccount,就能夠看到 ServiceAccount.secret,這是由於 k8s 會爲一個 ServiceAccount 自動建立並分配一個 Secret 對象,而這個 Secret 就是用來跟 APIServer 進行交互的受權文件: TokenToken 文件的內容通常是證書或者密碼,以一個 Secret 對象的方式保存在 etcd 當中。

這個時候,咱們在咱們的 Pod 的 YAML 文件中定義字段 .spec.serviceAccountName 爲上面的 ServiceAccount name 便可聲明使用。

若是一個 Pod 沒有聲明 serviceAccountName,Kubernetes 會自動在它的 Namespace 下建立一個名叫 default 的默認 ServiceAccount,而後分配給這個 Pod。然而這個默認 ServiceAccount 並無關聯任何 Role。也就是說,此時它有訪問 APIServer 的絕大多數權限。

ClusterRole & ClusterRoleBinding

須要注意的是 Role 和 RoleBinding 對象都是 Namespaced 對象,它們只對本身的 Namespace 內的資源有效。

而某個 Role 須要對於非 Namespaced 對象(好比:Node),或者想要做用於全部的 Namespace 的時候,咱們須要使用 ClusterRole 和 ClusterRoleBinding 去作受權。

這兩個 API 對象的用法跟 Role 和 RoleBinding 徹底同樣。只不過,它們的定義裏,沒有了 Namespace 字段。

值得一提的是,Kubernetes 已經內置了不少個爲系統保留的 ClusterRole,它們的名字都以 system: 開頭。通常來講,這些系統級別的 ClusterRole,是綁定給 Kubernetes 系統組件對應的 ServiceAccount 使用的。

除此以外,Kubernetes 還提供了四個內置的 ClusterRole 來供用戶直接使用:

cluster-admin:整個集羣的最高權限。若是在 ClusterRoleBinding 中使用,意味着在這個集羣中的全部 namespace 中的全部資源都擁有最高權限,隨心所欲;若是在 RoleBinding 中使用,即在某個 namespace 中隨心所欲。

admin:管理員權限。若是在 RoleBinding 中使用,意味着在某個 namespace 中,對大部分資源擁有讀寫權限,包括建立 Role 和 RoleBinding 的權限,但沒有對資源 quota 和 namespace 自己的寫權限。

edit:寫權限。在某個 namespace 中,擁有對大部分資源的讀寫權限,但沒有對 Role 和 RoleBinding 的讀寫權限。

view:讀權限。在某個 namespace 中,僅擁有對大部分資源的讀權限,沒有對 Role 和 RoleBinding 的讀權限,也沒有對 seccrets 的讀權限。

Aggregated ClusterRoles

在 Kubernetes v1.9 以後,ClusterRole 有一種新的定義方法,就是使用 aggregationRule 將多個 ClusterRole 合成一個新的 ClusterRole

首先看個 k8s 官網的例子:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: monitoring
aggregationRule:
 clusterRoleSelectors:
 - matchLabels:
      rbac.example.com/aggregate-to-monitoring: "true"
rules: []
複製代碼

其中 rules 字段沒必要定義,會被 controller manager 自動填充。

能夠看出 aggregationRule 就是將全部知足 label 條件的 ClusterRole 的合成一個 ClusterRole,而這個新的 ClusterRole 權限爲其餘總和。

Group

相對於 User 而言,k8s 還擁有「用戶組」(Group)的概念,也就是一組「用戶」的意思。而對於「內置用戶」 ServiceAccount 來講,「用戶組」的概念也一樣適用。

實際上,一個 ServiceAccount,在 Kubernetes 裏對應的「用戶」的名字是: system:serviceaccount:<ServiceAccount 名字 > ;而它對應的內置「用戶組」的名字,就是 system:serviceaccounts:<Namespace 名字 >

對於 Group 的運用,咱們舉個例子,在 RoleBinding 裏這樣定義 subjects:

subjects:
- kind: Group
	name: system:serviceaccounts:hdls
	apiGroup: rbac.authorization.k8s.io
複製代碼

這就意味着這個 Role 的權限規則,做用於 hdls 裏的全部 ServiceAccount。

而若是 Group 不指定 Namespace,即直接定義爲 system:serviceaccounts,意味着做用於整個系統裏的全部 ServiceAccount。

ABAC

Attribute-based access control (ABAC) 是基於屬性的權限訪問控制。若要開啓該模式,須要在 APIServer 啓動時,開啓 --authorization-policy-file=<SOME_FILENAME>--authorization-mode=ABAC 兩個參數。

其 policy 文件用來指定權限規則,必須知足每行都是一個 json 對象的格式。能夠指定 user 或 group 爲某個特定的對象,並描述其擁有的權限。

與 Yaml 文件一致,必須描述的屬性有 apiVersion、kind、spec,而 spec 裏描述了具體的用戶、資源和行爲。看個例子:

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "bob", "namespace": "projectCaribou", "resource": "pods", "readonly": true}}
複製代碼

這就描述了用戶 bob 只有在 namespace projectCaribou 下對 pod 的讀權限。相似的,這個 User 能夠是某我的,也能夠是 kubelet 或者某個 ServiceAccount,這裏 ServiceAccount 須要寫全,好比:system:serviceaccount:kube-system:default

若是是描述某個 namespace 下的全部人,須要用到 group,好比:

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group": "system:serviceaccounts:default", "readonly": true, "resource": "pods"}}
複製代碼

Node

Node 受權機制是一種特殊的模式,是 kubelet 發起的請求受權。開啓該模式,須要開啓參數 --authorization-mode=Node

經過啓動 --enable-admission-plugins=...,NodeRestriction,...,來限制 kubelet 訪問 node,endpoint、pod、service以及secret、configmap、PV 和 PVC 等相關的資源。

Webhook

Webhook 模式是一種 HTTP 回調模式,是一種經過 HTTP POST 方式實現的簡單事件通知。該模式須要 APIServer 配置參數 –authorization-webhook-config-file=<SOME_FILENAME>,HTTP 配置文件的格式跟 kubeconfig 的格式相似。

# Kubernetes API version
apiVersion: v1
# kind of the API object
kind: Config
# clusters refers to the remote service.
clusters:
 - name: name-of-remote-authz-service
 cluster:
      # CA for verifying the remote service.
 certificate-authority: /path/to/ca.pem
      # URL of remote service to query. Must use 'https'. May not include parameters.
 server: https://authz.example.com/authorize

# users refers to the API Server's webhook configuration.
users:
 - name: name-of-api-server
 user:
 client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
 client-key: /path/to/key.pem          # key matching the cert

# kubeconfig files require a context. Provide one for the API Server.
current-context: webhook
contexts:
- context:
 cluster: name-of-remote-authz-service
 user: name-of-api-server
 name: webhook
複製代碼

其中,Cluster 指須要回調的地方的客戶端,指定其訪問證書和 URL;user 指回調處訪問的身份,指明其所需證書和 key;contexts 指回調的內容。

准入控制(Admission Controllers)

在一個請求經過了認證機制和受權認證後,須要通過最後一層篩查,即准入控制。這個准入控制模塊的代碼一般在 APIServer 中,並被編譯到二進制文件中被執行。這一層安全檢查的意義在於,檢查該請求是否達到系統的門檻,便是否知足系統的默認設置,並添加默認參數。

准入控制以插件的形式存在,開啓的方式爲: kube-apiserver --enable-admission-plugins=NamespaceLifecycle,LimitRanger ...

關閉的方式爲: kube-apiserver --disable-admission-plugins=PodNodeSelector,AlwaysDeny ...

經常使用的准入控制插件有:

  • AlwaysAdmit:容許全部請求經過,被官方反對,由於沒有實際意義;
  • AlwaysPullImages:將每一個 pod 的 image pull policy 改成 always,在多租戶的集羣被使用;
  • AlwaysDeny:禁止全部請求經過,被官方反對,由於沒有實際意義;
  • DefaultStorageClass:爲每一個 PersistentVolumeClaim 建立默認的 PV;
  • DefaultTolerationSeconds:若是 pod 對污點 node.kubernetes.io/not-ready:NoExecutenode.alpha.kubernetes.io/unreachable:NoExecute 沒有容忍,爲其建立默認的 5 分鐘容忍 notready:NoExecuteunreachable:NoExecute
  • LimitRanger:確保每一個請求都沒有超過其 namespace 下的 LimitRange,若是在 Deployment 中使用了 LimitRange 對象,該准入控制插件必須開啓;
  • NamespaceAutoProvision:檢查請求中對應的 namespace 是否存在,若不存在自動建立;
  • NamespaceExists:檢查請求中對應的 namespace 是否存在,若不存在拒絕該請求;
  • NamespaceLifecycle:保證被刪除的 namespace 中不會建立新的資源;
  • NodeRestriction:不容許 kubelet 修改 Node 和 Pod 對象;
  • PodNodeSelector:經過讀取 namespace 的註解和全局配置,來控制某 namespace 下哪些 label 選擇器可被使用;
  • PodPreset:知足預先設置的標準的 pod 不容許被建立;
  • Priority:經過 priorityClassName 來決定優先級;
  • ResourceQuota:保證 namespace 下的資源配額;
  • ServiceAccount:保證 ServiceAccount 的自動建立,若是用到 ServiceAccount,建議開啓;

以上只列舉了部分,詳情請移步 Kubernetes 官方文檔。

官方建議:

  • 版本 > v1.10:
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota
複製代碼
  • v1.9
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota
複製代碼
  • v1.6 - v1.8
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
複製代碼
  • v1.4 - v1.5
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota
複製代碼

相關文章
相關標籤/搜索