十五、Kubernetes之安全配置


本章實驗為kubeadm安裝k8s集群https://www.cnblogs.com/yaokaka/p/15501688.html

在任何將資源或服務提供給有限使用者的系統上,認證和授權是兩個必不可少的功能,前者用於身份鑒別,負責驗證“來者是誰”,而后者則實現權限分派,負責鑒證“他有權做哪些事”。Kubernetes系統完全分離了身份驗證和授權功能,將二者分別以多種不同的插件實現,而且,特有的准入控制機制,還能在“寫”請求上輔助完成更為精細的操作驗證及變異功能。

Kubernetes集群中所有資源的訪問和變更都是通過Kubernetes API Server的REST API來實現的,所以集群安全的關鍵點就在於如何識別並認證客戶端身份(Authentication),以及隨后訪問權限的授權(Authorization)這兩個關鍵問題。

一、Kubernetes的訪問控制介紹

1、apiserver的認證

API Server作為Kubernetes集群系統的網關,是訪問及管理資源對象的唯一入口,它默認監聽TCP的6443端口,通過HTTPS協議暴露了一個RESTful風格的接口。所有需要訪問集群資源的集群組件或客戶端,包括kube-controller-manager、kube-scheduler、kubelet和kube-proxy等集群基礎組件,CoreDNS等集群的附加組件,以及此前使用的kubectl命令等都必須要經此網關請求與集群進行通信。所有客戶端均要經由API Server訪問或改變集群狀態以及完成數據存儲,並且API Server會對每一次的訪問請求進行合法性檢驗,包括用戶身份鑒別、操作權限驗證以及操作是否符合全局規范的約束等。所有檢查均正常完成且對象配置信息合法性檢驗無誤之后才能訪問或存入數據到后端存儲系統etcd中。

 

客戶端認證操作由API Server配置的一到多個認證插件完成。收到請求后,API Server依次調用配置的認證插件來校驗客戶端身份,直到其中一個插件可以識別出請求者的身份為止。授權操作則由一到多個授權插件完成,這些插件負責確定通過認證的用戶是否有權限執行發出的資源操作請求,該類操作包括創建、讀取、刪除或修改指定的對象等。隨后,通過授權檢測的用戶請求修改相關的操作還要經由一到多個准入控制插件的遍歷式檢測,例如使用默認值補足要創建的目標資源對象中未定義的各字段、檢查目標Namespace資源對象是否存在、檢查請求創建的Pod對象是否違反系統資源限制等,而其中任何的檢查失敗都可能會導致寫入操作失敗。

Kubernetes對整個系統的認證,授權,訪問控制做了精密的設置;對於Kubernetes集群來說,apiserver是整個就集群訪問控制的唯一入口,在Kubernetes集群之上部署應用程序的時候,也可以通過宿主機的NodePort暴露的端口訪問里面的程序,用戶訪問kubernetes集群需要經歷如下認證過程:認證->授權->准入控制(adminationcontroller)

1).認證(Authenticating)是對客戶端的認證,通俗點就是用戶名密碼驗證。認證通過,則客戶端可以與Kubernetes集群進行交互。

2).授權(Authorization)是對資源的授權,Kubernetes中的資源無非是容器,最終其實就是容器的計算,網絡,存儲資源,當一個請求經過認證后,需要訪問某一個資源(比如創建一個pod),授權檢查都會通過訪問策略比較該請求上下文的屬性,(比如用戶,資源和Namespace),根據授權規則判定該資源(比如某namespace下的pod)是否是該客戶可訪問的。授權通過,則客戶端可以對集群中授權的資源做增、刪、改、查的操作。

3).准入(Admission Control)機制是一種在改變資源的持久化之前(比如某些資源的創建或刪除,修改等之前)的機制。不會攔截查詢操作。

2、Kubernetes的用戶賬戶及用戶組

Kubernetes系統上的用戶賬戶及用戶組的實現機制與常規應用略有不同。Kubernetes集群將那些通過命令行工具kubectl、客戶端庫或者直接使用RESTful接口向API Server發起請求的客戶端上的請求主體分為兩個不同的類別:現實中的“人”和Pod對象,它們的用戶身份分別對應用戶賬戶(User Account,也稱為普通用戶)和服務賬戶(Service Account,簡稱SA)。

1)用戶賬戶:其使用主體往往是“人”,一般由外部的用戶管理系統存儲和管理,Kubernetes本身並不維護這一類的任何用戶賬戶信息,它們不會存儲到API Server之上,僅僅用於檢驗用戶是否有權限執行其所請求的操作。

2)服務賬戶:其使用主體是“應用程序”,專用於為Pod資源中的服務進程提供訪問Kubernetes API時的身份標識(identity);ServiceAccount資源通常要綁定到特定的名稱空間,它們由API Server自動創建或通過API調用,由管理員手動創建,通常附帶着一組訪問API Server的認證憑據——Secret,可由同一名稱的Pod應用訪問API Server時使用。

3)用戶賬戶通常用於復雜的業務邏輯管控,作用於系統全局,因而名稱必須全局唯一。Kubernetes並不會存儲由認證插件從客戶端請求中提取的用戶及所屬的組信息,因而也就沒有辦法對普通用戶進行身份認證,它們僅僅用於檢驗該操作主體是否有權限執行其所請求的操作。

4)服務賬戶則隸屬於名稱空間級別,僅用於實現某些特定操作任務,因此功能上要輕量得多。這兩類賬戶都可以隸屬於一個或多個用戶組。

舉例說明:

sa賬號:訪問pod資源中提供的服務的賬號。如:登陸dashboard使用的賬號。

user account:這個是登陸Kubernetes集群物理機器的賬號。如:配置一個賬號讓其只能訪問集群中namespace=dev下的資源。

用戶組只是用戶賬戶的邏輯集合,它本身沒有執行系統操作的能力,但附加於組上的權限可由其內部的所有用戶繼承,以實現高效的授權管理機制。Kubernetes有以下幾個內置用於特殊目的的組。

▪system:unauthenticated:未能通過任何一個授權插件檢驗的賬戶的、所有未通過認證測試的用戶統一隸屬的用戶組。
▪system:authenticated:認證成功后的用戶自動加入的一個專用組,用於快捷引用所有正常通過認證的用戶賬戶。
▪system:serviceaccounts:所有名稱空間中的所有ServiceAccount對象。
▪system:serviceaccounts:<namespace>:特定名稱空間內所有的ServiceAccount對象。

對API Server來說,來自客戶端的請求要么與用戶賬戶綁定,要么以某個服務賬戶的身份進行,要么被視為匿名請求。這意味着群集內部或外部的每個進程,包括由人類用戶使用kubectl,以及各節點上運行的kubelet進程,再到控制平面的成員組件,必須在向API Server發出請求時進行身份驗證,否則即被視為匿名用戶。

3、認證、授權與准入控制基礎知識

Kubernetes使用身份驗證插件對API請求進行身份驗證,它允許管理員自定義服務賬戶和用戶賬戶要啟用或禁用的插件,並支持各自同時啟用多種認證機制。具體設定時,至少應該為服務賬戶和用戶賬戶各自啟用一個認證插件。 如果啟用了多種認證機制,賬號認證過程由認證插件以串行方式進行,直到其中一種認證機制成功完成即結束。若認證失敗,服務器則響應以401狀態碼,反之,請求者就會被Kubernetes識別為某個具體的用戶(以其用戶名進行標識),並且該連接上隨后的操作都會以此用戶身份進行。API Server對於接收到的每個訪問請求會調用認證插件,嘗試將以下屬性與訪問請求相關聯。

▪Username:用戶名,例如kubernetes-admin等。
▪UID:用戶的數字標簽符,用於確保用戶身份的唯一性。
▪Groups:用戶所屬的組,用於權限指派和繼承。
▪Extra:鍵值數據類型的字符串,用於提供認證需要用到的額外信息。

3.1 Kubernetes的認證方式

Kubernetes支持的認證方式包括X.509數字證書、承載令牌(bearer token,也稱為不記名令牌)、身份驗證代理(authenticating proxy)和HTTP Basic認證等。其中所有的令牌認證機制通常被統稱為“承載令牌認證”。

1)靜態密碼文件認證:將用戶名和密碼等信息以明文形式存儲在CSV格式的文件中,由kube-apiserver在啟動時通過--basic-auth-file選項予以加載,添加或刪除用戶都需要重啟API Server;客戶端通過在HTTP Basic認證(Authorization: Basic base64-encoded-username:password標頭)方式中將用戶名和密碼編碼后對該文件進行認證;不建議生產環境中使用。

說明:靜態密碼文件認證插件自Kubernetes v1.20版本中預以棄用,該插件的測試操作部分在v1.20及之后的版本上不可用,但在v1.19及之前的版本中,仍然可用。

2)靜態令牌文件認證:即保存用於認證的令牌信息的靜態文件,由kube-apiserver的命令行選項--token-auth-file加載,且API Sever進程啟動后不可更改;HTTP協議的客戶端能基於承載令牌(Authorization: Bearer <token>標頭)對靜態令牌文件進行身份驗證,它將令牌編碼后通過請求報文中的Authorization頭部承載並傳遞給API Server即可;不建議生產環境中使用。

3)X509客戶端證書認證:客戶端在請求報文中攜帶X.509格式的數字證書用於認證,其認證過程類似於HTTPS協議通信模型;認證通過后,證書中的主體標識(Subject)將被識別為用戶標識,其中的字段CN(Common Name)的值是用戶名,字段O(Organization)的值是用戶所屬的組。例如/CN=ilinux/O=opmasters/O=admin中,用戶名為ilinux,它屬於opmasters和admin兩個組;該認證方式可通過--client-ca-file=SOMEFILE選項啟用。

4)引導令牌(Bootstrap Token)認證:一種動態管理承載令牌進行身份認證的方式,常用於簡化組建新Kubernetes集群時將節點加入集群的認證過程,需要由kube-apiserver通過--experimental-bootstrap-token-auth選項啟用;新的工作節點首次加入時,Master使用引導令牌確認節點身份的合法性之后自動為其簽署數字證書以用於后續的安全通信,kubeadm初始化的集群也是這種認證方式;這些令牌作為Secrets存儲在kube-system命名空間中,可以動態管理和創建它們,並由TokenCleaner控制器負責刪除過期的引導令牌。 5)ServiceAccount令牌認證:該認證方式會由kube-apiserver程序自動啟用,它同樣使用簽名的承載令牌來驗證請求;該認證方式還支持通過可選項--service-account-key-file加載簽署承載令牌的密鑰文件,未指定時將使用API Server自己的TLS私鑰;ServiceAccount通常由API Server自動創建,並通過ServiceAccount准入控制器將其注入Pod對象,包括ServiceAccount上的承載令牌,容器中的應用程序請求API Server的服務時以此完成身份認證。 6)OpenID Connect令牌認證:簡稱為OIDC,是OAuth 2協議的一種擴展,由Azure AD、Salesforce和Google Accounts等OAuth 2服務商所支持,協議的主要擴展是返回的附加字段,其中的訪問令牌也稱為ID令牌;它屬於JSON Web令牌(JWT)類型,有服務器簽名過的常用字段,例如email等;kube-apiserver啟用這種認證功能的相關選項較多。

7)Webhook令牌認證:Webhook身份認證是用於驗證承載令牌的鈎子;HTTP協議的身份驗證允許將服務器的URL注冊為Webhook,並接收帶有承載令牌的POST請求進行身份認證;客戶端使用kubeconfig格式的配置文件,在文件中,users指的是API Server的Webhook,而clusters則指的是API Server。 8)代理認證:API Server支持從請求頭部的值中識別用戶,例如常用的X-Remote-User、X-Remote-Group和幾個以X-Remote-Extra-開頭的頭部,它旨在與身份驗證代理服務相結合,由該代理設置相應的請求頭部;為了防止頭欺騙,在檢查請求標頭之前,需要身份認證代理服務向API Server提供有效的客戶端證書,以驗證指定CA(由選項--requestheader-client-ca-file等進行指定)的代理服務是否合法。

9)那些未能被任何驗證插件明確拒絕的請求中的用戶即為匿名用戶,該類用戶會被冠以system:anonymous用戶名,隸屬於system:unauthenticated用戶組。若API Server啟用了除AlwaysAllow以外的認證機制,則匿名用戶處於啟用狀態。但是,出於安全因素的考慮,建議管理員通過--anonymous-auth=false選項將其禁用。

注意:
API Server還允許用戶通過模擬頭部冒充另一個用戶,這些請求可以以手動方式覆蓋請求中用於身份驗證的用戶信息。例如,管理員可以使用此功能臨時模擬其他用戶來查看請求是否被拒絕,以進行授權策略調試。

除了身份信息,請求報文還需要提供操作方法及其目標對象,例如針對某Pod資源對象進行的創建、查看、修改或刪除操作等:

▪API:用於定義請求的目標是否為一個API資源。
▪Request path:請求的非資源型路徑,例如/api或/healthz。
▪API group:要訪問的API組,僅對資源型請求有效;默認為core API group。
▪Namespace:目標資源所屬的名稱空間,僅對隸屬於名稱空間類型的資源有效。
▪API request verb:API請求類的操作,即資源型請求(對資源執行的操作),包括get、list、create、update、patch、watch、proxy、redirect、delete和deletecollection等。
▪HTTP request verb:HTTP請求類的操作,即非資源型請求要執行的操作,如get、post、put和delete。
▪Resource:請求的目標資源的ID或名稱。
▪Subresource:請求的子資源。

3.2 Kubernetes的授權

為了核驗用戶的操作許可,成功通過身份認證后的操作請求還需要轉交給授權插件進行許可權限檢查,以確保其擁有執行相應操作的許可。API Server主要支持使用4類內置的授權插件來定義用戶的操作權限。

▪Node:基於Pod資源的目標調度節點來實現對kubelet的訪問控制。
▪ABAC:Attribute-based access control,基於屬性的訪問控制。
▪RBAC:Role-based access control,基於角色的訪問控制。
▪Webhook:基於HTTP回調機制實現外部REST服務檢查,確認用戶授權的訪問控制。

另外,還有AlwaysDeny和AlwaysAllow兩個特殊的授權插件,其中AlwaysDeny(總是拒絕)僅用於測試,而AlwaysAllow(總是允許)則用於不期望進行授權檢查時直接在授權檢查階段放行所有的操作請求。--authorization-mode選項用於定義API Server要啟用的授權機制,多個選項值彼此間以逗號進行分隔。

3.3 Kubernetes的准入控制

准入控制器[1](admission controller)則用於在客戶端請求經過身份驗證和授權檢查之后,將對象持久化存儲到etcd之前攔截請求,從而實現在資源的創建、更新和刪除操作期間強制執行對象的語義驗證等功能,而讀取資源信息的操作請求則不會經由准入控制器檢查。API Server內置了許多准入控制器,常用的包含下面列出的幾種。不過,其中的個別控制器僅在較新版本的Kubernetes中才被支持。

1)AlwaysAdmit和AlwaysDeny:前者允許所有請求,后者則拒絕所有請求。
2)AlwaysPullImages:總是下載鏡像,即每次創建Pod對象之前都要去下載鏡像,常用於多租戶環境中,以確保私有鏡像僅能夠由擁有權限的用戶使用。
3)NamespaceLifecycle:拒絕在不存在的名稱空間中創建資源,而刪除名稱空間則會級聯刪除其下的所有其他資源。
4)LimitRanger:可用資源范圍界定,用於對設置了LimitRange的對象所發出的所有請求進行監控,以確保其資源請求不會超限。
5)ServiceAccount:用於實現服務賬戶管控機制的自動化,實現創建Pod對象時自動為其附加相關的Service Account對象。
6)PersistentVolumeLabel:為那些由雲計算服務商提供的PV自動附加region或zone標簽,以確保這些存儲卷能正確關聯且僅能關聯到所屬的region或zone。
7)DefaultStorageClass:監控所有創建PVC對象的請求,以保證那些沒有附加任何專用StorageClass的請求會被自動設定一個默認值。
8)ResourceQuota:用於為名稱空間設置可用資源上限,並確保當其中創建的任何設置了資源限額的對象時,不會超出名稱空間的資源配額。
9)DefaultTolerationSeconds:如果Pod對象上不存在污點寬容期限,則為它們設置默認的寬容期,以寬容notready:NoExecute和unreachable:NoExecute類的污點5分鍾時間。
10)ValidatingAdmissionWebhook:並行調用匹配當前請求的所有驗證類的Webhook,任何一個校驗失敗,請求即失敗。
11)MutatingAdmissionWebhook:串行調用匹配當前請求的所有變異類的Webhook,每個調用都可能會更改對象。

檢查期間,僅那些順利通過所有准入控制器檢查的資源操作請求的結果才能保存到etcd中,而任何一個准入控制器的拒絕都將導致寫入請求失敗。

二、ServiceAccount及認證

Kubernetes原生的應用程序意味着專為運行於Kubernetes系統之上而開發的應用程序,這些程序托管運行在Kubernetes之上,能夠直接與API Server進行交互,並進行資源狀態的查詢或更新,例如Flannel和CoreDNS等。API Server同樣需要對這類來自Pod資源中的客戶端程序進行身份驗證,服務賬戶也是專用於這類場景的賬號。ServiceAccount資源一般由用戶身份信息及保存了認證信息的Secret對象組成。

 

1、ServiceAccount自動化

