帶你玩轉kubernetes-k8s(第38篇:深入分析集羣安全機制)

       Kuberetes通過一系列機制來實現集羣的安全控制,其中包括API Server的認證授權、准入控制機制及保護敏感信息的Secret機制等。集羣的安全性必須考慮如下幾個目標。

(1) 保證容器與其所在宿主機的隔離。

(2) 限制容器給基礎設施或其他容器帶來的干擾。

(3) 最小權限原則一合理限制所有組件的權限,確保組件只執行它被授權的行爲,通過限制單個組件的能力來限制它的權限範圍。

(4) 明確組件間邊界的劃分。

(5) 劃分普通用戶和管理員的角色。

(6) 在必要時允許將管理員權限賦給普通用戶。

(7) 允許擁有Secret數據(Keys、Certs、passwords)的應用在集羣中運行。

下面分別從Authentication、Authorization、AdmissionControl、Secret和Service Account等方面來說明集羣的安全機制。

API Server認證管理

   我們知道,Kubernetes集羣中所有資源的訪問和變更都是通過Kubernetes API Server的REST API來實現的,所以集羣安全的關鍵點就在於如何識別並認證客戶端身份(Authentication),以及隨後訪問權限的授權(Authorization)這兩個關鍵問題,本節對認證管理進行說明。

   Kubernetes集羣提供了3中級別的客戶端身份認證方式。

    最嚴格的HTTPS證書認證:基於CA根證書籤名的雙向數字證書認證方式。

  •     HTTP Token認證:通過一個Token來識別合法用戶。
  •     HTTP Base認證: 通過用戶名+密碼的方式認證。

     首先說說HTTPS證書認證的原理。

     這裏需要有一個CA證書,我們知道CA是PKI系統只通信雙雙方都信任的實體,被稱爲可信第三方。CA作爲可信第三方的重要條件之一就是CA的行爲具有非否認性。作爲第三方而不是簡單的上級,就不必須能讓信任者有追究自己責任的能力。CA通過證書證實他人的公鑰信息,證書上有CA的簽名。用戶如果因爲信任證書而有了損失,則證書可以作爲有效的證據用於追究CA的法律責任。正是因爲CA承擔責任的承諾,所以CA也被稱爲可信第三方。在很多情況下,CA與用戶是相互獨立的實體,CA作爲服務提供方,有可能因爲服務質量問題(例如,發佈的公鑰數據有錯誤)而給用戶帶來損失。在證書綁定了公鑰數據和相應私鑰擁有者的身份信息,並帶有CA的數字簽名;在證書中也包含了CA的名稱,以便於依賴方找到CA的公鑰,驗證證書上的數字簽名。

    CA認證涉及諸多概念,比如根證書、自簽名證書、私鑰、密鑰、加密算法及HTTPS等,本書大致講述SSL協議的流程,有助於理解CA認證和Kubernetes CA認證的配置過程。

    CA證書大概包含下面幾個步驟。

   (1) HTTPS通信雙方的服務器端向CA機構申請證書,CA機構是可信的第三方機構,它可以是一個公認的權威企業,也可以是企業自身。企業內部系統一般都用企業自身的認證系統。CA機構下發根證書、服務端證書及私鑰給申請者。

  (2) HTTPS通信雙方的客戶端向CA機構申請證書,CA機構下發根證書、客戶端證書及私鑰給申請者。

  (3)  客戶端向服務器端發起請求,服務端下發服務端證書給客戶端。客戶端接收到證書後,通過私鑰解密證書,並利用服務器端證書中的公鑰證書信息比較證書裏的信息,例如,比較域名和公鑰與服務器剛剛發送的相關信息是否一致,如果一致,則客戶端認可這個服務器的合法身份。

  (4) 客戶端發送客戶端證書給服務器端,服務端在接受到證書後,通過私鑰解密證書,獲得客戶端證書公鑰,並用該公鑰認證證書信息,確認客戶端是否合法。

 (5)  客戶端通過隨機密鑰加密信息,併發送加密後的信息給服務端。在服務器端和客戶端協商好加密方案後,客戶端會產生一個隨機的密鑰,客戶端通過協商好的加密方案加密該隨機密鑰,併發送該隨機密鑰到服務器端。服務器端接收這個密鑰後,雙發通信的所有內容都通過該隨機密鑰加密。

     上述是雙向認證SSL協議的具體通信過程,這種情況要求服務器和用戶雙方都有證書。單向認證SSL協議則不需要客戶端擁有CA證書,對於上面的步驟,只需將服務器端驗證客戶證書的過程去掉,之後協商對稱密碼方案和對稱通話密鑰時,服務器發送給客戶的密碼沒被加密即可。

   HTTP Token的認證使用一個很長的特殊編碼方式的並且難易被模仿的字符串——Token來表明客戶身份的一種方式。

   在通常情況下,Token是一個很複雜的字符串,比如我們用私鑰簽名一個字符串後的數據就可以被當作一個Token。此外,每個Token對應一個用戶名,存儲在API Server能訪問的一個文件中。當客戶端發起API調用請求時,需要在HTTP Header裏放入Token,這樣一來,API Server就能識別合法用戶和非法用戶了。

    最後說說HTTP Base認證。

    我們知道,HTTP是無狀態的,瀏覽器和Web服務器之間可以通過Cooki來進行身份識別。桌面應用程序(比如新浪桌面客戶端、SkyDrive客戶端、命令行程序)一般不會使用Cookie,那麼它們與Web服務器之間是如何進行身份識別的呢?這就用到了HTTP Base認證,這種認證方式是把“用戶名+冒號+密碼”用BASE64算法進行編碼後的字符串放在HTTP Request中的Header Authorization域裏發送給服務端,服務端在收到後進行解碼,獲取用戶名及密碼,然後進行用戶身份鑑權。

