十五、Kubernetes之安全配置
在任何將資源或服務提供給有限使用者的系統上,認證和授權是兩個必不可少的功能,前者用於身份鑑別,負責驗證“來者是誰”,而後者則實現許可權分派,負責鑑證“他有權做哪些事”。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物件是否違反系統資源限制等,而其中任何的檢查失敗都可能會導致寫入操作失敗。
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物件。
3、認證、授權與准入控制基礎知識
Kubernetes使用身份驗證外掛對API請求進行身份驗證,它允許管理員自定義服務賬戶和使用者賬戶要啟用或禁用的外掛,並支援各自同時啟用多種認證機制。具體設定時,至少應該為服務賬戶和使用者賬戶各自啟用一個認證外掛。 如果啟用了多種認證機制,賬號認證過程由認證外掛以序列方式進行,直到其中一種認證機制成功完成即結束。若認證失敗,伺服器則響應以401狀態碼,反之,請求者就會被Kubernetes識別為某個具體的使用者(以其使用者名稱進行標識),並且該連線上隨後的操作都會以此使用者身份進行。API Server對於接收到的每個訪問請求會呼叫認證外掛,嘗試將以下屬性與訪問請求相關聯。
▪Username:使用者名稱,例如kubernetes-admin等。
▪UID:使用者的數字標籤符,用於確保使用者身份的唯一性。
▪Groups:使用者所屬的組,用於許可權指派和繼承。
▪Extra:鍵值資料型別的字串,用於提供認證需要用到的額外資訊。
3.1 Kubernetes的認證方式
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的授權
▪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)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,每個呼叫都可能會更改物件。
二、ServiceAccount及認證
Kubernetes原生的應用程式意味著專為運行於Kubernetes系統之上而開發的應用程式,這些程式託管執行在Kubernetes之上,能夠直接與API Server進行互動,並進行資源狀態的查詢或更新,例如Flannel和CoreDNS等。API Server同樣需要對這類來自Pod資源中的客戶端程式進行身份驗證,服務賬戶也是專用於這類場景的賬號。ServiceAccount資源一般由使用者身份資訊及儲存了認證資訊的Secret物件組成。
1、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的引用。
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資源清單
完善地建立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例項
[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
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進行驗證,許可權校驗則由授權外掛完成。
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
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下的資源
三、 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叢集中的CA:
(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>
1.2 Kubernetes叢集需要的數字證書
完整執行的Kubernetes系統需要為etcd、API Server及前端代理(front proxy)生成多個數字證書
普通使用者使用這種認證方式的前提是,它們各自擁有自己的數字證書,證書中的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的任意憑據或身份,因而叢集管理員必須自行集中管理證書,管理員的工作量比較大。
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命令成功後即完成。
~# kubeadm alpha certs check-expiration
~# kubeadm alpha certs renew all
四、kubeconfig配置檔案
基於無狀態協議HTTP/HTTPS的API Server需要驗證每次連線請求中的使用者身份,因而kube-controller-manager、kube-scheduler和kube-proxy等各類客戶端元件必須能自動完成身份認證資訊的提交,但通過程式選項來提供這些資訊會導致敏感資訊洩露。另外,管理員還面臨著使用kubectl工具分別接入不同叢集時的認證及認證資訊對映難題。為此,Kubernetes設計了一種稱為kubeconfig的配置檔案,它儲存有接入一到多個Kubernetes叢集的相關配置資訊,並允許管理員按需在各配置間靈活切換。
1、kubeconfig檔案格式
kubeconfig檔案中,各叢集的接入端點以列表形式定義在clusters配置段中,每個列表項代表一個Kubernetes叢集,並擁有名稱標識;各身份認證資訊(credentials)定義在users配置段中,每個列表項代表一個能夠認證到某Kubernetes叢集的憑據。將身份憑據與叢集分開定義以便複用,具體使用時還要以context(上下文)在二者之間按需建立對映關係,各context以列表形式定義在contexts配置段中,而當前使用的對映關係則定義在current-context配置段中。
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
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中定義的上下文列表。
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
步驟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
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"
① 基於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
① 根據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檔案中。還沒有給該使用者授權。
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.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"
基於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
① 生成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 scopeI have a dream so I study hard!!!