創建的每個Pod資源都自動關聯了一個Secret存儲卷,並由其容器掛載至/var/run/secrets/kubernetes.io/serviceaccount目錄

[root@k8s-master01 k8s-yaml]# kubectl describe pod test-pod
......
Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-btlhc (ro)
......
Volumes:
  default-token-btlhc:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-btlhc
    Optional:    false
......

容器的該掛載點目錄中通常存在3個文件:ca.crt、namespace和token,其中,token文件保存了ServiceAccount的認證令牌,容器中的進程使用該賬戶認證到API Server,進而由認證插件完成用戶認證並將其用戶名傳遞給授權插件。

[root@k8s-master01 k8s-yaml]# kubectl exec -it test-pod -- bash
[root@test-pod /]# ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt  namespace  token

每個Pod對象只有一個服務賬戶,若創建Pod資源時未予明確指定,則ServiceAccount准入控制器會為其自動附加當前名稱空間中默認的服務賬戶,其名稱通常為default。下面的命令顯示了default這個服務賬戶的詳細信息。

[root@k8s-master01 k8s-yaml]# kubectl describe serviceaccounts default -n default 
Name:                default
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   default-token-btlhc
Tokens:              default-token-btlhc
Events:              <none>

Kubernetes系統通過3個獨立的組件間相互協作實現了上面描述的Pod對象服務賬戶的自動化過程:ServiceAccount准入控制器、令牌控制器和ServiceAccount控制器。ServiceAccount控制器負責為名稱空間管理相應的資源對象,它需要確保每個名稱空間中都存在一個名為default的服務賬戶對象。ServiceAccount准入控制器內置在API Server中,負責在創建或更新Pod時按需進行ServiceAccount資源對象相關信息的修改。

▪若Pod沒有顯式定義使用的ServiceAccount對象,則將其設置為default。
▪若Pod顯式引用了ServiceAccount,則負責檢查被引用的對象是否存在,不存在時將拒絕Pod資源的創建請求。
▪若Pod中不包含ImagePullSecerts,則把ServiceAccount的ImagePullSecrets附加其上。
▪為帶有訪問API的令牌的Pod對象添加一個存儲卷。
▪為Pod對象中的每個容器添加一個volumeMounts,將ServiceAccount的存儲卷掛至/var/run/secrets/kubernetes.io/serviceaccount。

令牌控制器是控制平面組件Controller Manager中的一個專用控制器,它工作於異步模式,負責完成如下任務:

▪監控ServiceAccount的創建操作,並為其添加用於訪問API的Secret對象;
▪監控ServiceAccount的刪除操作,並刪除其相關的所有ServiceAccount令牌密鑰;
▪監控Secret對象的添加操作,確保其引用的ServiceAccount存在,並在必要時為Secret對象添加認證令牌;
▪監控Secret對象的刪除操作,以確保刪除每個ServiceAccount對此Secret的引用。

需要注意的是,為確保完整性等,必須為kube-controller-manager使用--service-account-private-key-file選項指定一個私鑰文件,用於對生成的ServiceAccount令牌進行簽名,該私鑰文件必須是PEM格式。同時,要使用--service-account-key-file為kube-apiserver指定與前面的私鑰配對的公鑰文件,實現在認證期間對認證令牌進行校驗。

2、ServiceAccount基礎應用

ServiceAccount是Kubernetes API上的一種資源類型,它屬於名稱空間級別,用於讓Pod對象內部的應用程序在與API Server通信時完成身份認證。同樣名為ServiceAccount的准入控制器實現了服務賬戶自動化,該准入控制器為每個名稱空間都自動生成了一個名為default的默認資源對象。 每個Pod對象可附加其所屬名稱空間中的一個ServiceAccount資源,且只能附加一個。不過,一個ServiceAccount資源可由其所屬名稱空間中的多個Pod對象共享使用。創建Pod資源時,用戶可使用spec.serviceAccountName屬性直接指定要使用的ServiceAccount對象,或者省略此字段而由准入控制器自動附加當前名稱空間中默認的ServiceAccount,以確保每個Pod對象至少基於該服務賬戶有權限讀取當前名稱空間中其他資源對象的元數據信息。 Kubernetes也支持用戶按需創建ServiceAccount資源並將其指定到特定應用的Pod對象之上,結合集群啟用的授權機制為該ServiceAccount資源賦予所需要的更多權限,從而構建出更加靈活的權限委派模型。

2.1 命令式ServiceAccount資源創建

kubectl create serviceaccount命令能夠快速創建自定義的ServiceAccount資源,我們僅需要在命令后給出目標ServiceAccount資源的名稱。

[root@k8s-master01 ~]# kubectl create serviceaccount my-sa
serviceaccount/my-sa created
[root@k8s-master01 ~]# kubectl get sa my-sa 
NAME    SECRETS   AGE
my-sa   1         48s

Kubernetes會為創建的ServiceAccount資源自動生成並附加一個Secret對象,該對象以ServiceAccount資源名稱為前綴,后面加token-隨機數的方式。

[root@k8s-master01 ~]# kubectl get secrets 
NAME                  TYPE                                  DATA   AGE
default-token-btlhc   kubernetes.io/service-account-token   3      15d
my-sa-token-5kw7c     kubernetes.io/service-account-token   3      95s

該Secret對象屬於特殊的kubernetes.io/service-account-token類型,它包含ca.crt、namespace和token這3個數據項,它們分別包含Kubernetes Root CA證書、Secret對象所屬的名稱空間和訪問API Server的token令牌。由Pod對象以Secret存儲卷的方式將該類型的Secret對象掛載至/var/run/secrets/kubernetes.io/serviceaccount目錄后,這3個數據項映射為同名的3個文件。

[root@k8s-master01 ~]# kubectl get secrets my-sa-token-5kw7c -o yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0......
  namespace: ZGVmYXVsdA==
  token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklqVkdSV......
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: my-sa
    kubernetes.io/service-account.uid: 07ce8903-29d5-456f-a0d4-5a7cf50c2527
  ......
  name: my-sa-token-5kw7c
  namespace: default
  resourceVersion: "2650574"
  uid: 9adfd7d5-1a3f-4cef-b8d5-2229f8cc3d8f
type: kubernetes.io/service-account-token

2.2 ServiceAccount資源清單

以資源規范形式創建Secret對象時,以類似如上命令結果的形式,為Secret對象使用資源注解kubernetes.io/service-account.name引用一個現存的ServiceAccount對象,並指定資源類型為特定的kubernetes.io/service-account-token,我們便可以將指定的ServiceAccount對象引用的Secret對象予以置換,該Secret對象同樣會自動生成固定的3個數據項。

完善地創建ServiceAccount資源的方式是使用資源規范,該規范比較簡單,它沒有spec字段,而是將幾個關鍵定義直接通過一級字段給出。

apiVersion: v1               # ServiceAccount所屬的API群組及版本
kind: ServiceAccount         # 資源類型標識
metadata:
  name <string>              # 資源名稱
  namespace <string>         # ServiceAccount是名稱空間級別的資源
automountServiceAccountToken <boolean>   # 是否讓Pod自動掛載API令牌
secrets <[]Object>           # 以該SA運行的Pod要使用的Secret對象所組成的列表
  apiVersion <string>        # 引用的Secret對象所屬的API群組及版本,可省略
  kind <string>              # 引用的資源類型,這里是指Secret,可省略
  name <string>              # 引用的Secret對象的名稱,通常僅給出該字段即可
  namespace <string>         # 引用的Secret對象所屬的名稱空間
  uid  <string>              # 引用的Secret對象的標識符
imagePullSecrets <[]Object>  # 引用的用於下載Pod中容器鏡像的Secret對象列表
  name <string>              # docker-registry類型的Secret資源名稱

serviceacceount實例

僅指定了資源名稱,以及允許Pod對象將其自動掛載為存儲卷,引用的Secret對象則交由系統自動生成。

[root@k8s-master01 k8s-yaml]# vim sa-demo.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: namespace-admin
  namespace: default
automountServiceAccountToken: true

將配置清單中定義的default-ns-admin資源創建到集群上,ServiceAccount控制器會自動為其附加以該資源名稱為前綴的Secret對象。隨后,用戶便可以在創建的Pod對象上引用該ServiceAccount對象,以借助權限管理機制實現自主控制Pod對象資源訪問權限。

[root@k8s-master01 k8s-yaml]# kubectl apply -f sa-demo.yaml 
serviceaccount/namespace-admin created
[root@k8s-master01 k8s-yaml]# kubectl get sa
NAME              SECRETS   AGE
default           1         15d
my-sa             1         15m
namespace-admin   1         74s
[root@k8s-master01 k8s-yaml]# kubectl get secrets 
NAME                          TYPE                                  DATA   AGE
default-token-btlhc           kubernetes.io/service-account-token   3      15d
my-sa-token-5kw7c             kubernetes.io/service-account-token   3      16m
namespace-admin-token-gqmrb   kubernetes.io/service-account-token   3      91s

另外,ServiceAccount資源還可以基於spec.imagePullSecret字段附帶一個由下載鏡像專用的Secret資源組成的列表,讓Pod對象在創建容器時且從私有鏡像倉庫下載鏡像文件之前完成身份認證。下面的示例定義了一個從本地私有鏡像倉庫Harbor下載鏡像文件時的Secret對象信息的ServiceAccount。

---
#定義harbor的賬號密碼在secret中
apiVersion: v1
kind: Secret
metadata:
  name: local-harbor-secret
type: Opaque
data:
  username: YWRtaW4= #harbor的賬號,使用base64加密
  password: MTIzNDU2 #harbor的密碼,使用base64加密
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: eshop-sa
  namespace: eshop
imagePullSecrets:
- name: local-harbor-secret #調用secret

其中,local-harbor-secret是docker-registry類型的Secret對象,包含目標Docker Registry的服務入口、用戶名、密碼及用戶的電子郵件等信息,它必須要由用戶提前手動創建。該Pod資源所在節點上的kubelet進程使用Secret對象中的令牌認證到目標Docker Registry,以下載運行容器所需要的鏡像文件。

2.3 Pod資源上的服務賬戶

借助權限分配模型,按需應用“最小權限法則”將不同的資源操作權限配置給不同的賬戶,是有效降低安全風險的法則之一。有相當一部分Kubernetes原生應用程序依賴的權限都會大於從Pod默認ServiceAccount繼承到的權限,且彼此間各有不同,為這類應用定制一個專用的ServiceAccount並授予所需的全部權限是主流的解決方案。

[root@k8s-master01 k8s-yaml]# vim pod-with-sa.yml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-sa
  namespace: default
spec:
  containers:
  - name: adminbox
    image: ikubernetes/admin-toolbox:v1.0
    imagePullPolicy: IfNotPresent
  serviceAccountName: namespace-admin  #調用前面創建的sa

該Pod資源創建完成后會以Secret存儲卷的形式自動掛載serviceaccounts/default-ns-admin的Secret對象

[root@k8s-master01 k8s-yaml]# kubectl apply -f pod-with-sa.yml 
pod/pod-with-sa created

[root@k8s-master01 k8s-yaml]# kubectl get pod
NAME          READY   STATUS    RESTARTS   AGE
pod-with-sa   1/1     Running   0          29s

[root@k8s-master01 k8s-yaml]# kubectl describe pod pod-with-sa 
Name:         pod-with-sa
Namespace:    default
......
Containers:
......
  Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from namespace-admin-token-gqmrb (ro)
......
Volumes:
  namespace-admin-token-gqmrb:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  namespace-admin-token-gqmrb
......  

Secret對象默認的掛載路徑是/var/run/secrets/kubernetes.io/serviceaccount。與API Server交互時,工作負載進程會使用該目錄下的ca.crt證書文件驗證API Server的服務器證書是否為自己信任的證書頒發機構(所在集群的kubernetes-ca)所簽發;驗證服務器身份成功通過后,工作負載向API Server請求操作namespace文件指定的名稱空間中的資源時,會將token文件中的令牌以承載令牌的認證方式提交給API Server進行驗證,權限校驗則由授權插件完成。

可在pods/pod-with-sa的交互式接口中進行訪問測試。

1)切換到pods/pod-with-sa的adminbox容器的Secret對象的掛載點為工作目錄以便於加載所需要的文件:

[root@k8s-master01 k8s-yaml]# kubectl exec -it pod-with-sa -- bash
[root@pod-with-sa /]$ ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt     namespace  token

2)在容器中使用curl命令向API Server發起訪問請求,--cacert選項用於指定驗證服務器端的CA證書,而-H選項用於自定義頭部,它指定了使用的承載令牌;下面的命令使用了“命令引用”機制來加載token和namespace文件的內容,其結果顯示容器進程使用指定的ServiceAccount進行身份認證成功。因為沒有授權所有該sa賬戶沒有該namespace下所有資源的操作權限。

[root@pod-with-sa /]$ cd /var/run/secrets/kubernetes.io/serviceaccount/ 
[root@pod-with-sa /var/run/secrets/kubernetes.io/serviceaccount]$ curl --cacert ./ca.crt -H "Authorization: Bearer $(cat ./token)"               https://kubernetes/api/v1/namespaces/$(cat ./namespace)/
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
    
  },
  "status": "Failure",
  "message": "namespaces \"default\" is forbidden: User \"system:serviceaccount:default:namespace-admin\" cannot get resource \"namespaces\" in API group \"\" in the namespace \"default\"",
  "reason": "Forbidden",
  "details": {
    "name": "default",
    "kind": "namespaces"
  },
  "code": 403

接下來,單獨向serviceaccount/namespace-admin授予default名稱空間的管理權限,pods/pod-with-sa中的進程便能借助該ServiceAccount的身份管理相應名稱空間下的資源.

1)切換至kubectl管理終端運行如下資源創建命令:

[root@k8s-master01 k8s-yaml]# kubectl create rolebinding namespace-admin-binding-admin --clusterrole=admin \
>      --serviceaccount=default:namespace-admin -n default
rolebinding.rbac.authorization.k8s.io/namespace-admin-binding-admin created

2)回到pods/pod-with-sa的adminbox容器中再次運行訪問測試命令即可驗證授權結果,如下命令表示namespace-admin用戶已然有權限訪問default名稱空間。事實上,它擁有該名稱空間中所有資源的CRUD權限。

[root@k8s-master01 k8s-yaml]# kubectl exec -it pod-with-sa -- bash
[root@pod-with-sa /]$
[root@pod-with-sa /]$ cd /var/run/secrets/kubernetes.io/serviceaccount/ 
[root@pod-with-sa /var/run/secrets/kubernetes.io/serviceaccount]$ curl --cacert ./ca.crt -H "Authorization: Bearer $(cat ./token)"  https://kubernetes/api/v1/namespaces/$(cat ./namespace)/
{
  "kind": "Namespace",
  "apiVersion": "v1",
  "metadata": {
    "name": "default",
    "uid": "84b5b410-0c48-4163-a0cb-0af27a941b32",
    "resourceVersion": "195",
    "creationTimestamp": "2021-04-23T02:20:54Z",
    "managedFields": [
      {
        "manager": "kube-apiserver",
        "operation": "Update",
        "apiVersion": "v1",
        "time": "2021-04-23T02:20:54Z",
        "fieldsType": "FieldsV1",
        "fieldsV1": {"f:status":{"f:phase":{}}}
      }
    ]
  },
  "spec": {
    "finalizers": [
      "kubernetes"
    ]
  },
  "status": {
    "phase": "Active"
  }
}
#授權后可以正常訪問該namespace下的資源

default名稱空間引用了serviceaccounts/default資源中Pod的容器進程卻不具有如上權限,因為它們並未獲得相應的授權。事實上,kube-system名稱空間中的許多應用都使用了專用的ServiceAccount資源,例如Flannel、CoreDNS、kube-proxy以及多種控制器等

三、 X509數字證書認證

X509數字證書認證常用的方式有“單向認證”和“雙向認證”。SSL / TLS最常見的應用場景是將X.509數字證書與服務器端關聯,但客戶端不使用證書。

單向認證是客戶端能夠驗證服務端的身份,但服務端無法驗證客戶端的身份,至少不能通過SSL / TLS協議進行。之所以如此,是因為SSL / TLS安全性最初是為互聯網應用開發,保護客戶端是高優先級的需求,它可以讓客戶端確保目標服務器不會被冒名頂替。

雙向認證的場景中,服務端與客戶端需各自配備一套數字證書,並擁有信任的簽證機構的證書列表。使用私有簽證機構頒發的數字證書時,除了證書管理和分發,通常還要依賴用戶手動將此私有簽證機構的證書添加到信任的簽證機構列表中。X509數字證書認證是Kubernetes默認使用的認證機制,采用雙向認證模式。

1、Kubernetes的X509數字證書認證體系

構建安全基礎通信環境的Kubernetes集群時,需要用到PKI基礎設施以完成獨立HTTPS安全通信及X509數字證書認證的場景有多種。API Server是整個Kubernetes集群的通信網關,controller-manager、scheduler、kubelet及kube-proxy等API Server的客戶端均需要經由API Server與etcd通信,完成資源狀態信息獲取及更新等。同樣出於安全通信的目的,Master的各組件(API Server、controller-manager和scheduler)需要基於SSL/TLS向外提供服務,而且與集群內部組件間通信時(主要是各節點上的kubelet和kube-proxy)還需要進行雙向身份驗證。

 

1.1 Kubernetes集群中的PKI設施與X509數字證書認證體系