API Server授權管理

    當客戶端發起API Server調用是,API Server內部要先進性用戶認證,然後執行用戶授權流程,即通過授權策略來決定一個API 調用是否合法。 對合法用戶進行授權並且隨後在用戶訪問時進行鑑權,是權限與安全系統的重要一環。 簡單地說,授權就是授予不同的用戶不同的訪問權限。API Server目前支持一下幾種授權策略(通過API Server的啓動參數“--authorization-mode”設置)。

  •    AlwaysDeny: 表示拒絕所有請求,一般用與測試。
  •    AlwaysAllow: 允許接收所有請求,如果集羣不需要授權流程,則可以採用該策略,這也是Kubernetes的默認配置。
  •    ABAC(Attribute-Based Access Control):基於屬性的訪問控制,表示使用用戶配置的授權規則對用戶請求進行匹配和控制。
  •   Webhook: 通過調用外部REST服務對用戶進行授權。
  •   RBAC: Role-Based  Access Control,基於角色的訪問控制。
  •   Node: 是一中專用模式,用於對Kubelet發出的請求進行訪問控制。

  API Server在接收到請求後,會讀取該請求中的數據,生成一個訪問策略對象,如果在該請求中不帶某些屬性(如 Namesoace),則這些屬性的值將根據屬性類型的不同,設置不同的默認值(例如,爲字符串類型的屬性設置一個空字符串;爲布爾類型的屬性設置false;爲數值類型的屬性設置0)。然後將這個訪問策略對象和授權策略文件中的所有訪問策略對象逐條匹配,如果至少有一個策略對象被匹配,則該請求被鑑權通過,否則終止API調用流程,並返回客戶端的錯誤調用碼。

ABAC授權模式詳解

   

