Kubernetes過一系列機制來實現集羣的安全機制,包括API Server的認證受權、准入控制機制及保護敏感信息的Secret機制等。集羣的安全性必須考慮如下的幾個目標:redis
下面分別從Authentication、Authorization、Admission Control、Secret和Service Account等方面來講明集羣的安全機制。算法
Kubernetes集羣中全部資源的訪問和變動都是經過Kubernetes API Server的REST API來實現的,因此集羣安全的關鍵點在於識別認證客戶端身份(Authentication)以及訪問權限的受權(Authorization)。docker
Kubernetes提供管理三種級別的客戶端身份認證方式:數據庫
SSL雙向認證步驟:後端
CA認證流程圖:api
上述是雙向SSL協議的具體通訊過程,這種狀況要求服務器和用戶雙方都有證書。單向認證SSL協議不須要客戶擁有CA證書,對應上面的步驟,只需將服務器端驗證客戶端證書的過程去掉,以及在協商對稱密碼方案和對稱通話祕鑰時,服務器端發送給客戶端的是沒有加過密的(這並不影響SSL過程的安全性)密碼方案。安全
HTTP Token原理:HTTP Token的認證是用一個很長的特殊編碼方式的而且難以被模仿的字符串——Token來代表客戶身份的一種方式。在一般狀況下,Token是一個複雜的字符串,好比咱們用私鑰簽名一個字符串的數據就能夠做爲一個Token,此外每一個Token對應一個用戶名,存儲在API Server能訪問的一個文件中。當客戶端發起API調用請求時,須要在HTTP Header裏放入Token,這樣一來API Server就可以識別合法用戶和非法用戶了。服務器
HTTP Base:常見的客戶端帳號登陸程序,這種認證方式是把「用戶名+冒號+密碼」用BASE64算法進行編碼後的字符串放在HTTP REQUEST中的Header Authorization域裏發送給服務端,服務端收到後進行解碼,獲取用戶名及密碼,而後進行用戶身份的鑑權過程。併發
對合法用戶進行受權(Authorization)而且隨後在用戶訪問時進行鑑權,是權限與安全系統的重要一環。受權就是授予不一樣用戶不一樣訪問權限,API Server目前支持一下集中受權策略:框架
爲了簡化受權的複雜度,對於ABAC模式的受權策略,Kubernetes僅有下面四個基本屬性:
當API Server啓用ABAC模式時,須要指定受權文件的路徑和名字(--authorization_policy_file=SOME_FILENAME),受權策略文件裏的每一行都是一個Map類型的JOSN對象,被稱爲訪問策略對象,咱們能夠經過設置「訪問策略對象」中的以下屬性來肯定具體的受權行爲:
eg:
經過認證和鑑權以後,客戶端並不能獲得API Server的真正響應,這個請求還需經過Admission Control所控制的一個「准入控制鏈」的層層考驗,Admission Control配備有一個「准入控制器」的列表,發送給API Server的任何請求都須要經過列表中每一個准入控制器的檢查,檢查不經過API Server拒絕此調用請求。此外,准入控制器還可以修改請求參數以完成一些自動化的任務。好比Service Account這個控制器,當前可配置的准入控制以下:
在API Server上設置--admission-control參數,便可定製咱們須要的准入控制鏈,若是啓用多種准入控制選項,則建議的設置以下:
下面着重介紹三個准入控制器:
Security Context時運用於容器的操做系統安全設置(uid、gid、capabilities、SELinux role等),Admission Control的SecurityContextDeny插件的做用是,禁止建立設置了Security Context的Pod,例如包含如下配置項的Pod:
ResourceQuota不只可以限制某個Namespace中建立資源的數量,並且可以限制某個namespace中被Pod所請求的資源總量。該准入控制器和資源對象ResourceQuota一塊兒實現了資源的配額管理;
准入控制器LimitRanger的做用相似於上面的ResourceQuota控制器,這對Namespace資源的每一個個體的資源配額。該插件和資源對象LimitRange一塊兒實現資源限制管理。
Servuce Account是一種帳號,但他並非給Kubernetes的集羣的用戶(系統管理員、運維人員、租戶用戶等),而是給運行在Pod裏的進程用的,它爲Pod裏的進程提供必要的身份證實。
Pod中訪問Kubernetes API Server服務的時候,是以Service方式訪問服務名爲kubernetes這個服務的,而kubernetes服務又只在HTTPS安全端口443上提供服務,那麼如何進行身份認證呢?在Kubernetes的官方文檔並無清除的說明這個問題。
經過查看源碼獲知這是在用一種相似HTTP Token的新的認證方式--ServiceAccount Auht,Pod中的客戶端調用Kubernetes API的時候,在HTTP Header中傳遞了一個Token字符串,這相似於以前提到的HTTP Token認證方式,存在如下幾個不一樣點:
明白原理以後。接下來分析認證過程當中涉及的Pod中的三個文件:
這三個文件因爲參與到Pod進程與API Server認證的過程當中,起到了相似Secret(私密憑據)的做用,因此他們被稱爲Kubernetes Secret對象。Secret從屬於ServiceAccount資源對象,屬於Service Account的一部分,一個ServiceAccount對象裏面能夠包括多個不一樣的Secret對象,分別用於不一樣目的的認證活動。
下面經過命令來直觀的加深對ServiceAccount的認識:
查看系統中ServiceAccount對象,能夠看到一個名爲default的Service Account對象,包含一個名爲default-token-xxx的Secret,這個Secret同時是「Mountable secrets」,代表他是須要被Mount到Pod上的。
default-token-xxx包括三個數據項:
聯想到「Mountable secrets」的標記,以及以前看到的Pod中的三個文件的文件名:每一個namespace下有一個名爲default的默認的ServiceAccount對象,這個ServiceAccount裏有一個名爲Tokens的能夠做爲Volume同樣被Mount到Pod裏的Secret,當Pod啓動時這個Secret會被自動Mount到Pod的指定目錄下,用來協助完成Pod中的進程訪問API Server時的身份鑑權過程。
一個ServiceAccount能夠包括多個Secrets對象:
若是一個Pod在定義時沒有指定spec.service.AccountName屬性,則系統會自動爲其賦值爲「Default」,即便用同一namespace下默認的ServiceAccount,若是某個Pod須要使用非default的ServiceAccount,須要在定義時指定:
apiVersion:v1
kind:Pod
metadata:
name:mypod
spec:
containers:
- name:mycontainer
image:
serviceAccountName:myserviceaccount
Kubernetes之因此要建立兩套獨一的帳號系統,緣由以下:
下面分析Service Account與Secret相關的一些運行機制:
Controller manager建立了ServiceAccountController與Token Controllerl兩個安全相關的控制器。其中ServiceAccountController一直監聽Service Account和Namespace的事件,若是一個Namespace中沒有default Service Account,那麼Service Account Controller就會爲該Namespace建立一個默認的(default)的Service Account,這就是咱們以前看到的每一個namespace下都有一個名爲default的ServiceAccount的緣由。
若是Controller manager進程在啓動時指定了API Server私鑰(service-account-private-key-file)參數,那麼Controller manager會建立Token Controller。Token Controller也監聽Service Account的事件,若是發現新建的Service Account裏沒有對應的Service Account Secret,則會用API Server私鑰建立一個Token(JWT Token),並用該Token、CA證書Namespace名稱等三個信息產生一個新的Secret對象,而後放入剛纔的Service Account中;若是監聽到的事件是刪除Service Account事件,則自動刪除與該Service Account相關的全部Secret。此外,Token Controller對象同時監聽Secret的建立、修改和刪除事件,並根據事件的不一樣作不一樣的處理。
當咱們在API Server的鑑權過程當中啓用了Service Account類型的准入控制器,即在kube-apiserver的啓動參數中包括下面的內容時:
則針對Pod新增或修改的請求,Service Account准入控制器會驗證Pod裏Service Account是否合法。
綜上所述,ServiceAccount正常運行須要如下幾個控制器:
Secret主要做用是保管私密數據,好比密碼、OAuth Tokens、SSH Keys等信息。將這些私密信息放在Secret對象中比直接放在Pod或Docker Image中要更安全,也便於使用和分發。
secret.yaml
apiVersion:v1
kind:Secret
metadata:
name:mysecret
type: Opaque
data:
password:dmfsdWUtMg0k
username:dmfsdWUtMg0k
kubectl create -f secret.yaml
在上面的data域中的各子域的值必須爲BASE64編碼值,其中password域和username域BASE64編碼前的值分別爲value-1和value-2。一旦secret被建立,能夠經過如下三個方式使用它:
apiVersion:v1
kind:Pod
metadata:
name:mypod
namespace:myns
spec:
containers:
- name:mycontainer
image:redis
volumeMounts:
- name:foo
mountPath:「/etc/foo」
readOnly:true
volumes:
- name:foo
secret:
secretName:mysecret
image-pull-secret.yaml:
apiVersion:v1
kind:Secret
metadata:
name:myregistrykey
data:
.dockercfg:xxx
type:kubernetes.io/dockercfg
pods.yaml
apiVersion:v1
kind:Pod
metadata:
name:mypod2
spec:
containers:
- name:foo
image:xxxxxx:v1
imagePullSecrets:
- name:myregistrykey
每一個單獨的Secret大小不能超過1M,Kubernetes不鼓勵建立大尺寸的Secret,由於若是使用大尺寸的Secret,則將大量佔用API Server和kubelet的內存。固然建立許多小的Secret也能耗盡API Server和kubelet的內存。
在使用Mount方式掛載Secret時,Container中Secret的「data」域的各個域的key值做爲目錄中的文件,Value值被BASE64編碼後存儲在相應的文件中。前面的例子中建立的Secret,被掛載到一個叫作mycontainer的container中,在該container中能夠經過命令查看所生產的文件和文件中的內容:
username
password
value-1
value-2
咱們能夠經過Secret保管其餘系統的敏感信息(好比數據庫用戶名和密碼),並以Mount的方式將Secret掛載到Container中,而後經過訪問目錄中的文件的方式獲取該敏感信息。當Pod被API Server建立時,API Server不會校驗該Pod引用的Secret是否存在。一旦這個Pod被調度,則Kubelet將試着獲取Secret的值。若是Secret不存在或暫時沒法鏈接到API Server,則kubelet將按必定的時間間隔按期重試獲取該Secret,併發送一個Event來解釋Pod沒有啓動的緣由。一旦Secret被Pod獲取,則Kubelet將建立並Mount包含Secret的Volume。只有全部的Volume被Mount後,Pod中的Container纔會被啓動。在kubelet啓動Pod中container後,Container中和Secret相關的Volume將不會被改變,即便Secret自己被修改了。爲了使用更新後的Secret,必須刪除舊的Pod,並從新建立一個新的Pod,所以更新Secret的流程和部署一個新的Image是同樣的。