Kubernetes集群中存在3個需要獨立完成X509數字證書認證和HTTPS通信的體系:一是etcd集群成員、服務器及其客戶端;二是API Server及其客戶端,以及kubelet API及其客戶端;三是Kubernetes認證代理體系中的服務器和客戶端。這3個獨立的體系各自需要一個獨立證書頒發機構為體系內的服務器和客戶端頒發證書,完成體系內的組件身份認證同時又彼此隔離。

kubernetes集群中的CA:

 

(1)etcd集群CA及相關的數字證書 Kubernetes的API Server將集群的狀態數據存儲到集群存儲服務etcd中,包括含有敏感數據的Secret資源對象。出於提升服務可用性、數據冗余及安全性等目的,生產環境通常應該配置有3、5或7個節點的etcd集群,集群內各節點間基於HTTPS協議進行通信,它們使用Peer類型的數字證書進行通信時的身份認證。而且,各etcd節點提供Server類型的數字證書與客戶端建立安全連接,並驗證其客戶端Client類型的數字證書。Kubernetes集群各組件中,kube-apiserver是唯一一個可直接與集群存儲通信的組件,它是etcd服務的客戶端。

(2)Kubernetes集群CA及相關的數字證書

Kubernetes集群的其他各組件均需要通過kube-apiserver訪問集群資源,同樣出於安全性等目的,API Server也要借助HTTPS協議與其客戶端通信,而X509雙向數字證書認證僅是API Server支持的認證方式中的一種,客戶端也可能會使用HTTP Basic或Bearer Token認證方式接入到API Server。

kubelet也通過HTTPS端點暴露了一組API,這些API提供了多個不同級別的敏感數據接口,並支持來自客戶端的請求在節點和容器上執行不同級別的操作。默認情況下,匿名請求將自動隸屬於system:unauthenticated用戶組,其用戶名為system:anonymous。不過,kubelet可使用--anonymous-auth=false選項拒絕匿名訪問,並通過--client-ca-file選項指定CA方式驗證客戶端身份。kubelet可直接使用kubernetes-ca,同時應該為kube-apiserver使用--kubelet-client-certificate和--kubelet-client-key選項指定認證到kubelet的客戶端證書與私鑰。

(3)認證代理服務體系CA及相關的數字證書

API Server支持將認證功能交由外部的其他認證服務代為完成,這些服務通過特定的響應頭部返回身份驗證的結果狀態,API Server擴展服務就是認證代理的最常見應用場景之一。

除了API Server提供的核心API,Kubernetes還支持通過聚合層(aggregation layer)對其進行擴展。簡單來說,聚合層允許管理員在群集中部署使用其他Kubernetes風格的API,例如service catalog或用戶自定義的API Server等。聚合層本身打包在kube-apiserver程序中,並作為進程的一部分運行,但僅在管理員通過指定的APIService對象注冊擴展資源之后,它才會代理轉發相應的請求。而APIService則會由運行在Kubernetes集群上的Pod中的extention-apiserver實現。

創建一個APIService資源時,作為注冊和發現過程的一部分,kube-aggregator控制器(位於kube-apiserver內部)將與extention-apiserver的HTTP2連接[1],而后將經過身份驗證的用戶請求經由此連接代理到extention-apiserver上,於是,kube-aggregator被設置為執行RequestHeader客戶端認證。 不過,只有kube-apiserver在啟動時使用了如下選項時,才能啟用其內置的聚合層:

▪--requestheader-client-ca-file=<path to aggregator CA cert>--requestheader-allowed-names=front-proxy-client
▪--requestheader-extra-headers-prefix=X-Remote-Extra---requestheader-group-headers=X-Remote-Group
▪--requestheader-username-headers=X-Remote-User
▪--proxy-client-cert-file=<path to aggregator proxy cert>--proxy-client-key-file=<path to aggregator proxy key>

proxy-client-cert-file和proxy-client-key-file包含kube-aggregator執行客戶端證書身份驗證的證書/密鑰對,它使用requestheader-client-ca-file中指定的CA文件對聚合器證書進行簽名。requestheader-allowed-names包含允許充當偽裝前端代理的身份/名稱列表(客戶端證書中使用的CN),而requestheader-username-headers、requestheader-group-headers和requestheader-extraheaders-prefix攜帶一個HTTP頭的列表,用於攜帶遠程用戶信息。

1.2 Kubernetes集群需要的數字證書

完整運行的Kubernetes系統需要為etcd、API Server及前端代理(front proxy)生成多個數字證書

 

另外,其他集群上運行的應用(Pod)同其客戶端的通信經由不可信的網絡傳輸時也可能需要用到TLS/SSL協議,例如Nginx Pod與其客戶端間的通信,客戶端來自於互聯網時,此處通常需配置一個公信的服務端證書。

普通用戶使用這種認證方式的前提是,它們各自擁有自己的數字證書,證書中的CN和O屬性分別提供了准確的用戶標識和用戶組。API Server可接受或拒絕這些證書,評估標准在於證書是否由API Server信任的客戶端證書CA(由選項--client-ca-file指定,默認為kubernetes-ca)所簽發,但API Server自身並不了解這些證書,因此也不了解各個用戶,它僅知道負責為各個客戶端頒發證書的CA。因此,相較於靜態密碼文件認證和靜態令牌文件認證來說,X509數字證書認證實現了用戶管理與Kubernetes集群的分離,且有着更好的安全性。

X509數字證書認證因其可不依賴第三方服務、有着更好的安全性以及與API Server相分離等優勢,成為Kubernetes系統內部默認使用的認證方式。但是,將X509數字證書用於普通用戶認證的缺陷也是顯而易見的,它主要表現在如下兩個方面。

▪證書的到期時間在頒發時設定,其生命周期往往很長(數月甚至數年),且事實上的身份驗證功能也是在頒發時完成,若撤銷用戶的可用身份只能使用證書吊銷功能完成。
▪現實使用中,證書通常由一些通用的簽證機構簽發,而API Server需要信任該CA;顯然,獲得該CA使用權限的用戶便能夠授予自己可認證到的Kubernetes的任意憑據或身份,因而集群管理員必須自行集中管理證書,管理員的工作量比較大。

對於大型組織來說,Kubernetes系統用戶量大且變動頻繁,靜態密碼文件和靜態令牌文件認證方式動輒需要重啟API Server,而X509認證中的證書維護開銷較高且無法靈活變動憑據生效期限,因此這些認證方式都非理想選擇。實踐中,人們通常使用ID Token進行Kubernetes的普通用戶身份認證,API Server的OpenID Connect令牌認證插件即用於該場景。

2、TLS Bootstrapping機制

TLS Bootstrapping機制有什么用途呢?

新的工作節點接入Kubernetes集群時需要事先配置好相關的證書和私鑰等以進行安全通信,管理員可以手動管理這些證書,也可以選擇由kubelet自行生成私鑰和自簽證書。集群略具規模后,第一種方式無疑會為管理員帶來不小的負擔,但對於保障集群安全運行卻又必不可少。第二種方式降低了管理員的工作量,卻也損失了PKI本身具有的諸多優勢。取而代之,Kubernetes采用了由kubelet自行生成私鑰和證書簽署請求,而后發送給集群上的證書簽署進程(CA),由管理員審核后予以簽署或直接由控制器進程自動統一簽署。這種方式就是kubelet TLS Bootstrapping機制,它實現了前述第一種方式的功能,卻基本不增加管理員工作量。

一旦開啟TLS Bootstrapping功能,任何kubelet進程都可以向API Server發起驗證請求並加入到集群中,包括那些非計划或非授權主機,這必將增大管理驗證操作時的審核工作量。為此,API Server設計了可經由--enable-bootstrap-token-auth選項啟用的Bootstrap Token(引導令牌)認證插件。該插件用於加強TLS Bootstrapping機制,僅那些通過Bootstrap Token認證的請求才可以使用TLS Bootstrapping發送證書簽署請求給控制平面,並由相應的審批控制器(approval controller)完成證書簽署和分發。

說明:
kubeadm啟用了節點加入集群時的證書自動簽署功能,因此加入過程在kubeadm join命令成功后即完成。

Kubelet會把簽署后的證書及配對的私鑰存儲到--cert-dir選項指定的目錄下,並以之生成kubeconfig格式的配置文件,該文件的保存路徑以--kubeconfig選項指定,它保存有API Server的地址以及認證憑據。若指定的kubeocnfig配置文件不存在,kubelet會轉而使用Bootstrap Token,從API Server自動請求完成TLS Bootstrapping過程。 kube-controller-manager內部有一個用於證書頒發的控制循環,它采用了類似於cfssl簽證器格式的自動簽證器,頒發的所有證書默認具有一年有效期限。正常使用中的Kubernetes集群需要在證書過期之前完成更新,以免集群服務不可用。較新版本的kubeadm部署工具已經能夠自動完成更新,如下第一條命令用於檢測證書有效期限,在接近過期時間的情況下,即可使用第二條命令進行更新。

~# kubeadm alpha certs check-expiration
~# kubeadm alpha certs renew all

Kubernetes 1.8之后的版本中使用的csrapproving審批控制器內置於kube-controller-manager,並且默認為啟用狀態。此審批控制器使用SubjectAccessview API確認給定的用戶是否有權限請求CSR(證書簽署請求),而后根據授權結果判定是否予以簽署。不過,為了避免同其他審批器沖突,內置的審批器並不顯式拒絕CSR,而只是忽略它們。

四、kubeconfig配置文件

基於無狀態協議HTTP/HTTPS的API Server需要驗證每次連接請求中的用戶身份,因而kube-controller-manager、kube-scheduler和kube-proxy等各類客戶端組件必須能自動完成身份認證信息的提交,但通過程序選項來提供這些信息會導致敏感信息泄露。另外,管理員還面臨着使用kubectl工具分別接入不同集群時的認證及認證信息映射難題。為此,Kubernetes設計了一種稱為kubeconfig的配置文件,它保存有接入一到多個Kubernetes集群的相關配置信息,並允許管理員按需在各配置間靈活切換。

 

客戶端程序可通過默認路徑、--kubeconfig選項或者KUBECONFIG環境變量自定義要加載的kubeconfig文件,從而能夠在每次的訪問請求中可認證到目標API Server。

1、kubeconfig文件格式

kubeconfig文件中,各集群的接入端點以列表形式定義在clusters配置段中,每個列表項代表一個Kubernetes集群,並擁有名稱標識;各身份認證信息(credentials)定義在users配置段中,每個列表項代表一個能夠認證到某Kubernetes集群的憑據。將身份憑據與集群分開定義以便復用,具體使用時還要以context(上下文)在二者之間按需建立映射關系,各context以列表形式定義在contexts配置段中,而當前使用的映射關系則定義在current-context配置段中。

 

使用kubeadm初始化Kubernetes集群過程中,在Master節點上生成的/etc/kubernetes/admin.conf文件就是一個kubeconfig格式的文件,它由kubeadm init命令自動生成,可由kubectl加載后接入當前集群的API Server。kubectl加載kubeconfig文件的默認路徑為$HOME/.kube/config,在kubeadm init命令初始化集群過程中有一個步驟便是將/etc/kubernetes/admin.conf復制為該默認搜索路徑上的文件。當然,我們也可以通過--kubeconfig選項或KUBECONFIG環境變量將其修改為其他路徑。

kubectl config view命令能打印kubeconfig文件的內容,下面的命令結果顯示了默認路徑下的文件配置,包括集群列表、用戶列表、上下文列表以及當前使用的上下文(current-context)等。

[root@k8s-master01 ~]# kubectl config view 
apiVersion: v1
#k8s的集群列表
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://192.168.32.201:6443
  name: cluster1
#上下文列表
contexts:
- context:
    cluster: cluster1
    user: admin
  name: context-cluster1-admin
#當前上下文列表
current-context: context-cluster1-admin
#用戶列表
kind: Config
preferences: {}
users:
- name: admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

用戶也可以在kubeconfig配置文件中按需自定義相關的配置信息,以實現使用不同的用戶賬戶接入集群等功能。kubeconfig是一個文本文件,盡管可以使用文本處理工具直接編輯它,但強烈建議用戶使用kubectl config及其子命令進行該文件的設定,以便利用其他自動進行語法檢測等額外功能。

kubectl config的常用子命令有如下幾項:

▪view:打印kubeconfig文件內容。
▪set-cluster:設定新的集群信息,以單獨的列表項保存於clusters配置段。
▪set-credentials:設置認證憑據,保存為users配置段的一個列表項。
▪set-context:設置新的上下文信息,保存為contexts配置段的一個列表項。
▪use-context:設定current-context配置段,確定當前以哪個用戶的身份接入到哪個集群之中。
▪delete-cluster:刪除clusters中指定的列表項。
▪delete-context:刪除contexts中指定的列表項。
▪get-clusters:獲取clusters中定義的集群列表。
▪get-contexts:獲取contexts中定義的上下文列表。

kubectl config命令的相關操作將針對加載的單個kubeconfig文件進行,它根據其優先級由高到低,依次搜索--kubeconfig選項指定的文件、KUBECONFIG環境變量指定的文件和默認的.HOME/.kube/config文件,以其中任何一種方式加載到配置文件后即可終止搜索過程。不過,kubectl config命令支持同時使用多個kubeconfig文件,以及將多個配置文件合並為一個。

2、自定義kubeconfig文件

一個完整kubeconfig配置的定義至少應該包括集群、身份憑據、上下文及當前上下文4項,但在保存有集群和身份憑據的現有kubeconfig文件基礎上添加新的上下文時,可能只需要提供身份憑據而復用已有的集群定義,具體的操作步驟要按實際情況進行判定。

2.1 基於靜態密碼文件認證

例如,我們下面嘗試創建一個新的kubeconfig文件,設定它使用此前定義的基於靜態密碼文件認證的ilinux用戶接入到現有的Kubernetes集群,該集群API Server的網絡端點為https://192.168.32.248:6443,相關的CA證書保存在Master節點上的/etc/kubernetes/pki/ca.crt文件中,而配置結果則使用--kubeconfig選項保存在當前用戶主目錄下的.kube/kube-dev.config文件中。

步驟1:添加集群配置,包括集群名稱、API Server URL和信任的CA的證書;clusters配置段中的各列表項名稱需要唯一。

kubeadm部署的k8s集群

[root@k8s-master01 ~]# kubectl config set-cluster kube-dev --embed-certs=true \
--certificate-authority=/etc/kubernetes/pki/ca.crt  \
--server="https://192.168.32.248:6443"  \
--kubeconfig=$HOME/.kube/kube-dev.config

步驟2:添加身份憑據,使用靜態密碼文件認證的客戶端提供用戶名和密碼即可。

[root@k8s-master01 ~]# kubectl config set-credentials ilinux \
--username=ilinux --password=ilinux@123 \
--kubeconfig=$HOME/.kube/kube-dev.config
User "ilinux" set.

步驟3:以用戶ilinux的身份憑據與kube-dev集群建立映射關系。

[root@k8s-master01 ~]# kubectl config set-context ilinux@kube-dev \
--cluster=kube-dev --user=ilinux \
--kubeconfig=$HOME/.kube/kube-dev.config
Context "ilinux@kube-dev" created.

步驟4:設置當前上下文為ilinux@kube-dev

[root@k8s-master01 ~]# kubectl config use-context ilinux@kube-dev --kubeconfig=$HOME/.kube/kube-dev.config
Switched to context "ilinux@cluster1".

步驟5:預覽kube-dev.config文件,確認其配置信息。

[root@k8s-master01 ~]#  kubectl config view --kubeconfig=$HOME/.kube/kube-dev.config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://192.168.32.248:6443
  name: kube-dev
contexts:
- context:
    cluster: kube-dev
    user: ilinux
  name: ilinux@kube-dev
current-context: ilinux@kube-dev
kind: Config
preferences: {}
users:
- name: ilinux
  user:
    password: ilinux@123
    username: ilinux

步驟6:使用該kubeconfig中的當前上下文進行測試訪問;該用戶僅被授權了default名稱空間的所有權限,因而不具有列出集群級別資源的權限,但能查看default名稱空間的狀態。

[root@k8s-master01 ~]#kubectl get namespaces --kubeconfig=$HOME/.kube/kube-dev.config
Error from server (Forbidden): namespaces is forbidden: User "ilinux" cannot list resource "namespaces" in API group "" at the cluster scope
~$ kubectl get namespaces/default --kubeconfig=$HOME/.kube/kube-dev.config
NAME       STATUS     AGE
default    Active     3d

#有時需要重新拷貝admin.conf文件
#[root@k8s-master01 ~]#cp /etc/kubernetes/admin.conf /root/.kube/config

上面的第6步確認了自定義配置中的ilinux用戶有效可用,它被API Server借助靜態密碼文件認證插件完成認證並標識為ilinux用戶,從而擁有該用戶的資源操作權限。為了進一步測試並了解kubeconfig的使用格式,下面把基於令牌文件認證的ik8s用戶添加進同一個kubeconfig文件中。ik8s用戶同ilinux用戶位於同一集群上,因此,我們可省略添加集群的步驟而直接復用它。

步驟7:添加身份憑據,使用靜態令牌文件認證的客戶端認證時只需要提供靜態令牌信息

~$ TOKEN=$(sudo awk -F "," '$2=="ik8s"{print $1}' /etc/kubernetes/authfiles/token.csv)
~$ kubectl config set-credentials ik8s --token="$TOKEN" \
      --kubeconfig=$HOME/.kube/kube-dev.config
User "ik8s" set.