在API Server啓用ABAC模式時,需要指定授權策略文件的路徑和名稱(--authorization- policy-file=SOME_FILENAME),授權策略文件裏的每一行都以一個Map類型的JSON對象進行設置,這被稱爲“訪問策略對象”。通過設置訪問策略對象中的apiVersion、kind、spec屬性來確定具體的授權策略,其中,apiVersion當前版本爲abac.authorization.kubernetes.io/v1beta1;kind被設置爲Policy;spec指詳細的策略設置,包括主題屬性、資源屬性、非資源屬性這三個字段,如下所述。
(1)主體屬性
◎ user(用戶名):字符串類型,該字符串類型的用戶名來源於Token文件(--token-auth-file參數設置的文件)或基本認證文件中用戶名稱段的值。
◎ group(用戶組):在被設置爲“system:autheticated”時表示匹配所有已認證的請求,在被設置爲“system:unauthenticated”時表示匹配所有未認證的請求。
(2)資源屬性
◎ apiGroup(API組):字符串類型,表明匹配哪些API Group,例如extensions或*(表示匹配所有API Group)。
◎ namespace(命名空間):字符串類型,表明該策略允許訪問某個Namespace的資源,例如kube-system或*(表示匹配所有Namespace)。
◎ resource(資源):字符串類型,API資源對象,例如pods或*(表示匹配所有資源對象)。
(3)非資源屬性
◎ nonResourcePath(非資源對象類路徑):非資源對象類的URL路徑,例如/version或/apis,*表示匹配所有非資源對象類的請求路徑,也可以設置爲子路徑,/foo/*表示匹配所有/foo路徑下的所有子路徑。
◎ readonly(只讀標識):布爾類型,當它的值爲true時,表明僅允許GET請求通過。
下面對ABAC授權算法、使用kubectl時的授權機制、常見ABAC授權示例、以及如何對Service Account進行授權進行說明。

ABAC授權算法

        API Server進行ABAC授權的算法爲: 在API Server收到請求之後,首先識別出請求攜帶的策略對象的屬性,然後根據在策略文件中定義的策略對這些屬性逐條匹配,以判定是否允許授權。如果有至少一條匹配成功,那麼這個請求就通過了授權(不過還是可能在後續其他授權校驗中失敗)。常見的策略配置如下。

     ◎    要允許所有認證用戶做某件事,可以寫一個策略,將group屬性設置爲system:authenticated。
     ◎ 要允許所有未認證用戶做某件事,可以把策略的group屬性設置爲system:unauthenticated。
     ◎ 要允許一個用戶做任何事,將策略的apiGroup、namespace、resource和nonResourcePath屬性設置爲“*”即可。

2.使用kubectl是的授權機制

         kubectl使用API Server的/api和/apis端點來獲取版本信息。要驗證kubectl create/update命令發送給服務器的對象,kubectl需要向OpenAPI進行查詢,對應的URL路徑爲/openapi/v2。

         當使用ABAC授權模式時,下列特殊資源必須顯示通過nonResourcePath屬性進行設置。

      ◎ API版本協商過程中的/api、/api/*、/apis、和/apis/*。 
      ◎ 使用kubectl version命令從服務器獲取版本時的/version。
      ◎ create/update操作過程中的/swaggerapi/*

         在使用kubectl操作時,如果需要查看發送到API Server的HTTP請求,則可以將日誌級別設置如下:

kubectl --v=8 version

3.常見的ABAC授權示例

     下面通過幾個授權策略文件(JSON格式)示例說明ABAC的訪問控制用法。

       (1)  允許用戶alice對所有資源做任何操作:

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1","kind": "Policy","spec":{"user":"alice","namespace":"*","resource":"*","apiGroup":"*"}}

       (2)   kubelet可以讀取任意Pod:

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "", "namespace": "*", "resource": "pods", "readonly": true}}

       (3)  kubelet 可以讀寫Event 對象:

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec" : {"user" : "kubelet", "namespace": "*" , "resource": "events"}}

      (4)   用戶bob只能讀取projectCariboy中的Pod:

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy","spec":{"user": "bob", "namespace": "projectCarbou", "resource": "pods","readonly":true}}

     (5)  任何用戶都可以對非資源類路徑進行只讀請求:

{"apiVersion": "abc.authorization.kubernetes.io/v1beta1", "kind":"Policy", "spec":{"group": "system:authenticated","readonly":true,"nonResourcePath": "*"}}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1","kind":"Policy, "spec": {"group": "system.unautheticated", "readonly": true, "nonResourcePath": "*"}}

   如果添加了新的ABAC策略,則需要重啓API Server以使其生效。

對Service Account進行授權

   Service Account會自動生成一個ABAC用戶名(username),用戶名按照以下命名規則生成:

systemm:serviceaccount:<namespace>:<serviceccountname>

   創建新的命名空間時,會產生一個如下名稱的Service Account:

system:serviceaccount:<namespace>:default

   如果希望kube-system命令空間中的Service Account "default"具有全部權限,就要在策略文件中加入如下內容:

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user": "system:serviceaccount:kube-system:default", "namespace":"*" "resource":"*","apiGroup":"*"}}

Webhook授權模式詳解

     Webhook定義了一個HTTP回調接口,實現Webhook的應用會再指定事件發生時,向一個URL地址發送(POST)通知信息。啓用Webhook授權模式後,Kubernetes會調用外部REST服務對用戶進行授權。

     Webhook模式用參數--authorization-webhook-config-file=SOME_FILENAME來設置遠端授權服務的信息。

     配置文件使用的是kubeconfig文件的格式。文件裏user一節的內容指的是API Server。相對於遠程授權服務來說,API Server是客戶端,也就是用戶;cluster一節的內容指的是遠程授權服務器的配置。下面的例子爲設置一個使用HTTPS客戶端認證的配置:

clusters:  #指定遠端服務
- name: name-of-remoto-authz-service
  certificate-authority: /path/to/ca.pem    # 驗證遠端服務的CA
  server: https://authz.example.com/authorize  # 遠端服務的URL,必須使用HTTPS
users:            # API Server 的Webhook配置
- name: name-of-api-server
  user:
    client-certificate: /path/to/cert.pem   # Webhook插件使用的證書
    client-key: /path/to/key.pem
current-context: webhook   # kubeconfig 文件需要設置 context
contexts:
- context:
  cluster: name-of-remote-authz-service
  user: name-of-api-server
  name: webhook


    在授權開始時,API Server會生成一個api.authorization.v1beta1.SubjectAccessReview對象,用於描述操作信息,在進行JSON序列化之後POST出來。在這個對象中包含用戶嘗試訪問資源的請求動作的描述,以及被訪問資源的屬性。

    Webhook API 對象和其他API對象一樣,遵循同樣的版本兼容性規則,在實現時要注意apiVersion字段的版本,以實現正確的反序列化操作。另外,API Server必須啓用authorization.k8s.io/v1beta1 API擴展(--runtime-config=authorization.k8s.io/v1beta1=true)。

    下面是一個希望獲取Pod列表的請求報文示例:

{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "spec": {
     "resourceAttributes": {
        "namespace": "kittensandponies",
        "verb": "get",
        "group": "unicorn.example.org"
        "resource": "pods"
      },
      "user": "jane",
      "group": [
         "group1",
         "group2"
       ]
   }
}

     遠端服務需要填充請求中的SubjectAccessReviewStatus字段,並返回允許或不允許訪問的結果。應答報文中的spec字段是無效,也可以省略。

     一個返回“運行訪問”的應答報文示例惡如下:

{
   "apiVersion": "authorization.k8s.io/v1beta1",
   "kind": "SubjectAccessReview",
   "status": {
      "allowed": true
  }
}

  一個返回“不運行訪問”的應答報文示例如下:

{
   "apiVersion": "authorization.k8s.io/v1beta1",
   "kind": "SubjectAccessReview",
   "status": {
      "allowed": false,
      "reason": "user does not have read access to the namespace" 
  }
  
}

     非資源的訪問請求路徑包括/api、/apis、/metrics、/resetMetrics、/logs、/debug、/healthz、/swagger-ui/、/swaggerapi/、/ui和/version。通常可以對/api、/api/*、/apis、/apis/*和/version對於客戶端發現服務器提供的資源和版本信息給予“允許”授權,對於其他非資源的訪問一般可以禁止,以限制客戶端對API Server進行沒有必要的查詢。

    查詢/debug的請求報文示例如下:

{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "spec": {
     "nonResourceAttributes": {
        "path": "/debug",
        "verb": "get"
     },
     "user": "jane",
     "group": [
        "group1"
        "group2"
     ]
   }
}

 

小結:

        本節內容到此結束,謝謝大家的支持~

         多多點關注哦。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章