步驟8:為用戶ik8s的身份憑據與kube-dev集群建立映射關系。

~$ kubectl config set-context ik8s@kube-dev \
    --cluster=kube-dev --user=ik8s \
    --kubeconfig=$HOME/.kube/kube-dev.config
Context "ik8s@kube-dev" created.

步驟9:將當前上下文切換為ik8s@kube-dev。

~$ kubectl config use-context ik8s@kube-dev --kubeconfig=$HOME/.kube/kube-dev.config
Switched to context "ik8s@kube-dev".

步驟10:預覽kube-dev.config文件,確認ik8s用戶相關的各項配置信息。

$ kubectl config view --kubeconfig=$HOME/.kube/kube-dev.config

步驟11:依舊使用當前上下文發起集群訪問測試,ik8s用戶未獲得任何授權,但它能夠被系統識別為ik8s用戶,這表示身份認證請求成功返回;我們這次使用kubectl的whoami插件進行測試:

~ $ kubectl whoami --kubeconfig=$HOME/.kube/kube-dev.config
ik8s
說明:
事實上除了靜態令牌,客戶端認證到API Server的各種令牌都可以使用前面的這種方式添加到kubeconfig文件中,包括ServiceAccount令牌、OpenID Connnect令牌和Bootstrap令牌等。

當kubectl引用了擁有兩個及以上context的kubeconfig文件時,可隨時通過kubectl config use-context命令在不同上下文之間切換,它們可能使用不同的身份憑據接入相同的集群或不同的集群之上。如下命令結果表示當前加載的配置文件中共有兩個context,而擁有星號標識的是當前使用的context,即current-context。

~ kubectl config get-contexts --kubeconfig=HOME/.kube/kube-dev.config
CURRENT   NAME               CLUSTER    AUTHINFO   NAMESPACE

- ik8s@kube-dev      kube-dev   ik8s       
ilinux@kube-dev    kube-dev   ilinux

實踐中,API Server支持的X509數字證書認證和OpenID Connect令牌認證才是客戶端使用最多的認證方式.

2.2 X509數字證書身份憑據

kubeadm部署Kubernetes集群的過程中會自動生成多個kubeconfig文件,它們是默認位於/etc/kubernetes目錄下以.conf為后綴名的文件,前綴名稱代表了它的適用場景,其中的admin.conf中保存了以X509數字證書格式提供身份憑據的kubernetes-admin用戶,該用戶能夠以管理員的身份對當前集群發起資源操作請求。

由kubeadm初始化的Kubernetes集群上,kube-apiserver默認信任的CA就是集群自己的kubernetes-ca,該CA的數字證書是Master節點之上的/etc/kubernetes/pki/ca.crt文件。於是,客戶端按需生成證書簽署請求,再由管理員通過kubernetes-ca為客戶端簽署證書,便可讓客戶端以其證書中的CN為用戶名認證到API Server上。為了便於說明問題,下面將客戶端生成私鑰和證書簽署請求,服務器簽署該請求,以及客戶端將證書配置為kubeconfig文件的步驟統一進行說明,所有操作都在Master節點上運行。

步驟1:以客戶端的身份,生成目標用戶賬號mason的私鑰及證書簽署請求,保存在用戶主目錄下的.certs目錄中。

① 生成私鑰文件,注意其權限應該為600以阻止其他用戶讀取。

[root@k8s-master01 ~]# mkdir $HOME/.certs
[root@k8s-master01 ~]# (umask 077; openssl genrsa -out $HOME/.certs/mason.key 2048)
Generating RSA private key, 2048 bit long modulus
.............................................+++
...............................+++
e is 65537 (0x10001)

② 創建證書簽署請求,-subj選項中CN的值將被API Server識別為用戶名,O的值將被識別為用戶組。

[root@k8s-master01 ~]# openssl req -new -key $HOME/.certs/mason.key \
     -out $HOME/.certs/mason.csr \
     -subj "/CN=mason/O=developers"

步驟2:以kubernetes-ca的身份簽署ikubernetes的證書請求,這里直接讀取相關的CSR文件,並將簽署后的證書仍然保存在當前系統用戶主目錄下的.certs中。

① 基於kubernetes-ca簽署證書,並為其設置合理的生效時長,例如365天。

[root@k8s-master01 ~]# openssl x509 -req -days 365 -CA /etc/kubernetes/pki/ca.crt \
 -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial \
 -in $HOME/.certs/mason.csr -out $HOME/.certs/mason.crt
Signature ok
subject=/CN=mason/O=developers
Getting CA Private Key

② 必要時,還可以驗證生成的數字證書的相關信息(可選)。

[root@k8s-master01 ~]# openssl x509 -in $HOME/.certs/mason.crt -text -noout

步驟3:以ikubernetes的身份憑據生成kubeconfig配置,將其保存在kubectl默認搜索路徑指向的$HOME/.kube/config文件中。另外,因指向當前集群的配置項已經存在,即位於clusters配置段中的kubernetes,這里直接復用該集群定義。

① 根據X509數字證書及私鑰創建身份憑據,列表項名稱同目標用戶名。

[root@k8s-master01 ~]# kubectl config set-credentials mason --embed-certs=true \
       --client-certificate=$HOME/.certs/mason.crt \
       --client-key=$HOME/.certs/mason.key    
User "mason" set.

② 配置context,以mason的身份憑據訪問已定義的Kubernetes集群,該context的名稱為mason@kubernetes。

[root@k8s-master01 ~]# kubectl config set-context mason@kubernetes --cluster=kubernetes --user=mason
Context "mason@kubernetes" created.

③ 將當前上下文切換為mason@kubernetes,或直接在kubectl命令上使用“--context= 'mason@kubernetes'”以完成該用戶的認證測試,下面的命令選擇了以第二種方式進行認證,雖然提示權限錯誤,但mason用戶已被API Server正確識別;

[root@k8s-master01 ~]# kubectl get namespaces/default --context='mason@kubernetes'
Error from server (Forbidden): namespaces "default" is forbidden: User "mason" cannot get resource "namespaces" in API group "" in the namespace "default"

通過創建自定義的數字證書,實現了將mason用戶認證到API Server,並將該用戶的身份憑據保存至kubeconfig文件中。還沒有給該用戶授權。

3、多kubeconfig文件與合並

kubectl config一次僅能使用單個kubeconfig文件。事實上,若將兩個文件路徑以冒號分隔並賦值給KUBECONFIG環境變量,也能夠讓kubectl config一次加載多個文件信息,優先級由高到低為各文件自左而右的次序。下面兩條命令的結果顯示,左側文件擁有較高的優先級,因而其配置的current-context成為默認使用的context。

[root@k8s-master01 ~]# export KUBECONFIG="$HOME/.kube/config:$HOME/.kube/kube-dev.config"
[root@k8s-master01 ~]# kubectl config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
          ilinux@kube-dev               kube-dev     ilinux             
*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   
          mason@kubernetes              kubernetes   mason              

聯合使用多個kubeconfig時,同樣可以按需調整當前使用的context,其實現方式同使用單個kubeconfig文件並沒有不同之處。

[root@k8s-master01 ~]# kubectl config use-context mason@kubernetes
Switched to context "mason@kubernetes".
[root@k8s-master01 ~]# kubectl config get-contexts 
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
          ilinux@kube-dev               kube-dev     ilinux             
          kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   
*         mason@kubernetes              kubernetes   mason     

kubectl config view命令會將多個配置文件的內容按給定的次序連接並輸出,其風格類似於Linux系統的cat命令。但我們也能夠在view命令中將加載的多個配置文件展平為單個配置文件的格式予以輸出,並將結果保存在指定路徑下便能將多個kubeconfig文件合並為一。例如,下面的命令便將KUBECONFIG環境變量中指定的兩個kubeconfig文件合並成了單個配置文件。

[root@k8s-master01 ~]#kubectl config view --merge --flatten  > $HOME/.kube/kube.config

此時,切換kubectl config加載新生成的kubeconfig配置文件,它便直接擁有了此前兩個文件中定義的所有信息,且current-context亦遵循此前命令中的設定,即mason@kubernetes。

[root@k8s-master01 ~]# KUBECONFIG="$HOME/.kube/kube.config"
[root@k8s-master01 ~]# kubectl config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
          ilinux@kube-dev               kube-dev     ilinux             
          kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   
*         mason@kubernetes              kubernetes   mason      

4、為指定用戶配置apiserver訪問認證

4.1 生成私鑰和證書簽署請求

① 生成私鑰文件,注意其權限應該為600以阻止其他用戶讀取。

[root@k8s-master01 ~]# mkdir $HOME/.certs
[root@k8s-master01 ~]# (umask 077; openssl genrsa -out $HOME/.certs/mason.key 2048)
Generating RSA private key, 2048 bit long modulus
.............................................+++
...............................+++
e is 65537 (0x10001)

② 創建證書簽署請求,-subj選項中CN的值將被API Server識別為用戶名,O的值將被識別為用戶組。

[root@k8s-master01 ~]# openssl req -new -key $HOME/.certs/mason.key \
     -out $HOME/.certs/mason.csr \
     -subj "/CN=mason/O=developers"

4.2 以kubernetes-ca的身份簽署請求證書

基於kubernetes-ca簽署證書,並為其設置合理的生效時長,例如365天。

[root@k8s-master01 ~]# openssl x509 -req -days 365 -CA /etc/kubernetes/pki/ca.crt \
 -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial \
 -in $HOME/.certs/mason.csr -out $HOME/.certs/mason.crt
Signature ok
subject=/CN=mason/O=developers
Getting CA Private Key

4.3 生成mason-kube.config

以ikubernetes的身份憑據生成kubeconfig配置,將其保存在kubectl默認搜索路徑指向的$HOME/.kube/mason-kube.config文件中。另外,因指向當前集群的配置項已經存在,即位於clusters配置段中的kubernetes,這里直接復用該集群定義。

① 生成kubeconfig授權文件:

[root@k8s-master01 ~]#kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=https://192.168.32.248:6443 \
--kubeconfig=$HOME/.kube/mason-kube.config

② 設置客戶端認證

[root@k8s-master01 ~]#kubectl config set-credentials mason \
--client-key=$HOME/.certs/mason.key \
--client-certificate=$HOME/.certs/mason.crt \
--embed-certs=true \
--kubeconfig=$HOME/.kube/mason-kube.config

③配置context,以mason的身份憑據訪問已定義的Kubernetes集群,該context的名稱為mason@kubernetes。

[root@k8s-master01 ~]#kubectl config set-context mason@kubernetes \
--cluster=kubernetes \
--user=mason \
--kubeconfig=$HOME/.kube/mason-kube.config

④切換當前上下文

[root@k8s-master01 ~]# kubectl config use-context mason@kubernetes --kubeconfig=$HOME/.kube/mason-kube.config

⑤直接在kubectl命令上使用“--context= 'mason@kubernetes'”以完成該用戶的認證測試,下面的命令選擇了以第二種方式進行認證,雖然提示權限錯誤,但mason用戶已被API Server正確識別。

[root@k8s-master01 .kube]# kubectl get ns --kubeconfig=$HOME/.kube/mason-kube.config
Error from server (Forbidden): namespaces is forbidden: User "mason" cannot list resource "namespaces" in API group "" at the cluster scope

 

五、基於角色的訪問控制:RBAC

DAC(自主訪問控制)、MAC(強制訪問控制)、RBAC(基於角色的訪問控制)和ABAC(基於屬性的訪問控制)這4種主流的權限管理模型中,Kubernetes支持使用后兩種完成普通賬戶和服務賬戶的權限管理,另外支持的權限管理模型還有Node和Webhook兩種。

RBAC是一種新型、靈活且使用廣泛的訪問控制機制,它將權限授予角色,通過讓“用戶”扮演一到多個“角色”完成靈活的權限管理,這有別於傳統訪問控制機制中將權限直接賦予使用者的方式。相對於Kubernetes支持的ABAC和Webhook等授權機制,RBAC具有如下優勢:

▪對集群中的資源和非資源型URL的權限實現了完整覆蓋。
▪整個RBAC完全由少數幾個API對象實現,而且與其他API對象一樣可以用kubectl或API調用進行操作。
▪支持權限的運行時調整,無須重新啟動API Server。

1、RBAC授權模型

RBAC是一種特定的權限管理模型,它把可以施加在“資源對象”上的“動作”稱為“許可權限”,這些許可權限能夠按需組合在一起構建出“角色”及其職能,並通過為“用戶賬戶或組賬戶”分配一到多個角色完成權限委派。這些能夠發出動作的用戶在RBAC中也稱為“主體”。

RBAC中用戶、角色與權限之間的關系:

 

RBAC訪問控制模型中,授權操作只能通過角色完成,主體只有在分配到角色之后才能行使權限,且僅限於從其綁定的各角色之上繼承而來的權限。換句話說,用戶的權限僅能夠通過角色分配獲得,未能得到顯式角色委派的用戶則不具有任何權限。

簡單來說,RBAC就是一種訪問控制模型,它以角色為中心界定“誰”(subject)能夠“操作”(verb)哪個或哪類“對象”(object)。動作的發出者即“主體”,通常以“賬號”為載體,在Kubernetes系統上,它可以是普通賬戶,也可以是服務賬戶。“動作”用於表明要執行的具體操作,包括創建、刪除、修改和查看等行為,對於API Server來說,即PUT、POST、DELETE和GET等請求方法。而“對象”則是指管理操作能夠施加的目標實體,對Kubernetes API來說主要指各類資源對象以及非資源型URL。 API Server是RESTful風格的API,各類客戶端由認證插件完成身份驗證,而后通過HTTP協議的請求方法指定對目標對象的操作請求,並由授權插件進行授權檢查,而操作的對象則是URL路徑指定的REST資源。

 

Kubernetes系統上的普通賬戶或服務賬戶向API Server發起資源操作請求,並以相應HTTP方法承載,如下圖所示,由運行在API Server之上的授權插件RBAC進行鑒權。

 

2、Role、RoleBinding、ClusterRole和ClusterRoleBinding

Kubernetes系統的RBAC授權插件將角色分為Role和ClusterRole兩類,它們都是Kubernetes內置支持的API資源類型,其中Role作用於名稱空間級別,用於承載名稱空間內的資源權限集合,而ClusterRole則能夠同時承載名稱空間和集群級別的資源權限集合。Role無法承載集群級別的資源類型的操作權限,這類的資源包括集群級別的資源(例如Nodes)、非資源類型的端點(例如/healthz),以及作用於所有名稱空間的資源(例如跨名稱空間獲取任何資源的權限)等。 利用Role和ClusterRole兩類角色進行賦權時,需要用到另外兩種資源RoleBinding和ClusterRoleBinding,它們同樣是由API Server內置支持的資源類型。RoleBinding用於將Role綁定到一個或一組用戶之上,它隸屬於且僅能作用於其所在的單個名稱空間。RoleBinding可以引用同一名稱中的Role,也可以引用集群級別的ClusterRole,但引用ClusterRole的許可權限會降級到僅能在RoleBinding所在的名稱空間生效。而ClusterRoleBinding則用於將ClusterRole綁定到用戶或組,它作用於集群全局,且僅能夠引用ClusterRole。

 

全局作用范圍的User2因通過A名稱空間中的RoleBinding關聯至Role-A上,因而它僅能在NamespaceA名稱空間中發揮作用。名稱空間B中的ServiceAccount1通過RoleBinding關聯至集群級別的ClusterRole-M上,對該賬戶來說,ClusterRole-M上的操作權限也僅限於該名稱空間。全局級別的用戶User1通過ClusterRoleBindig關聯到ClusterRole-M,因而,該用戶將在集群級別行使該角色的權限。

Kubernetes集群用戶大體規划為集群管理員、名稱空間管理員和用戶(通常為開發人員)3類。

▪集群管理員可以創建、讀取、更新和刪除任何策略對象,能夠創建命名空間並將其分配給名稱空間管理員;此角色適用於在整個集群中管理所有租戶或項目的管理員。
▪名稱空間管理員可以管理其名稱空間中的用戶,此角色適用於特定單一租戶或項目的管理員。
▪開發者用戶可以創建、讀取、更新和刪除名稱空間內的非策略對象,如Pod、Job和Ingress等,但只在它們有權訪問的名稱空間中擁有這些權限。

另外,有些特殊的應用程序可能還會需要一些比較特殊的權限集合,例如集群或名稱空間級別的只讀權限等,我們可以在必要時按需定義這些較為特別的角色。

2.1 、Role與ClusterRole

Role和ClusterRole是API Server內置的兩種資源類型,它們在本質上都只是一組許可權限的集合。Role和ClusterRole的資源規范完全相同,該規范沒有使用spec字段,而是直接使用rules字段嵌套授權規則列表。規則的基本要素是動作(verb)和相關的目標資源,后者支持指定一個或多個資源類型、特定資源類型下的單個或多個具體的資源,以及非資源類型的URL等。在Role和ClusterRole資源上定義的rules也稱為PolicyRule,即策略規則,它可以內嵌的字段有如下幾個。

1)apiGroups <[]string>:目標資源的API群組名稱,支持列表格式指定多個組,空值("")表示核心群組。
2)resources <[]string>:規則應用的目標資源類型,例如pods、services、deployments和daemonsets等,未同時使用resourceNames字段時,表示指定類型下的所有資源。ResourceAll表示所有資源。
3)resourceNames <[]string>:可選字段,指定操作適用的具體目標資源名稱。
4)nonResourceURLs <[]string>:用於定義用戶有權限訪問的網址列表,它並非名稱空間級別的資源,因此只能應用於ClusterRole,Role支持此字段僅是為了格式上的兼容;該字段在一條規則中與resources和resourceNames互斥。
5)verbs <[]string>:可應用在此規則匹配到的所有資源類型的操作列表,可用選項有get、list、create、update、patch、watch、proxy、redirect、delete和deletecollection;此為必選字段。

下面的配置清單示例(pods-reader-rbac.yaml)在default名稱空間中定義了一個名稱為Role的資源,它設定了讀取、列出及監視pods和services資源,以及pods/log子資源的許可權限。

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pods-reader
rules:
- apiGroups: [""]   # "" 表示核心API群組
  resources: ["pods", "services", "pods/log"] #資源對象
  verbs: ["get", "list", "watch"] #授權

絕大多數資源可通過其資源類型的名稱引用,例如pods或services等,這些名稱與它們在API endpoint中的形式相同。另外,有些資源類型支持子資源,例如Pod對象的/log,Node對象的/status等,它們在API Server上的URL形如下面的表示格式。

/api/v1/namespaces/{namespace}/pods/{name}/log

RBAC角色引用這種類型的子資源時需要使用resource/subresource的格式,例如上面示例規則中的pods/log。另外,還可以通過直接給定資源名稱(resourceName)來引用特定的資源,僅支持get、delete、update和patch等。

ClusterRole資源隸屬於集群級別,它引用名稱空間級別的資源意味着相關的操作權限能夠在所有名稱空間生效,同時,它也能夠引用Role所不支持的集群級別的資源類型,例如nodes和persistentvolumes等。下面的清單示例(nodes-admin-rbac.yaml)定義了ClusterRole資源nodes-admin,它擁有管理集群節點信息的權限。ClusterRole不屬於名稱空間,所以其配置不能夠使用metadata.namespace字段。

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nodes-admin
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["*"]

將上面兩個清單中分別定義的Role和ClusterRole資源創建到集群上,以便按需調用並驗證其權限。

[root@k8s-master01 apps]# kubectl apply -f pods-reader-rbac.yaml -f nodes-admin-rbac.yaml 
role.rbac.authorization.k8s.io/pods-reader created
clusterrole.rbac.authorization.k8s.io/nodes-admin created

Role或ClusterRole資源的詳細描述能夠以比較直觀的方式打印相關的規則定義,由kubectl describe roles/pods-reader clusterroles/nodes-admin命令輸出的規則定義。

[root@k8s-master01 apps]# kubectl describe roles pods-reader
Name:         pods-reader
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  pods/log   []                 []              [get list watch]
  pods       []                 []              [get list watch]
  service    []                 []              [get list watch]

[root@k8s-master01 apps]# kubectl describe clusterroles nodes-admin
Name:         nodes-admin
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  nodes      []                 []              [*]

kubectl命令也分別提供了創建Role和ClusterRole資源的命令式命令,create role和create clusterrole,它們支持如下幾個關鍵選項。

▪--verb:指定可施加於目標資源的動作,支持以逗號分隔的列表值,也支持重復使用該選項分別指定不同的動作,例如--verb=get,list,watch,或者--verb=get --verb=list --verb=watch。
▪--resource:指定目標資源類型,使用格式類似於--verb選項。
▪--resource-name:指定目標資源,使用格式類似於--verb選項。
▪--non-resource-url:指定非資源類型的URL,使用格式類似於--verb選項,但僅適用於clusterrole資源。

例如,下面的第一條命令創建了dev名稱空間,第二條命令在該名稱空間創建了一個具有所有資源管理權限的roles/admin資源,第三條命令則創建了一個有PVC和PV資源管理權限的clusterroles/pv-admin資源。

[root@k8s-master01 ~]# kubectl create namespace dev 
namespace/dev created
[root@k8s-master01 ~]# kubectl create role admin -n dev --resource="*.*" \
       --verb="get,list,watch,create,delete,deletecollection,patch,update"
role.rbac.authorization.k8s.io/admin created

[root@k8s-master01 ~]# kubectl create clusterrole pv-admin --verb="*" \
       --resource="persistentvolumeclaims,persistentvolumes"
clusterrole.rbac.authorization.k8s.io/pv-admin created

Role或ClusterRole對象本身並不能作為動作的執行主體,它們需要“綁定”到主體(例如User、Group或Service Account)之上完成賦權,而后由相應主體執行資源操作。

2.2 RoleBinding與ClusterRoleBinding

RoleBinding負責在名稱空間級別向普通賬戶、服務賬戶或組分配Role或ClusterRole,而ClusterRoleBinding則只能用於在集群級別分配ClusterRole。但二者的配置規范格式完全相同,它們沒有spec字段,直接使用subjects和roleRef兩個嵌套的字段。其中,subjects的值是一個對象列表,用於給出要綁定的主體,而roleRef的值是單個對象,用於指定要綁定的Role或ClusterRole資源。

subjects字段的可嵌套字段如下:

▪apiGroup <string>:要引用的主體所屬的API群組,對於ServiceAccount類的主體來說默認為"",而User和Group類主體的默認值為"rbac.authorization.k8s.io"。
▪kind <string>:要引用的資源對象(主體)所屬的類別,可用值為User、Group和ServiceAccount,必選字段。
▪name <string>:引用的主體的名稱,必選字段。
▪namespace <string>:引用的主體所屬的名稱空間,對於非名稱空間類型的主體,例如User和Group,其值必須為空,否則授權插件將返回錯誤信息。

roleRef的可嵌套字段如下:

▪apiGroup <string>:引用的資源(Role或ClusterRole)所屬的API群組,必選字段。
▪kind <string>:引用的資源所屬的類別,可用值為Role或ClusterRole,必選字段。
▪name <string>:引用的資源(Role或ClusterRole)的名稱。

需要注意的是,RoleBinding僅能夠引用同一名稱空間中的Role資源。

例如下面配置清單中的RoleBindings在dev名稱空間中把admin角色分配給前面配置的用戶mason,從而mason擁有了此角色之上的所有許可授權。

配置role角色admin

[root@k8s-master01 ~]# kubectl create namespace dev 
namespace/dev created
[root@k8s-master01 ~]# kubectl create role admin -n dev --resource="*.*" \
       --verb="get,list,watch,create,delete,deletecollection,patch,update"
role.rbac.authorization.k8s.io/admin created

[root@k8s-master01 apps]# kubectl describe roles admin -n dev
Name:         admin
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  *.*        []                 []              [get list watch create delete deletecollection patch update]

將role角色admin與普通用戶mason綁定

[root@k8s-master01 apps]# vim mason-rolebindings.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: mason-admin
  namespace: dev
subjects:
- kind: User
  name: mason
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: admin
  apiGroup: rbac.authorization.k8s.io

在綁定role角色之前,mason用戶無法在dev命名空間下創建pod

[root@k8s-master01 apps]# kubectl run demoapp --image="ikubernetes/demoapp:v1.0" -n dev --kubeconfig=/root/.kube/mason-kube.config
Error from server (Forbidden): pods is forbidden: User "mason" cannot create resource "pods" in API group "" in the namespace "dev"

示例中的RoleBinding資源mason-admin創建到集群上,便能夠以該用戶的身份測試其繼承而來的權限是否已然生效。下面以--config選項臨時將用戶切換為mason進行資源管理,測試命令及結果顯示,mason已然具有dev名稱空間下的資源操作權限。

[root@k8s-master01 apps]# kubectl apply -f mason-rolebindings.yaml 
rolebinding.rbac.authorization.k8s.io/mason-admin created

[root@k8s-master01 apps]# kubectl run demoapp --image="ikubernetes/demoapp:v1.0" -n dev --kubeconfig=/root/.kube/mason-kube.config
pod/demoapp created

[root@k8s-master01 apps]# kubectl get pods -n dev --kubeconfig=/root/.kube/mason-kube.config
NAME      READY   STATUS    RESTARTS   AGE
demoapp   1/1     Running   0          11s

[root@k8s-master01 apps]# kubectl delete pods demoapp -n dev --kubeconfig=/root/.kube/mason-kube.config
pod "demoapp" deleted

RoleBinding也能夠為主體分配集群角色,但它僅能賦予主體訪問RoleBinding資源本身所在的名稱空間之內的、由ClusterRole所持有的權限。例如,對於具有PVC和PV管理權限的clusterroles/pv-admin來說,在dev名稱空間中使用RoleBinding將其分配給用戶mason,意味着mason僅對dev名稱空間下的PVC資源具有管理權限,它無法繼承clusterroles/pv-admin除dev名稱空間之外的其他名稱空間中的PVC管理權限,更不能繼承集群級別資源PV的任何權限。

一種高效分配權限的做法是,由集群管理員在集群范圍預先定義好一組具有名稱空間級別資源權限的ClusterRole資源,而后由RoleBinding分別在不同名稱空間中引用它們,從而在多個名稱空間向不同用戶授予RoleBinding所有名稱空間下的相同權限。

Role和RoleBinding是名稱空間級別的資源,它們僅能用於完成單個名稱空間內的訪問控制,需要賦予某主體多個名稱空間中的訪問權限時就不得不在各名稱空間分別進行。若需要完成集群全局的資源管理授權,或者希望資源操作能夠針對Nodes、Namespaces和PersistentVolumes等集群級別的資源進行,或者針對/api、/apis、/healthz或/version等非資源型URL路徑進行,就需要使用ClusterRoleBinding。

說明;nonResourceURLs資源僅支持get訪問權限。

下面的配置清單示例(rolebinding-and-clusterrolebinding-rbac.yaml)中,rolebinding/mason-pvc-admin資源位於dev名稱空間,它使用RoleBinding為用戶mason分配了pv-admin這一集群角色,而clusterrolebinding/ik8s-pv-admin隸屬集群級別,它使用ClusterRoleBinding為ik8s分配了pv-admin這一集群。

[root@k8s-master01 apps]#vim rolebinding-and-clusterrolebinding-rbac.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: mason-pvc-admin
  namespace: dev
subjects:
- kind: User
  name: mason
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: pv-admin
  apiGroup: rbac.authorization.k8s.io
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ik8s-pv-admin
subjects:
- kind: User
  name: ik8s
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: pv-admin
  apiGroup: rbac.authorization.k8s.io

運行rolebinding-and-clusterrolebinding-rbac.yaml

[root@k8s-master01 apps]# kubectl apply -f rolebinding-and-clusterrolebinding-rbac.yaml 
rolebinding.rbac.authorization.k8s.io/mason-pvc-admin created
clusterrolebinding.rbac.authorization.k8s.io/ik8s-pv-admin created

我們使用mason用戶進行測試,它僅能訪問dev名稱空間下的名稱空間級別的PVC資源,且無法通過RoleBinding從clusterroles/pv-admin繼承指定名稱空間之外的任何權限,如下面的命令及結果所示。

[root@k8s-master01 apps]# kubectl get pvc -n dev --kubeconfig=/root/.kube/mason-kube.config
No resources found in dev namespace.

[root@k8s-master01 apps]# kubectl get pv -n dev --kubeconfig=/root/.kube/mason-kube.config
Error from server (Forbidden): persistentvolumes is forbidden: User "mason" cannot list resource "persistentvolumes" in API group "" at the cluster scope

[root@k8s-master01 apps]# kubectl get pv -n default --kubeconfig=/root/.kube/mason-kube.config
Error from server (Forbidden): persistentvolumes is forbidden: User "mason" cannot list resource "persistentvolumes" in API group "" at the cluster scope

[root@k8s-master01 apps]# kubectl get pvc -n default --kubeconfig=/root/.kube/mason-kube.config
Error from server (Forbidden): persistentvolumeclaims is forbidden: User "mason" cannot list resource "persistentvolumeclaims" in API group "" in the namespace "default"

使用ik8s用戶進行測試,它通過ClusterRoleBinding從clusterroles/pv-admin繼承了該集群角色的所有授權,如下面的命令及結果所示。

[root@k8s-master01 apps]# kubectl get pvc -n default --context="ik8s@kube-dev"   
No resources found in default namespace.
[root@k8s-master01 apps]# kubectl get pvc -n dev --context="ik8s@kube-dev"    
No resources found in dev namespace.
[root@k8s-master01 apps]# kubectl get pv --context="ik8s@kube-dev"        
No resources found in default namespace.

kubectl也提供了分別創建RoleBinding和ClusterRoleBinding資源的命令式命令:create rolebinding和create clusterrolebinding,它們使用的選項基本相同,常用的選項如下。

▪--role="":綁定的角色,僅RoleBinding支持。
▪--clusterrole="":綁定的集群角色,RoleBinding和ClusterRoleBinding均支持。
▪--group=[]:綁定的組,支持逗號分隔的列表格式。
▪--user=[]:綁定的普通賬戶,支持逗號分隔的列表格式。
▪--serviceaccount=[]:綁定的服務賬戶,支持逗號分隔的列表格式。

下面的命令為用戶組kubeusers分配了集群角色nodes-admin,從而該組的所有用戶均自動繼承該角色上的所有許可權限。

[root@k8s-master01 apps]#kubectl create clusterrolebinding kubeusers-nodes-admin \
      --clusterrole='nodes-admin' --group='kubeusers'
clusterrolebinding.rbac.authorization.k8s.io/kubeusers-nodes-admin created

3、聚合型ClusterRole

Kubernetes自1.9版本開始支持在ClusterRole的rules字段中嵌套aggregationRule字段來整合其他ClusterRole資源的規則,這種類型的ClusterRole對象的實際可用權限受控於控制器,具體許可授權由所有被標簽選擇器匹配到的ClusterRole的聚合授權規則合並生成。 下面的配置清單中首先定義了兩個擁有標簽的集群角色global-resources-view和global-resources-edit,而后在第三個集群角色資源global-resources-admin上使用聚合規則的標簽選擇器來匹配前兩個資源的標簽,因此,集群角色global-resources-admin的權限將由匹配到的其他ClusterRole資源的規則列表自動聚合而成。

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: global-resources-view
  labels:
    rbac.ilinux.io/aggregate-to-global-admin: "true"
rules:
- apiGroups: [""]
  resources: ["nodes", "namespaces", "persistentvolumes", "clusterroles"]
  verbs: ["get", "list", "watch"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: global-resources-edit
  labels:
    rbac.ilinux.io/aggregate-to-global-admin: "true"
rules:
- apiGroups: [""]
  resources: ["nodes", "namespaces", "persistentvolumes"]
  verbs: ["create", "delete", "deletecollection", "patch", "update"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: global-resources-admin
aggregationRule:
  clusterRoleSelectors:
  - matchLabels:
      rbac.ilinux.io/aggregate-to-global-admin: "true"
rules: []  # 該規則列表為空,它將由控制器自動聚合生成

任何能夠被示例中clusterrole/globa-resources-admin資源的標簽選擇器匹配到的Cluster-Role資源的相關規則將一同合並為它的授權規則,並且相關作用域內的任何ClusterRole資源的變動都將實時反饋到聚合資源之上。因而,聚合型ClusterRole的規則會隨着標簽選擇器的匹配結果動態變化。

事實上,Kubernetes系統上面向用戶的內置ClusterRole admin和edit也是聚合型的ClusterRole對象,因為這可以使得默認角色中包含自定義資源的相關規則,例如由CustomResourceDefinitions或Aggregated API服務器提供的規則等。

4、面向用戶的內置ClusterRole

API Server內置了一組默認的ClusterRole和ClusterRoleBinding資源預留給系統使用,其中大多數都以system:為前綴。另外有一些不以system:為前綴的默認的ClusterRole資源是為面向用戶的需求而設計,包括集群管理員角色cluster-admin,以及專用於授予特定名稱空間級別權限的集群角色admin、edit和view,如下圖所示。掌握這些默認的內置ClusterRole資源有助於按需創建用戶並分配相應權限。

 

內置的clusterroles/cluster-admin資源擁有管理集群所有資源的權限,而內置的clusterrolebindings/cluster-admn將該角色分配給了system:masters用戶組,這意味着所有隸屬於該組的用戶都將自動具有集群的超級管理權限。kubeadm安裝設置集群時,自動創建的配置文件/etc/kubernetes/admin.conf中定義的用戶kubernetes-admin使用證書文件/etc/kubernetes/pki/apiserver-kubelet-client.crt向API Server進行驗證。而該數字證書的Subject屬性值為/O=system:masters,API Server會在成功驗證該用戶的身份之后將其識別為system: master用戶組的成員。

[root@k8s-master01 apps]# openssl x509 -in /etc/kubernetes/pki/apiserver-kubelet-client.crt  -noout -subject 
subject= /O=system:masters/CN=kube-apiserver-kubelet-client

為Kubernetes集群自定義超級管理員的方法至少有兩種:一是將用戶歸入system:masters組,二是通過ClusterRoleBinding直接將用戶綁定至內置的集群角色cluster-admin上。

在多租戶、多項目或多環境等使用場景中,用戶通常應該獲得名稱空間級別絕大多數資源的管理(admin)、只讀(view)或編輯(edit)權限,可通過在指定的名稱空間中創建RoleBinding資源引用內置的ClusterRole資源進行這類權限的快速授予。例如,在名稱空間dev中創建一個RoleBinding資源,為ik8s用戶分配集群角色admin,將使得該用戶具有管理dev名稱空間中除了名稱空間本身及資源配額之外的所有資源的權限。

[root@k8s-master01 apps]#kubectl create rolebinding ik8s-admin --clusterrole=admin --user=ik8s -n dev  

若僅需要授予編輯或只讀權限,在創建RoleBinding時引用ClusterRole的edit或view便能實現。

面向用戶的內置ClusterRole資源

API Server默認創建的以system:為前綴的大多數ClusterRole和ClusterRoleBinding專為Kubernetes系統的基礎架構而設計,修改這些資源可能會導致集群功能不正常。例如,若修改了為kubelet賦權的system:node將會導致kubelet無法正常工作。所有默認的ClusterRole和ClusterRoleBinding都打上了kubernetes.io/bootstrapping=rbac-defaults標簽。

每次啟動時,API Server都會自動為所有默認的ClusterRole重新賦予缺失的權限,同時為默認的ClusterRoleBinding綁定缺失的主體。這種機制給了集群從意外修改中自動恢復的能力,以及升級版本后自動將ClusterRole和ClusterRoleBinding升級到滿足新版本需求的能力。

說明:
必要時,在默認的ClusterRole或ClusterRoleBinding上設置annnotation中的rbac.authorization.kubernetes.io/autoupdate屬性的值為false,即可禁止這種自動恢復功能。

啟用RBAC后,Kubernetes系統的各核心組件、附加組件,以及由controller-manager運行的核心控制器等,幾乎都要依賴於合理的授權才能正常運行。因而,RBAC權限模型為這些組件內置了可獲得最小化的資源訪問授權的ClusterRole和ClusterRoleBinding,例如system:kube-sheduler、system:kube-controller-manager、system:node、system:node-proxier和system:kube-dns等,其中大多數組件都可以做到見名知義。

 

六、認證與權限應用案例:Dashboard

1、dashboard的介紹及部署

Kubernetes Dashboard項目為Kubernetes集群提供了一個基於Web的通用UI,支持集群管理、應用管理及應用排障等功能。Dashboard項目包含前端和后端兩個組件。前端運行於客戶端瀏覽器中,由TypeScript編寫,它使用標准的HTTP方法將請求發送到后端並從后端獲取業務數據;后端是使用Go語言編寫的HTTP服務器,它負責接收前端的請求、將數據請求發送到適配的遠程后端(例如Kubernetes API Server等)或實現業務邏輯等。

 

出於安全因素的考慮,Dashboard在其項目倉庫中推薦的默認部署清單(recommended.yaml)中僅定義了運行自身所需要的最小權限,並且強制要求遠程訪問必須要基於HTTPS通信,否則應該通過kubectl proxy以代理方式進行。因而,若需要繞過kubectl proxy代理直接訪問Dashboard,必須要為其HTTP服務進程提供用於建立HTTPS連接的服務器端證書。 推薦的部署清單默認便會在內存中生成自簽證書,並以之生成名為kubernetes-dashboard-certs的Secret對象,Dashboard Pod將從該Secret中加載證書(tls.crt)和私鑰(tls.key)。若需要使用自定義的證書,則應該在執行如下部署命令之前先把准備好的證書與私鑰文件分別以tls.crt和tls.key為鍵名,創建成kubernetes-dashboard名稱空間下名為kubernetes-dashboard-certs的Secret對象,需要用到時,在Dashboard部署之前參考Secret對象的管理方式完成創建即可。下面的命令未自定義Secret,它直接使用Dashboard項目master分支中的配置清單完成應用部署:

https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml下載dashboard清單文件,手動修改service暴露nodeport的端口為30001

# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: v1
kind: Namespace
metadata:
  name: kubernetes-dashboard

---

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard

---

kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  type: NodePort
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30001
  selector:
    k8s-app: kubernetes-dashboard

---

apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-certs
  namespace: kubernetes-dashboard
type: Opaque

---

apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-csrf
  namespace: kubernetes-dashboard
type: Opaque
data:
  csrf: ""

---

apiVersion: v1
kind: Secret
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-key-holder
  namespace: kubernetes-dashboard
type: Opaque

---

kind: ConfigMap
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard-settings
  namespace: kubernetes-dashboard

---

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
rules:
  # Allow Dashboard to get, update and delete Dashboard exclusive secrets.
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"]
    verbs: ["get", "update", "delete"]
    # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["kubernetes-dashboard-settings"]
    verbs: ["get", "update"]
    # Allow Dashboard to get metrics.
  - apiGroups: [""]
    resources: ["services"]
    resourceNames: ["heapster", "dashboard-metrics-scraper"]
    verbs: ["proxy"]
  - apiGroups: [""]
    resources: ["services/proxy"]
    resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"]
    verbs: ["get"]

---

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
rules:
  # Allow Metrics Scraper to get metrics from the Metrics server
  - apiGroups: ["metrics.k8s.io"]
    resources: ["pods", "nodes"]
    verbs: ["get", "list", "watch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: kubernetes-dashboard
subjects:
  - kind: ServiceAccount
    name: kubernetes-dashboard
    namespace: kubernetes-dashboard

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kubernetes-dashboard
subjects:
  - kind: ServiceAccount
    name: kubernetes-dashboard
    namespace: kubernetes-dashboard

---

kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: kubernetes-dashboard
  template:
    metadata:
      labels:
        k8s-app: kubernetes-dashboard
    spec:
      containers:
        - name: kubernetes-dashboard
          image: kubernetesui/dashboard:v2.2.0
          imagePullPolicy: Always
          ports:
            - containerPort: 8443
              protocol: TCP
          args:
            - --auto-generate-certificates
            - --namespace=kubernetes-dashboard
            # Uncomment the following line to manually specify Kubernetes API server Host
            # If not specified, Dashboard will attempt to auto discover the API server and connect
            # to it. Uncomment only if the default does not work.
            # - --apiserver-host=http://my-address:port
          volumeMounts:
            - name: kubernetes-dashboard-certs
              mountPath: /certs
              # Create on-disk volume to store exec logs
            - mountPath: /tmp
              name: tmp-volume
          livenessProbe:
            httpGet:
              scheme: HTTPS
              path: /
              port: 8443
            initialDelaySeconds: 30
            timeoutSeconds: 30
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsUser: 1001
            runAsGroup: 2001
      volumes:
        - name: kubernetes-dashboard-certs
          secret:
            secretName: kubernetes-dashboard-certs
        - name: tmp-volume
          emptyDir: {}
      serviceAccountName: kubernetes-dashboard
      nodeSelector:
        "kubernetes.io/os": linux
      # Comment the following tolerations if Dashboard must not be deployed on master
      tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule

---

kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: dashboard-metrics-scraper
  name: dashboard-metrics-scraper
  namespace: kubernetes-dashboard
spec:
  ports:
    - port: 8000
      targetPort: 8000
  selector:
    k8s-app: dashboard-metrics-scraper

---

kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    k8s-app: dashboard-metrics-scraper
  name: dashboard-metrics-scraper
  namespace: kubernetes-dashboard
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: dashboard-metrics-scraper
  template:
    metadata:
      labels:
        k8s-app: dashboard-metrics-scraper
      annotations:
        seccomp.security.alpha.kubernetes.io/pod: 'runtime/default'
    spec:
      containers:
        - name: dashboard-metrics-scraper
          image: kubernetesui/metrics-scraper:v1.0.6
          ports:
            - containerPort: 8000
              protocol: TCP
          livenessProbe:
            httpGet:
              scheme: HTTP
              path: /
              port: 8000
            initialDelaySeconds: 30
            timeoutSeconds: 30
          volumeMounts:
          - mountPath: /tmp
            name: tmp-volume
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsUser: 1001
            runAsGroup: 2001
      serviceAccountName: kubernetes-dashboard
      nodeSelector:
        "kubernetes.io/os": linux
      # Comment the following tolerations if Dashboard must not be deployed on master
      tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule
      volumes:
        - name: tmp-volume
          emptyDir: {}
[root@k8s-master01 apps]# kubectl apply -f dashboard.yaml 
namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created

[root@k8s-master01 apps]# kubectl get svc -A
NAMESPACE              NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE
default                kubernetes                  ClusterIP   172.26.0.1       <none>        443/TCP                  2d2h
kube-system            kube-dns                    ClusterIP   172.26.0.10      <none>        53/UDP,53/TCP,9153/TCP   2d2h
kubernetes-dashboard   dashboard-metrics-scraper   ClusterIP   172.26.186.123   <none>        8000/TCP                 12s
kubernetes-dashboard   kubernetes-dashboard        NodePort    172.26.237.12    <none>        443:30001/TCP            12s

部署完成的Dashboard支持多種不同的訪問方式,例如kubectl proxy、kubectl port-forward、節點端口、Ingress或API Server等,這里重點介紹節點端口。默認創建的Service對象(kubernetes-dashboard)類型為ClusterIP,它僅能在Pod客戶端中訪問,若需要在集群外使用瀏覽器訪問Dashboard,可將該Service對象類型修改為NodePort后,通過節點端口進行訪問。

Dashboard的默認登錄頁面,它支持直接通過目標Service Account的令牌加載身份憑據,或者以該令牌為身份憑據生成專用的kubeconfig文件,並通過指定的文件路徑向Dashboard提交認證信息。訪問https://192.168.32.204:30001(https://nodeIP:端口)

 

Dashboard的資源訪問權限繼承自登錄時的Service Account用戶,我們可以向相關的Service Account分配特定的角色或集群角色完成Dashboard用戶權限模型的構建。例如,為登錄的用戶授權集群級別管理權限時,可直接使用ClusterRoleBinding為Service Account分配內置的集群角色cluster-admin,而授權名稱空間級別的管理權限時,可在目標名稱空間上向Service Account分配內置的集群角色admin。當然,也可以直接自定義RBAC的角色或集群角色,以完成特殊需求的權限委派。

2、dashboard的認證與授權

2.1 使用token登錄dashboard

Kubernetes Dashboard自身並不進行任何形式的身份驗證和鑒權,它僅是把用戶提交的身份憑據轉發至后端的API Server完成驗證,資源操作請求及權限檢查同樣會提交至后端的API Server進行。從某種意義上講,Dashboard更像是用戶訪問Kubernetes的代理程序,發送給API Server的身份認證及資源操作請求都是由Dashboard應用程序完成,因而用戶提交的身份憑據需要關聯至某個Service Account。

集群全局的資源管理操作依賴於集群管理員權限,因而需要為專用於訪問Dashboard的Service Account分配內置的cluster-admin集群角色。隨后,將相應Service Account的令牌信息提交給Dashboard並認證到API Server,便可使得Dashboard繼承了該賬戶的所有管理權限。

例如,下面在kubernetes-dashboard名稱空間創建一個名為dashboard-admin的Service Account完成該目標。

[root@k8s-master01 apps]# kubectl create serviceaccount admin-dashboard -n kubernetes-dashboard
serviceaccount/admin-dashboard created

[root@k8s-master01 apps]# kubectl create clusterrolebinding admin-dashboard --clusterrole=cluster-admin \
 --serviceaccount=kubernetes-dashboard:admin-dashboard
clusterrolebinding.rbac.authorization.k8s.io/admin-dashboard-clusterrolebinding created

配置清單

---
#配置訪問dashboard的sa 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-dashboard
  namespace: kubernetes-dashboard
---
#把訪問dashboaed的sa與clusterrole的cluster-admin綁定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-dashboard
subjects:
- kind: ServiceAccount
  name: admin-dashboard
  namespace: kubernetes-dashboard
  apiGroup: ""   #sa default "" ; user and group default rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

獲取到服務賬戶kubernetes-dashboard:admin-dashboard關聯的Secret對象中的令牌信息,提交給Dashboard即可完成認證。下面第一個命令檢索到該服務賬戶的Secret對象名稱並保存到變量中,第二個命令則從該Secret中獲取經過Base64編碼后的令牌信息,並打印出解碼后的令牌信息。

[root@k8s-master01 apps]# kubectl get secrets -n kubernetes-dashboard
NAME                               TYPE                                  DATA   AGE
admin-dashboard-token-jldx4        kubernetes.io/service-account-token   3      10m
default-token-gp58x                kubernetes.io/service-account-token   3      23m
kubernetes-dashboard-certs         Opaque                                0      23m
kubernetes-dashboard-csrf          Opaque                                1      23m
kubernetes-dashboard-key-holder    Opaque                                2      23m
kubernetes-dashboard-token-w9lgr   kubernetes.io/service-account-token   3      23m

[root@k8s-master01 apps]# kubectl describe secrets admin-dashboard-token-jldx4 -n kubernetes-dashboard
Name:         admin-dashboard-token-jldx4
Namespace:    kubernetes-dashboard
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: admin-dashboard
              kubernetes.io/service-account.uid: 0fa14043-bae1-400b-b373-437b0b2155aa

Type:  kubernetes.io/service-account-token

Data
====
namespace:  20 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IkQ2cXNJdXJONzB2MmY1UDdadlFQZkxGSjFwUEI2TW0wVnIwdkhZWi1vakkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi1kYXNoYm9hcmQtdG9rZW4tamxkeDQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiYWRtaW4tZGFzaGJvYXJkIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMGZhMTQwNDMtYmFlMS00MDBiLWIzNzMtNDM3YjBiMjE1NWFhIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmVybmV0ZXMtZGFzaGJvYXJkOmFkbWluLWRhc2hib2FyZCJ9.GLRbOy-sWiFhd6fuBxvHRH2Zd3nykDoBDCJAz1IIm98-swb9IdgYCcYv5T67lKPZDYZC28ZXj0XM8vKSg5GipjBmxoD_TQkDgHjDB38z2HNYjOaT_3oB7VnDVGGbSdPx9OvojPgPcmqYN0VStVnXm6jx09qg6MiE3BWhIe9krAE7yRFmBALuY33FDL0FOxXU0g0cWBzLAaJJblk8zIJBl_eggydYgYXNU0FDS6rd1nq4WNXqEX3QB_w6l3VhJiNX1ocvTYPnL07p_dKbjM317JIJKgu3VFL-23685N6rComDAYh-H9__CuS_gmx6jGkTZdAuZqlIxhgARmiFuWnPtg
ca.crt:     1066 bytes

將令牌信息復制到Dashboard的登錄界面便可完成認證。

 

2.2 使用kubeconfig登錄dashboard

每次訪問Dashboard之前都要先通過如上命令獲取相應的令牌是件相當煩瑣的事情,更簡便的辦法是依該身份憑據創建出一個專用的kubeconfig文件並存儲到客戶端,隨后登錄時在瀏覽器中通過本地路徑加載該kubeconfig文件即可完成認證,更加安全和便捷。

下面僅給出相關步驟,實現為服務賬戶kubernetes-dashboard:admin-user創建相關的配置文件

1)創建admin-user私鑰及證書簽發請求

[root@k8s-master01 ~]#mkdir $HOME/.certs
[root@k8s-master01 ~]#(umask 077; openssl genrsa -out $HOME/.certs/admin-user.key 2048)
[root@k8s-master01 ~]# openssl req -new -key $HOME/.certs/admin-user.key \
     -out $HOME/.certs/admin-user.csr \
     -subj "/CN=admin-user/O=dashboard"

2) kubernetes-ca證書簽發admin-user證書

[root@k8s-master01 ~]#openssl x509 -req -days 365 -CA /etc/kubernetes/pki/ca.crt \
 -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial \
 -in $HOME/.certs/admin-user.csr -out $HOME/.certs/admin-user.crt 

3)添加集群配置,包括集群名稱、API Server URL和信任的CA的證書;clusters配置段中的各列表項名稱需要唯一。

[root@k8s-master01 ~]#kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=https://192.168.32.248:6443 \
--kubeconfig=$HOME/.kube/admin-user.config

4) 設置客戶端認證

[root@k8s-master01 ~]#kubectl config set-credentials admin-user \
--client-key=$HOME/.certs/admin-user.key \
--client-certificate=$HOME/.certs/admin-user.crt \
--embed-certs=true \
--kubeconfig=$HOME/.kube/admin-user.config

5) 以用戶admin-user的身份憑據與Kubernetes集群建立映射關系。配置上下文

[root@k8s-master01 ~]#kubectl config set-context  admin-user@kubernetes \
--cluster=kubernetes \
--user=admin-user \
--kubeconfig=$HOME/.kube/admin-user.config

6) 設置當前上下文為admin-user@kubernetes。

[root@k8s-master01 ~]#kubectl config use-context admin-user@kubernetes --kubeconfig=$HOME/.kube/admin-user.config    

7) 創建serviceaccount賬號為admin-user,並綁定cluser-admin的cluster-role

清單配置

[root@k8s-master01 ~]#vim admin-dashboard.yaml
---
#配置訪問dashboard的sa 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
---
#把訪問dashboaed的sa與clusterrole的cluster-admin綁定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard
  apiGroup: ""
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
[root@k8s-master01 apps]# kubectl apply -f admin-dashboard.yaml 
serviceaccount/admin-user created
clusterrolebinding.rbac.authorization.k8s.io/admin-user created

8) 獲取token名稱及token信息

[root@k8s-master01 apps]# kubectl get secrets -n kubernetes-dashboard|grep admin-user
admin-user-token-v52gz             kubernetes.io/service-account-token   3      7m9s

[root@k8s-master01 apps]# kubectl describe secrets admin-user-token-v52gz -n kubernetes-dashboard 
Name:         admin-user-token-v52gz
Namespace:    kubernetes-dashboard
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: admin-user
              kubernetes.io/service-account.uid: b2dde30c-b6a7-479a-ba25-8503291ce91e

Type:  kubernetes.io/service-account-token

Data
====
namespace:  20 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IkQ2cXNJdXJONzB2MmY1UDdadlFQZkxGSjFwUEI2TW0wVnIwdkhZWi1vakkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLXY1Mmd6Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJiMmRkZTMwYy1iNmE3LTQ3OWEtYmEyNS04NTAzMjkxY2U5MWUiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZXJuZXRlcy1kYXNoYm9hcmQ6YWRtaW4tdXNlciJ9.B0RPQ9mUue3GLt7xAfYD9nwKidGVEmaITNHVe-9o_IGkMZJHF3P0JFBSc6JagaTtqlzJCYzebqwqqYrI7o3XuQXRJ_LCQyQ9BuWkGOe27Wh95gaEgqR7oWH50iLT-ClWxOQOjPrchHfEeZV4XlCbk8NhphibZECKG7V6ExK4X0pBu0sc8Gb8bgVz-rvM69ipWncJgP7CmNcHh_-U4VYLEtMh1NkgMKOmf0nB61UF7lBLxLav1cKDNSJAowLSwJgKttNyOBS1Z5OQJDCwZbS2lN2A4PapfRisVGsOuxLt-ZePfr-RlhVWPvd02HXZjnw7VGzrc-yC8nAHzChQ3CQ1cw
ca.crt:     1066 bytes

9) 將token信息寫入/root/.kube/admin-user.config的最后面

[root@k8s-master01 apps]# vim /root/.kube/admin-user.config
contexts:
- context:
    cluster: kubernetes
    user: admin-user
  name: admin-user@kubernetes
current-context: admin-user@kubernetes
kind: Config
preferences: {}
users:
- name: admin-user
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN1akND......
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFB......
    token: eyJhbGciOiJSUzI1NiIsImtpZCI6IkQ2cXNJdXJONzB2MmY1UDdadlFQZkxGSjFwUE......

將admin-user.config拷貝到其它電腦上,即可使用token登錄dashboard

說明:
dashboard是使用serviceaccount賬號。

2.3 配置用戶只有個別權限的dashboard

若需要設定的用戶僅具有某個名稱空間的管理權限,或者僅擁有集群或名稱空間級別的資源讀取權限,都能夠通過RBAC權限管理模型來實現。這類用戶的設定過程與前述步驟中的關鍵不同之處僅在於角色分配步驟。例如,在名稱空間kubernetes-dashboard中創建服務賬戶monitor-user,並通過ClusterRoleBinding為其分配默認的集群角色view,便可創建一個僅具有全局讀取權限的Dashboard用戶,所需步驟如下。

[root@k8s-master01 apps]# kubectl create serviceaccount monitor -n kubernetes-dashboard
[root@k8s-master01 apps]# kubectl create clusterrolebinding monitor --clusterrole=view \
      --serviceaccount=kubernetes-dashboard:monitor

配置清單

[root@k8s-master01 ~]#vim monitor-dashboard.yaml
---
#配置訪問dashboard的sa 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: monitor
  namespace: kubernetes-dashboard
---
#把訪問dashboaed的sa與clusterrole的cluster-admin綁定
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: monitor
subjects:
- kind: ServiceAccount
  name: monitor
  namespace: kubernetes-dashboard
  apiGroup: ""
roleRef:
  kind: ClusterRole
  name: view
  apiGroup: rbac.authorization.k8s.io

或者在名稱空間dev中創建一個服務賬戶dev-ns-admin,並通過RoleBinding為其分配默認的集群角色admin,就能創建一個僅具有dev名稱空間管理權限的Dashboard用戶,所需要的步驟如下。

[root@k8s-master01 apps]# kubectl create serviceaccount ns-admin -n dev
[root@k8s-master01 apps]# kubectl create rolebinding ns-admin --clusterrole=admin --serviceaccount=dev:ns-admin

配置清單

[root@k8s-master01 ~]#vim monitor-dashboard.yaml
---
#配置訪問dashboard的sa 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ns-admin
  namespace: dev
---
#把訪問dashboaed的sa與clusterrole的cluster-admin綁定
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ns-admin
subjects:
- kind: ServiceAccount
  name: ns-adminr
  namespace: dev
  apiGroup: ""
roleRef:
  kind: ClusterRole
  name: admin
  apiGroup: rbac.authorization.k8s.io

最后找出token並寫入kubeconfig文件的最后即可。

七、准入控制器

API Server中的准入控制器同樣以插件形式存在,它們會攔截所有已完成認證的,且與資源創建、更新和刪除操作相關的請求,以強制實現控制器中定義的功能,包括執行對象的語義驗證和設置缺失字段的默認值等,具體功能取決於API Server啟用的插件。目前,Kubernetes內置了30多個准入控制器。

1、准入控制器概述

准入控制器的相關代碼必須要由管理員編譯進kube-apiserver中才能使用,實現方式缺乏靈活性。於是,Kubernetes自1.7版本引入了Initializers和External Admission Webhooks來嘗試突破此限制,而且自1.9版本起,External Admission Webhooks又被分為MutatingAdmissionWebhook和ValidatingAdmissionWebhook兩種類型,分別用於在API中執行對象配置的“變異”和“驗證”操作,前一種類型的控制器會“改動”和“驗證”資源規范,而后一種類型僅“驗證”資源規范是否合規。

在具體的代碼實現上,一個准入控制器可以是驗證型、變異型或兼具此兩項功能。例如,LimitRanger准入控制器可以使用默認資源請求和限制(變異階段)來擴展Pod,也能夠校驗有着顯式資源需求定義的Pod是否超出LimitRange對象(驗證階段)的定義。而在具體運行時,准入控制也會根據准入控制器類型分階段運行,第一個階段串行運行各變異型控制器,第二階段則串行運行各驗證型控制器,如圖所示。在此過程中,任何控制器拒絕請求都將導致整個請求被即刻拒絕,並將錯誤信息返回給客戶端。

 

Kubernetes集群內置功能的某些方面實際上就是由准入控制器控制的,例如,刪除名稱空間並進入Terminating狀態時,NamespaceLifecycle准入控制器將會阻止在該名稱空間中創建任何新的資源對象。甚至於,必須啟用准入控制器才能使用Kubernetes集群的某些更高級的安全功能,例如在整個命名空間上強制實施安全配置基線的Pod安全策略等。 API Server默認便會啟用部分准入控制器,它也支持通過--enable-admission-plugins選項顯式指定要加載的准入控制器,使用--disable-admission-plugins選項顯式指定要禁用的准入控制器。

Kubernetes內置支持的所有准入控制器及其功能說明請參考官方文檔中的說明,具體地址為https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/。

Kubernetes正是依賴LimitRange資源和相應的LimitRanger准入控制器、ResourceQuota資源和同名的准入控制器,以及PodSecurityPolicy資源和同名的准入控制器為多租戶或多項目的集群環境提供了基礎的安全策略框架。

2、LimitRange

盡管用戶可以為容器或Pod資源指定資源需求及資源限制,但這並非強制性要求,那些未明確定義資源限制的容器應用很可能會因程序Bug或真實需求而吞掉本地工作節點上的所有可用計算資源。因此妥當的做法是,使用LimitRange資源在每個名稱空間中限制每個容器的最小及最大計算資源用量,以及為未顯式定義計算資源使用區間的容器設置默認的計算資源需求和計算資源限制。一旦在名稱空間上定義了LimitRange對象,客戶端創建或修改資源對象的操作必將受到LimitRange控制器的“驗證”,任何違反LimitRange對象定義的資源最大用量的請求都將被直接拒絕。 LimitRange支持在Pod級別與容器級別分別設置CPU和內存兩種計算資源的可用范圍,它們對應的資源范圍限制類型分別為Pod和Container。一旦在名稱空間上啟用LimitRange,該名稱空間中的Pod或容器的requests和limits的各項屬性值必須在對應的可用資源范圍內,否則將會被拒絕,這是驗證型准入控制器的功能。以Pod級別的CPU資源為例,若某個LimitRange資源為其設定了[0.5,4]的區間,則相應名稱空間下任何Pod資源的requests.cpu的屬性值必須要大於等於500m,同時,limits.cpu的屬性值也必須要小於等於4。而未顯式指定request和limit屬性的容器,將會從LimitRange資源上分別自動繼承相應的默認設置,這是變異型准入控制器的功能。

 

LimitRange也支持在PersistentVolumeClaim資源級別設定存儲空間的范圍限制,它用於限制相應名稱空間中創建的PVC對象請求使用的存儲空間不能逾越指定的范圍。未指定requests和limits屬性的PVC規范,將在創建時自動繼承LimitRange上配置的默認值。 下面的資源清單(limitrange-demo.yaml)分別為dev名稱空間中的Pod、Container和PersistentVolumeClaim資源定義了各自的資源范圍,並為后兩者指定了相應可用資源規范的limits和requests屬性上的默認值。其中用到的各配置屬性中,default用於定義limits的默認值,defaultRequest定義requests的默認值,min定義最小資源用量,而最大資源用量可以使用max給出固定值,也可以使用maxLimitRequestRatio設定最小用量的指定倍數,同時定義二者時,其意義要相符。

[root@k8s-master01 apps]# vim limitrange-demo.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: resource-limits
  namespace: dev
spec:
  limits:
    - type: Pod
      max:
        cpu: "4" 
        memory: "4Gi" 
      min:
        cpu: "500m" 
        memory: "16Mi" 
    - type: Container
      max:
        cpu: "4" 
        memory: "1Gi" 
      min:
        cpu: "100m" 
        memory: "4Mi" 
      default:
        cpu: "2" 
        memory: "512Mi" 
      defaultRequest:
        cpu: "500m" 
        memory: "64Mi" 
      maxLimitRequestRatio:
        cpu: "4" 
    - type: PersistentVolumeClaim
      max:
        storage: "10Gi"
      min:
        storage: "1Gi"
      default:
        storage: "5Gi"
      defaultRequest:
        storage: "1Gi"
      maxLimitRequestRatio:
        storage: "5"

LimitRange僅在Container資源類型上可為CPU與內存設置default(limits屬性的默認值)和defaultrequest(requests屬性的默認值),Pod資源類型不支持。

LimitRange資源的詳細描述會以非常直觀、清晰的方式輸出相關的資源限制及默認值的定義,將如上配置清單中的LimitRange資源resource-limits創建到集群上,而后便可使用describe命令查看:

[root@k8s-master01 apps]# kubectl create ns dev
namespace/dev created
[root@k8s-master01 apps]# kubectl apply -f limitrange-demo.yaml 
limitrange/resource-limits created

[root@k8s-master01 apps]# kubectl get limitrange 
No resources found in default namespace.
[root@k8s-master01 apps]# kubectl get limitrange  -n dev
NAME              CREATED AT
resource-limits   2021-05-12T06:17:14Z
[root@k8s-master01 apps]# kubectl describe limitrange resource-limits -n dev
Name:                  resource-limits
Namespace:             dev
Type                   Resource  Min   Max   Default Request  Default Limit  Max Limit/Request Ratio
----                   --------  ---   ---   ---------------  -------------  -----------------------
Pod                    cpu       500m  4     -                -              -
Pod                    memory    16Mi  4Gi   -                -              -
Container              cpu       100m  4     500m             2              4
Container              memory    4Mi   1Gi   64Mi             512Mi          -
PersistentVolumeClaim  storage   1Gi   10Gi  1Gi              5Gi            5

LimitRange資源resource-limits的詳細描述

通過在dev名稱空間中創建Pod對象與PVC對象對各限制的邊界和默認值的效果進行多維度測試。先創建一個僅包含一個容器且沒有默認系統資源需求和限制的Pod對象:

[root@k8s-master01 apps]# kubectl run testpod-1 --image="ikubernetes/demoapp:v1.0" -n dev
pod/testpod-1 created

Pod對象testpod-1資源規范中被自動添加了CPU和內存資源的requests和limits屬性,它的值來自limitranges/resource-limits中的定義,如下面的命令及截取的結果片段所示。

[root@k8s-master01 apps]# kubectl get pod testpod-1 -n dev -o yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubernetes.io/limit-ranger: 'LimitRanger plugin set: cpu, memory request for container
      testpod-1; cpu, memory limit for container testpod-1'
......
spec:
  containers:
  - image: ikubernetes/demoapp:v1.0
    imagePullPolicy: IfNotPresent
    name: testpod-1
    resources:
      limits:
        cpu: "2"
        memory: 512Mi
      requests:
        cpu: 500m
        memory: 64Mi
......

沒有給containers配置資源限制,則使用定義好的默認資源限制mincpu=0.5,minmen=64m;maxcpu=2,maxmem=512m。

 

若Pod對象設定的CPU或內存的requests屬性值小於LimitRange中相應資源的下限,或limits屬性值大於設定的相應資源的上限,就會觸發LimitRanger准入控制器拒絕相關的請求。例如下面創建Pod的命令中,僅requests.memory一個屬性值違反了limitrange/resource-limits中的定義,但請求同樣會被拒絕。

[root@k8s-master01 apps]# kubectl run testpod-2 --image="ikubernetes/demoapp:v1.0" -n dev \
>           --limits='cpu=2,memory=1Gi' --requests='cpu=1,memory=8Mi' 
Error from server (Forbidden): pods "testpod-2" is forbidden: minimum memory usage per Pod is 16Mi, but request is 8388608
#配置pod的內存最少為8m,我們設置的pod資源位16m~4G,小於最下值,pod創建失敗。

在dev名稱空間中創建的PVC對象的可用存儲空間也將受到LimitRange資源中定義的限制。

需要注意的是,LimitRange生效於名稱空間級別,它需要定義在每個名稱空間之上;另外,定義的限制僅對該資源創建后的Pod和PVC資源創建請求有效,對之前已然存在的資源無效;再者,不建議在生效於同一名稱空間的多個LimitRange資源上,對同一個計算資源限制進行分別定義,以免產生歧義或導致沖突。

3、ResourceQuota

盡管LimitRange資源能在名稱空間上限制單個容器、Pod或PVC相關的系統資源用量,但用戶依然可以創建出無數的資源對象,進而侵占集群上所有的可用系統資源。ResourceQuota資源能夠定義名稱空間級別的資源配額,從而在名稱空間上限制聚合資源消耗的邊界,它支持以資源類型來限制用戶可在本地名稱空間中創建的相關資源的對象數量,以及這些對象可消耗的計算資源總量等。 而同名的ResourceQuota准入控制器負責觀察傳入的請求,並確保它沒有違反相應名稱空間中ResourceQuota資源定義的任何約束。ResourceQuota准入控制器屬於“驗證”類型的控制器,用戶創建或更新資源的操作違反配額約束時將會被拒絕,API Server會響應以HTTP狀態代碼403 FORBIDDEN,並顯示一條消息以提示違反的約束條件。 ResourceQuota資源可限制名稱空間中處於非終止狀態的所有Pod對象的計算資源需求及計算資源限制總量。

▪cpu或requests.cpu:CPU資源相關請求的總量限額。
▪memory或requests.cpu:內存資源相關請求的總量限額。
▪limits.cpu:CPU資源相關限制的總量限額。
▪limits.memory:內存資源相關限制的總量限額。

ResourceQuota資源還支持為本地名稱空間中的PVC存儲資源的需求總量和限制總量設置限額,它能夠分別從名稱空間中的全部PVC、隸屬於特定存儲類的PVC以及基於本地臨時存儲的PVC分別進行定義。

▪requests.storage:所有PVC存儲需求的總量限額。
▪persistentvolumeclaims:可以創建的PVC總數限額。
▪<storage-class-name>.storageclass.storage.k8s.io/requests.storage:特定存儲類上可使用的所有PVC存儲需求的總量限額。
▪<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims:特定存儲類上可使用的PVC總數限額。
▪requests.ephemeral-storage:所有Pod可以使用的本地臨時存儲資源的requets總量。
▪limits.ephemeral-storage:所有Pod可用的本地臨時存儲資源的limits總量。

在v1.9版本之前的Kubernetes系統上,ResourceQuota僅支持在有限的幾種資源集上設定對象計數配額,例如pods、services和configmaps等,而自v1.9版本起開始支持以count/<resource>.<group>的格式對所有資源類型對象的計數配額,例如count/deployments.apps、count/deployments.extensions和count/services等。

下面的資源清單(resourcequota-demo.yaml)在dev名稱空間中定義了一個ResourceQuota資源對象,它定義了計算資源與存儲資源分別在requests和limits維度的限額,也定義了部署資源類型中的可用對象數量。

[root@k8s-master01 apps]# vim resourcequota-demo.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: resourcequota-demo
  namespace: dev
spec:
  hard:
    pods: "5"
    count/services: "5"
    count/configmaps: "5"
    count/secrets: "5"
    count/cronjobs.batch: "2"
    requests.cpu: "2"
    requests.memory: "4Gi"
    limits.cpu: "4"
    limits.memory: "8Gi"
    count/deployments.apps: "2"
    count/statefulsets.apps: "2"
    persistentvolumeclaims: "6"
    requests.storage: "20Gi"
    fast-rbd.storageclass.storage.k8s.io/requests.storage: "20Gi"
    fast-rbd.storageclass.storage.k8s.io/persistentvolumeclaims: "6"

與LimitRange不同的是,ResourceQuota會計入指定范圍內,先前的資源對象對系統資源和資源對象的限額占用情況,因此將resourceqouta-demo創建到集群上之后,dev名稱空間中現有的資源會立即分去限額內的一部分可用空間,這在ResourceQuota資源的詳細描述中會有直觀展示。

[root@k8s-master01 apps]# kubectl apply -f resourcequota-demo.yaml 
resourcequota/resourcequota-demo created
[root@k8s-master01 apps]# kubectl describe resourcequotas/resourcequota-demo -n dev
Name:                                                        resourcequota-demo
Namespace:                                                   dev
Resource                                                     Used   Hard
--------                                                     ----   ----
count/configmaps                                             1      5
count/cronjobs.batch                                         0      2
count/deployments.apps                                       0      2
count/secrets                                                1      5
count/services                                               0      5
count/statefulsets.apps                                      0      2
fast-rbd.storageclass.storage.k8s.io/persistentvolumeclaims  0      6
fast-rbd.storageclass.storage.k8s.io/requests.storage        0      20Gi
limits.cpu                                                   2      4
limits.memory                                                512Mi  8Gi
persistentvolumeclaims                                       0      6
pods                                                         1      5
requests.cpu                                                 500m   2
requests.memory                                              64Mi   4Gi
requests.storage                                             0      20Gi

ResourceQuota資源詳細描述示例

dev名稱空間下的Pod資源限額已被先前的自主式Pod對象消耗了1/5,與此同時,計算資源請求和限制也各占用了一部分配額。隨后,在dev名稱空間中創建Pod資源時,requests.cpu、requests.memroy、limits.cpu、limits.memory和pods等任何一個限額的超出都將致使創建操作失敗,如下面的命令及結果所示。

[root@k8s-master01 apps]# kubectl run testpod-2 --image="ikubernetes/demoapp:v1.0" \
>       --requests="cpu=2,memory=1Gi" --limits="cpu=2,memory=1Gi" -n dev 
Error from server (Forbidden): pods "testpod-2" is forbidden: exceeded quota: resourcequota-demo, requested: requests.cpu=2, used: requests.cpu=500m, limited: requests.cpu=2
#cpu數超過最大的限制數量

每個ResourceQuota資源對象上還支持定義一組作用域,用於定義資源上的配額僅生效於這組作用域交集范圍內的對象,目前適用范圍包括Terminating、NotTerminating、BestEffort和NotBestEffort。

▪Terminating:匹配.spec.activeDeadlineSeconds的屬性值大於等於0的所有Pod對象。
▪NotTerminating:匹配.spec.activeDeadlineSeconds的屬性值為空的所有Pod對象。
▪BestEffort:匹配所有位於BestEffort QoS類別的Pod對象。
▪NotBestEffort:匹配所有非BestEffort QoS類別的Pod對象。

另外,Kubernetes自v1.8版本起支持管理員設置不同的優先級類別(PriorityClass)創建Pod對象,而且自v1.11版本起還支持對每個PriorityClass對象分別設定資源限額。於是,管理員還可以在ResourceQuota資源上使用scopeSelector字段定義其生效的作用域,它支持基於Pod對象的優先級來控制Pod對系統資源的消耗。

4、PodSecurityPolicy

Pod和容器規范中允許用戶使用securityContext字段定義安全相關的配置,但允許任何用戶隨意以特權模式運行容器或者使用任意的Linux內核能力等,顯然存在着難以預料的安全風險。API Server提供了PodSecurityPolicy資源讓管理員在集群全局定義或限定用戶在Pod和容器上可用及禁用的安全配置,例如是否可使用特權容器和主機名稱空間,可使用的主機網絡端口范圍、卷類型和Linux Capabilities等。因此,本質上來說,PodSecurityPolicy資源就是集群全局范圍內定義的Pod資源可用的安全上下文策略。同名的PodSecurityPolicy准入控制器負責觀察集群范圍內的Pod資源的運行屬性,並確保它沒有違反PodSecurityPolicy資源定義的約束條件。

PSP准入控制器會根據顯式定義的PSP資源中的安全策略判定允許何種Pod資源的創建操作,若無任何可用的安全策略,它將阻止創建任何Pod資源。新部署的Kubernetes集群默認並不會自動生成任何PSP資源,因而該准入控制器默認處於禁用狀態。PSP資源的API接口(policy/v1beta1/podsecuritypolicy)獨立於PSP准入控制器,因此管理員可以先定義好必要的Pod安全策略,再設置kube-apiserver啟用PSP准入控制器。不當的Pod安全策略可能會產生難以預料的副作用,因此請確保添加的任何PSP對象都經過了充分測試。

PodSecurityPolicy是標准的API資源類型,它隸屬於policy群組,在spec字段中嵌套多種安全規則來定義期望的目標,資源規范及簡要的使用說明如下所示。

apiVersion: policy/v1beta1   # PSP資源所屬的API群組及版本
kind: PodSecurityPolicy   # 資源類型標識
metadata:
  name <string>   # 資源名稱
spec:  
  allowPrivilegeEscalation  <boolean> # 是否允許權限升級
  allowedCSIDrivers <[]Object>        #內聯CSI驅動程序列表,必須在Pod規范中顯式定義
  allowedCapabilities <[]string>      # 允許使用的內核能力列表,“*”表示all
  allowedFlexVolumes <[]Object>       # 允許使用的Flexvolume列表,空值表示all
  allowedHostPaths <[]Object>         # 允許使用的主機路徑列表,空值表示all
  allowedProcMountTypes <[]string>    # 允許使用的ProcMountType列表,空值表示默認
  allowedUnsafeSysctls <[]string>     # 允許使用的非安全sysctl參數,空值表示不允許
  defaultAddCapabilities  <[]string>  # 默認添加到Pod對象的內核能力,可被drop
  defaultAllowPrivilegeEscalation <boolean> # 是否默認允許內核權限升級
  forbiddenSysctls  <[]string>        # 禁止使用的sysctl參數,空表示不禁用
  fsGroup <Object>    # 允許在SecurityContext中使用的fsgroup,必選字段
    rule <string>     # 允許使用的FSGroup規則,支持RunAsAny和MustRunAs
    ranges <[]Object> # 允許使用的組ID范圍,需要與MustRunAs規則一同使用
      max  <integer>                  # 最大組ID號
      min  <integer>                  # 最小組ID號
  hostIPC <boolean>                   # 是否允許Pod使用hostIPC
  hostNetwork <boolean>               # 是否允許Pod使用hostNetwork
  hostPID <boolean>                   # 是否允許Pod使用hostPID
  hostPorts <[]Object>                # 允許Pod使用的主機端口暴露其服務的范圍
 max  <integer>                    # 最大端口號,必選字段
    min  <integer>                    # 最小端口號,必選字段
  privileged  <boolean>               # 是否允許運行特權Pod
  readOnlyRootFilesystem  <boolean>   # 是否設定容器的根文件系統為“只讀”
  requiredDropCapabilities <[]string> # 必須要禁用的內核能力列表
  runAsGroup  <Object> # 允許Pod在runAsGroup中使用的值列表,未定義表示不限制
  runAsUser <Object>   # 允許Pod在runAsUser中使用的值列表,必選字段
    rule <string>      # 支持RunAsAny、MustRunAs和MustRunAsNonRoot
    ranges <[]Object>  # 允許使用的組ID范圍,需要跟MustRunAs規則一同使用
      max  <integer>                  # 最大組ID號
      min  <integer>                  # 最小組ID號
  runtimeClass <Object>               # 允許Pod使用的運行類,未定義表示不限制
    allowedRuntimeClassNames <[]string> # 可使用的runtimeClass列表,“*”表示all
    defaultRuntimeClassName <string>  # 默認使用的runtimeClass
  seLinux <Object>                    # 允許Pod使用的selinux標簽,必選字段
    rule <string> # MustRunAs表示使用seLinuxOptions定義的值;RunAsAny表示可使用任意值
    seLinuxOptions  <Object>   # 自定義seLinux選項對象,與MustRunAs協作生效
  supplementalGroups  <Object> # 允許Pod在SecurityContext中使用附加組,必選字段  
volumes <[]string>            # 允許Pod使用的存儲卷插件列表,空表示禁用,“*”表示all

啟用PSP准入控制器后要部署任何Pod對象,相關的User Account及Service Account必須全部獲得了恰當的Pod安全策略授權。以常規用戶的身份直接創建Pod對象時,PSP准入控制器將根據該賬戶被授權使用的Pod安全策略驗證其憑據,若無任何安全策略約束該Pod對象的安全性,則創建操作將會被拒絕。基於控制器(例如Deployment)創建Pod對象時,PSP准入控制器會根據Pod對象的Service Account被授權使用的Pod安全策略驗證其憑據,若不存在支持該Pod對象的安全性要求的安全策略,則Pod控制器資源自身能成功創建,但Pod對象不能。

然而,即便在啟用了PSP准入控制器的情況下,PSP對象依然不會生效,管理員還需要借助授權插件(例如RBAC)將use權限授權給特定的Role或ClusterRole,再為相關的User Account或Service Account分配這些角色才能讓PSP策略真正生效。下面簡單說明為Kubernetes集群設定的能支撐集群自身運行的框架性的Pod安全策略,以及允許非管理員使用的Pod安全策略,而后啟用PSP准入控制器中使這些策略生效的方法。

4.1 設置特權及受限的PSP對象

通常,system:masters組內的管理員賬戶、system:node組內的kubelet賬戶,以及kube-system名稱空間中的所有服務賬戶需要擁有創建各類Pod對象的權限,包括創建特權Pod對象。因此,啟用PSP准入控制器之前需要先創建一個特權PSP資源,並將該資源的使用權賦予各類管理員賬戶以確保Kubernetes集群的基礎服務可以正常運行。一個示例性的特權PSP資源清單(psp-privileged.yaml)如下,它啟用了幾乎所有的安全配置。

[root@k8s-master01 apps]# vim psp-privileged.yaml
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: privileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
  privileged: true
  allowPrivilegeEscalation: true
  allowedCapabilities: ['*']
  allowedUnsafeSysctls: ['*']
  volumes: ['*']
  hostNetwork: true
  hostPorts: 
  - min: 0
    max: 65535
  hostIPC: true
  hostPID: true
  runAsUser:
    rule: 'RunAsAny'
  runAsGroup:
    rule: 'RunAsAny'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'

出於安全加強的需要,除了有特權需求的系統級應用程序及集群管理員賬戶之外,其他應用或普通賬戶默認不應該允許使用與安全上下文相關的任何配置。因而,系統內置的特殊組之外的其他普通賬戶或服務賬戶,絕大多數都不必使用安全配置,它們僅可使用受限的安全策略。下面的資源清單(psp-restrict.yaml)定義了一個完全受限的安全策略,它禁止了幾乎所有的特權操作。

[root@k8s-master01 apps]#vim psp-restrict.yaml
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
  allowPrivilegeEscalation: false
  allowedUnsafeSysctls: []
  requiredDropCapabilities:
    - ALL
  # 允許使用的核心存儲卷類型
  volumes: ['configMap', 'emptyDir', 'projected', 'secret', 'secret', 
  'persistentVolumeClaim']
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    rule: 'MustRunAsNonRoot'
  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

將上面兩個資源清單中定義的PSP資源提交並創建到集群之上,隨后便可授權特定的Role或ClusterRole資源通過use調用它們。PSP資源創建完成后才能授權特定的Role或ClusterRole資源通過use進行調用。我們這里首先使用如下命令將上面配置清單中定義的資源創建到集群之上。

[root@k8s-master01 apps]# kubectl apply -f psp-privileged.yaml -f psp-restrict.yaml
podsecuritypolicy.policy/privileged created
podsecuritypolicy.policy/restricted created

4.2 創建ClusterRole並完成賬戶綁定

啟用PodSecurityPolicy准入控制器后,僅被授權使用PSP資源的賬戶才能夠在該資源中定義的策略框架下行使賬戶權限范圍內的資源管理操作。因此,這里還需要顯式授予system:masters、system:nodes和system:serviceaccounts:kube-system組內的用戶可以使用podsecuritypolicy/privileged資源,其他成功認證后的用戶能夠使用podsecuritypolicy/restricted資源。RBAC權限模型中,任何Subject都不能直接獲得權限,它們需要借助分配到的角色獲得權限。因此,下面先創建兩個分別能使用podsecuritypolicy/privileged和podsecuritypolicy/restricted資源的ClusterRole。

下面的資源清單(clusterrole-with-psp.yaml)中創建了兩個ClusterRole資源,授權psp-privileged可以使用名為privileged的安全策略,psp-restricted可以使用名為restricted的安全策略。

[root@k8s-master01 apps]# clusterrole-with-psp.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: psp-restricted
rules:
- apiGroups: ['policy']
  resources: ['podsecuritypolicies']
  verbs:  ['use']
  resourceNames:
  - restricted
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: psp-privileged
rules:
- apiGroups: ['policy']
  resources: ['podsecuritypolicies']
  verbs:  ['use']
  resourceNames:
  -  privileged

下面的資源清單(clusterrolebinding-with-psp.yaml)定義了兩個ClusterRoleBinding對象:前一個為system:masters、system:node和system:serviceaccounts:kube-system組的賬戶分配集群角色psp-privileged,從而能夠使用任何安全配置;后一個為system: authenticated組內的賬戶分配集群角色psp-restricted,以禁止它們在Pod和容器上使用任何安全配置。

[root@k8s-master01 apps]#vim clusterrolebinding-with-psp.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: privileged-psp-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: psp-privileged
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:masters
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:node
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:serviceaccounts:kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: restricted-psp-user
roleRef:
  kind: ClusterRole
  name: psp-restricted
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: Group
  apiGroup: rbac.authorization.k8s.io
  name: system:authenticated

將上面兩個資源清單中定義的ClusterRole和ClusterRoleBinding資源創建到集群上,即可為API Server啟用PodSecurityPolicy准入控制器。

[root@k8s-master01 apps]# kubectl apply -f clusterrole-with-psp.yaml -f clusterrolebinding-with-psp.yaml 
clusterrole.rbac.authorization.k8s.io/psp-restricted created
clusterrole.rbac.authorization.k8s.io/psp-privileged created
clusterrolebinding.rbac.authorization.k8s.io/privileged-psp-user created
clusterrolebinding.rbac.authorization.k8s.io/restricted-psp-user created

4.3 啟用PSP准入控制器

API Server的應用程kube-apiserver使用--enable-admission-plugins選項顯式指定要加載的准入控制器列表,因此在該選項的列表中添加PodSecurityPolicy條目,並重啟kube-apiserver程序便能啟用PSP准入控制器。對於使用kubeadm部署的Kubernetes集群來說,編輯Master節點上的/etc/kubernetes/manifests/kube-apiserver.yaml配置清單,直接修改--enable-admission-plugins選項的值,並添加PodSecurityPolicy列表項即可,各列表項以逗號分隔。kubelet監控到/etc/kubernetes/manifests目錄下的任何資源清單的改變時都會自動重建相關的Pod對象,因此編輯並保存kube-apiserver.yaml資源清單后,kubelet會通過重建相關的靜態Pod而自動生效。

待kube-apiserver重啟完成后,可通過監測API Server程序的運行狀態及相關日志來判定PodSecurityPolicy准入控制器是否成功啟用。以靜態Pod運行kube-apiserver的日志同樣可使用kubectl logs命令獲取。如下面的命令及截取的結果所示,PodSecurityPolicy准入控制器已然成功加載。若Kubernetes的各系統類Pod資源運行狀態正常,即表示安全策略已然成功啟用。

[root@k8s-master01 apps]# kubectl logs kube-apiserver-k8s-master01.ilinux.io -n kube-system
……
plugins.go:158] Loaded 13 mutating admission controller(s) successfully in the following order: NamespaceLifecycle,LimitRanger,…,PodSecurityPolicy,…
plugins.go:161] Loaded 11 validating admission controller(s) successfully in the following order: LimitRanger,ServiceAccount,PodSecurityPolicy,…
……

注意:
盡管PSP對已處於運行狀態的Pod或容器沒有影響,但對於正常運行中的Kubernetes集群來說,中途啟用PodSecurityPolicy仍然可能會導致諸多難以預料的錯誤,尤其是沒有事先為用到安全配置的Pod資源准備好可用的PSP資源時,這些Pod資源一旦重啟便會因觸發PSP策略而被阻止。

接下來,我們可通過能成功認證的普通賬戶測試其創建Pod資源時是否受限於restricted安全策略,以驗證PodSecurityPolicy資源的生效狀態。下面的命令嘗試以dev名稱空間的管理員mason用戶創建一個使用了主機端口(hostPort)的Pod資源,但該操作被PodSecurityPolicy拒絕。

[root@k8s-master01 apps]# kubectl run pod-with-hostport --image="ikubernetes/demoapp:v1.0" \
      --port=80 --hostport=32080 -n dev --context='mason@kubernetes'
Error from server (Forbidden): pods "pod-with-hostport" is forbidden: unable to validate against any pod security policy: [spec.containers[0].hostPort: Invalid value: 32080: Host port 32080 is not allowed to be used. Allowed ports: []]

因為mason用戶由API Server成功認證后,將被自動歸類到system:authenticated組和它所屬的developers組中,但僅前一個組有權使用restricted安全策略。移除命令中的--hostport選項再次執行創建操作即可成功完成。另外,我們也可按此方式授權特定的用戶擁有特定類型的Pod對象創建權限,但策略沖突時可能會導致意料不到的結果,因此將任何Pod安全策略應用到生產環境之前請務必做到充分測試。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM