Kubernetes 中的安全基礎知識:身份驗證、授權、審計

Kubernetes 中的安全基礎知識:身份驗證、授權、審計

在任何系統的運作中,遲早都會出現安全性問題:確保身分驗證、權限分離、稽核和其他任務。 已經為 Kubernetes 創建了 許多解決方案,即使在非常苛刻的環境中,您也可以實現符合標準...相同的材料專門介紹了 K8 內建機制中實現的安全性的基本方面。 首先,它對於開始熟悉 Kubernetes 的人來說非常有用——作為研究安全相關問題的起點。

認證

Kubernetes 中有兩種類型的使用者:

  • 服務帳號 — 由 Kubernetes API 管理的帳戶;
  • 用戶 — 由外部獨立服務管理的「普通」使用者。

這些類型之間的主要區別在於,對於服務帳戶,Kubernetes API 中有特殊物件(它們被稱為 - ServiceAccounts),它們與命名空間和儲存在叢集中 Secrets 類型的物件中的一組授權資料相關聯。 此類使用者(服務帳戶)主要用於管理 Kubernetes 叢集中執行的程序對 Kubernetes API 的存取權限。

普通使用者在 Kubernetes API 中沒有條目:它們必須由外部機制管理。 它們適用於生活在集群外部的人員或進程。

每個 API 請求都與一個服務帳戶、一個使用者相關聯,或被視為匿名。

用戶認證數據包括:

  • 用戶名 — 使用者名稱(區分大小寫!);
  • UID - 機器可讀的使用者識別字串,「比使用者名稱更一致和唯一」;
  • — 使用者所屬群組的清單;
  • 額外 — 授權機制可以使用的附加欄位。

Kubernetes 可以使用大量的驗證機制:X509 憑證、承載令牌、驗證代理、HTTP 基本驗證。 使用這些機制,您可以實作大量授權方案:從具有密碼的靜態檔案到 OpenID OAuth2。

此外,可以同時使用多種授權方案。 預設情況下,集群使用:

  • 服務帳戶令牌 - 用於服務帳戶;
  • X509 - 對於使用者。

有關管理 ServiceAccounts 的問題超出了本文的範圍,但對於想要更詳細地熟悉此問題的人,我建議從 官方文件頁面。 我們將仔細研究 X509 證書如何運作的問題。

使用者證書 (X.509)

使用憑證的經典方法包括:

  • 密鑰產生:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • 產生憑證要求:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • 使用 Kubernetes 叢集 CA 金鑰處理憑證要求,取得使用者憑證(要取得證書,您必須使用有權存取 Kubernetes 叢集 CA 金鑰的帳戶,預設位於 /etc/kubernetes/pki/ca.key):
    openssl x509 -req -in ~/.certs/mynewuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/.certs/mynewuser.crt -days 500
  • 建立設定檔:
    • 叢集描述(指定特定叢集安裝的 CA 憑證檔案的位址和位置):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • 或如何 沒有推薦選項 - 您不必指定根憑證(那麼 kubectl 將不會檢查叢集 api-server 的正確性):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • 在設定檔中新增使用者:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • 新增上下文:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • 預設上下文分配:
      kubectl config use-context mynewuser-context

經過上述操作後,在文件中 .kube/config 將會建立這樣的配置:

apiVersion: v1
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/ca.crt
    server: https://192.168.100.200:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    namespace: target-namespace
    user: mynewuser
  name: mynewuser-context
current-context: mynewuser-context
kind: Config
preferences: {}
users:
- name: mynewuser
  user:
    client-certificate: /home/mynewuser/.certs/mynewuser.crt
    client-key: /home/mynewuser/.certs/mynewuser.key

為了更輕鬆地在帳戶和伺服器之間傳輸配置,編輯以下按鍵的值很有用:

  • certificate-authority
  • client-certificate
  • client-key

為此,您可以使用 base64 對其中指定的檔案進行編碼,並將它們註冊到配置中,將後綴新增到鍵的名稱中 -data, IE。 已收到 certificate-authority-data 等等

kubeadm 的證書

隨著發布 庫伯內斯 1.15 由於 alpha 版本的支持,使用憑證變得更加容易 kubeadm 實用程式。 例如,使用使用者金鑰產生設定檔現在可能如下所示:

kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200

NB: 必需的 廣告地址 可以在 api-server 配置中找到,預設位於 /etc/kubernetes/manifests/kube-apiserver.yaml.

產生的配置將輸出到 stdout。 需要保存在 ~/.kube/config 在使用者帳戶或環境變數中指定的文件 KUBECONFIG.

深入挖掘

對於那些想要更徹底地理解所描述的問題的人:

授權

預設授權帳號沒有叢集操作權限。 為了授予權限,Kubernetes 實作了授權機制。

在 1.6 版本之前,Kubernetes 使用一種稱為 阿巴克 (基於屬性的存取控制)。 有關它的詳細資訊可以在 官方文檔。 此方法目前被認為是遺留方法,但您仍然可以將其與其他身份驗證類型一起使用。

目前(且更靈活)劃分叢集存取權限的方式稱為 紅十字會 (基於角色的訪問控制)。 自版本起已宣布穩定 庫伯內斯 1.8。 RBAC 實作了一種權限模型,其中所有未明確允許的內容都被禁止。
啟用 RBAC,需要使用參數啟動 Kubernetes api-server --authorization-mode=RBAC。 這些參數在清單中使用 api-server 配置進行設置,預設位於路徑上 /etc/kubernetes/manifests/kube-apiserver.yaml,在部分 command。 但是,RBAC 預設已啟用,因此您很可能不必擔心:您可以透過值驗證這一點 authorization-mode (在已經提到的 kube-apiserver.yaml)。 順便說一句,其含義中可能還有其他類型的授權(node, webhook, always allow),但我們會將他們的考慮留在材料的範圍之外。

順便說一句,我們已經發布了 一篇文章 對使用 RBAC 的原理和功能進行了相當詳細的描述,因此我將僅簡要列出基礎知識和範例。

以下 API 實體用於透過 RBAC 控制 Kubernetes 中的存取:

  • Role и ClusterRole — 用於描述存取權限的角色:
  • Role 允許您描述名稱空間內的權限;
  • ClusterRole - 叢集內,包括特定於叢集的對象,例如節點、非資源 url(即與 Kubernetes 資源無關 - 例如, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - 用於綁定 Role и ClusterRole 到使用者、使用者群組或 ServiceAccount。

Role 和 RoleBinding 實體受命名空間限制,即必須位於同一命名空間內。 但是,RoleBinding 可以引用 ClusterRole,這允許您建立一組通用權限並使用它們來控制存取。

角色使用規則集描述權利,其中包含:

  • API 群組 - 請參閱 官方文檔 透過 apiGroups 和輸出 kubectl api-resources;
  • 資源 (資源: pod, namespace, deployment 等等。);
  • 動詞 (動詞: set, update 等等)。
  • 資源名稱(resourceNames) - 適用於您需要提供對特定資源而不是所有此類資源的存取權限的情況。

Kubernetes中授權的更詳細的分析可以在頁面找到 官方文檔。 相反地​​(或更確切地說,除此之外),我將舉一些例子來說明她的工作。

RBAC 實體範例

Простая Role,它允許您獲取 Pod 的列表和狀態並在命名空間中監視它們 target-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: target-namespace
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

例子 ClusterRole,它允許您獲取 Pod 的清單和狀態並在整個叢集中監視它們:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # секции "namespace" нет, так как ClusterRole задействует весь кластер
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

例子 RoleBinding,這允許用戶 mynewuser 「讀取」命名空間中的 Pod my-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: target-namespace
subjects:
- kind: User
  name: mynewuser # имя пользователя зависимо от регистра!
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # здесь должно быть “Role” или “ClusterRole”
  name: pod-reader # имя Role, что находится в том же namespace,
                   # или имя ClusterRole, использование которой
                   # хотим разрешить пользователю
  apiGroup: rbac.authorization.k8s.io

事件審核

概括地說,Kubernetes 架構可以表示如下:

Kubernetes 中的安全基礎知識:身份驗證、授權、審計

負責處理請求的關鍵 Kubernetes 元件是 api伺服器。 叢集上的所有操作都要經過它。 您可以在文章“中閱讀有關這些內部機制的更多資訊”當您執行 kubectl run 時,Kubernetes 中會發生什麼事?“。

系統審計是 Kubernetes 中一個有趣的功能,預設為停用。 它允許您記錄對 Kubernetes API 的所有呼叫。 正如您可能猜到的,與監視和變更叢集狀態相關的所有操作都是透過此 API 執行的。 其功能的詳細描述(像往常一樣)可以在以下位置找到: 官方文檔 K8s。 接下來,我將嘗試用更簡單的語言來表達這個主題。

因此, 啟用稽核,我們需要向 api-server 中的容器傳遞三個必要的參數,以下將詳細介紹:

  • --audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml
  • --audit-log-path=/var/log/kube-audit/audit.log
  • --audit-log-format=json

除了這三個必要的參數之外,還有許多與審核相關的附加設定:從日誌輪替到 Webhook 描述。 日誌輪轉參數範例:

  • --audit-log-maxbackup=10
  • --audit-log-maxsize=100
  • --audit-log-maxage=7

但我們不會更詳細地討論它們 - 您可以在以下位置找到所有詳細信息 kube-apiserver 文檔.

如前所述,所有參數均在清單中使用 api-server 配置進行設定(預設情況下 /etc/kubernetes/manifests/kube-apiserver.yaml),在部分 command。 我們回到3個必填參數來分析一下:

  1. audit-policy-file — 描述審核策略的 YAML 檔案的路徑。 我們稍後會返回到它的內容,但現在我會注意到該檔案必須可由 api 伺服器進程讀取。 因此,有必要將其掛載到容器內,為此您可以將以下程式碼新增至配置的相應部分:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — 日誌檔案的路徑。 該路徑也必須可供 api-server 進程訪問,因此我們以相同的方式描述其掛載:
      volumeMounts:
        - mountPath: /var/log/kube-audit
          name: logs
          readOnly: false
      volumes:
      - hostPath:
          path: /var/log/kube-audit
          type: DirectoryOrCreate
        name: logs
  3. audit-log-format — 審核日誌格式。 預設為 json,但舊版文字格式也可用(legacy).

審核政策

現在關於描述日誌記錄策略的上述文件。 審計政策的第一個概念是 level, 記錄層級。 它們如下:

  • None - 不記錄;
  • Metadata — 日誌請求元資料:使用者、請求時間、目標資源(pod、命名空間等)、操作類型(動詞)等;
  • Request — 記錄元資料和請求內文;
  • RequestResponse — 日誌元資料、請求正文和回應正文。

最後兩級(Request и RequestResponse)不記錄未存取資源的請求(存取所謂的非資源 url)。

所有請求也都會透過 幾個階段:

  • RequestReceived ——請求被處理器接收且尚未沿著處理器鏈進一步傳輸的階段;
  • ResponseStarted — 傳送回應標頭,但在傳送回應正文之前。 為長時間運行的查詢產生(例如, watch);
  • ResponseComplete — 回應內文已傳送,不再傳送任何訊息;
  • Panic — 當偵測到異常情況時產生事件。

要跳過您可以使用的任何步驟 omitStages.

在策略文件中,我們可以描述具有不同日誌記錄等級的多個部分。 將應用策略描述中找到的第一個符合規則。

kubelet 守護程式使用 api-server 設定監視清單中的更改,如果偵測到任何更改,則使用 api-server 重新啟動容器。 但有一個重要的細節: 策略文件中的變更將被忽略。 更改策略檔案後,您需要手動重新啟動 api-server。 由於 api-server 啟動為 靜態吊艙, 團隊 kubectl delete 不會導致它重新啟動。 你必須手動完成 docker stop 在 kube-masters 上,審計策略已更改:

docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')

啟用審核時,請務必記住 kube-apiserver 上的負載增加。 特別是,用於儲存請求上下文的記憶體消耗增加。 僅在發送回應標頭後才開始記錄。 負載也取決於審核策略配置。

政策範例

讓我們透過範例來了解策略文件的結構。

這是一個簡單的文件 policy記錄該層級的所有內容 Metadata:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

在策略中,您可以指定使用者清單(Users и ServiceAccounts)和用戶群組。 例如,這就是我們如何忽略系統用戶,但在該層級記錄其他所有內容 Request:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: None
    userGroups:
      - "system:serviceaccounts"
      - "system:nodes"
    users:
      - "system:anonymous"
      - "system:apiserver"
      - "system:kube-controller-manager"
      - "system:kube-scheduler"
  - level: Request

也可以描述目標:

  • 命名空間(namespaces);
  • 動詞 (動詞: get, update, delete 和別的);
  • 資源 (資源具體情況如下: pod, configmaps 等)和資源組(apiGroups).

注意! 可以使用下列命令取得資源和資源群組(API 群組,即 apiGroups)及其在叢集中安裝的版本:

kubectl api-resources
kubectl api-versions

提供以下審計政策作為最佳實踐的演示 阿里雲端文檔:

apiVersion: audit.k8s.io/v1beta1
kind: Policy
# Не логировать стадию RequestReceived
omitStages:
  - "RequestReceived"
rules:
  # Не логировать события, считающиеся малозначительными и не опасными:
  - level: None
    users: ["system:kube-proxy"]
    verbs: ["watch"]
    resources:
      - group: "" # это api group с пустым именем, к которому относятся
                  # базовые ресурсы Kubernetes, называемые “core”
        resources: ["endpoints", "services"]
  - level: None
    users: ["system:unsecured"]
    namespaces: ["kube-system"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["configmaps"]
  - level: None
    users: ["kubelet"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    userGroups: ["system:nodes"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    users:
      - system:kube-controller-manager
      - system:kube-scheduler
      - system:serviceaccount:kube-system:endpoint-controller
    verbs: ["get", "update"]
    namespaces: ["kube-system"]
    resources:
      - group: "" # core
        resources: ["endpoints"]
  - level: None
    users: ["system:apiserver"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["namespaces"]
  # Не логировать обращения к read-only URLs:
  - level: None
    nonResourceURLs:
      - /healthz*
      - /version
      - /swagger*
  # Не логировать сообщения, относящиеся к типу ресурсов “события”:
  - level: None
    resources:
      - group: "" # core
        resources: ["events"]
  # Ресурсы типа Secret, ConfigMap и TokenReview могут содержать  секретные данные,
  # поэтому логируем только метаданные связанных с ними запросов
  - level: Metadata
    resources:
      - group: "" # core
        resources: ["secrets", "configmaps"]
      - group: authentication.k8s.io
        resources: ["tokenreviews"]
  # Действия типа get, list и watch могут быть ресурсоёмкими; не логируем их
  - level: Request
    verbs: ["get", "list", "watch"]
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Уровень логирования по умолчанию для стандартных ресурсов API
  - level: RequestResponse
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Уровень логирования по умолчанию для всех остальных запросов
  - level: Metadata

審計政策的另一個很好的例子是 GCE 中使用的設定檔.

為了快速回應審計事件,可以 說明網路鉤子。 這個問題包含在 官方文檔,我將把它排除在本文的討論範圍之外。

結果

本文概述了 Kubernetes 叢集中的基本安全機制,可讓您建立個人化的使用者帳戶、分離他們的權限並記錄他們的操作。 我希望它對那些在理論或實踐中面臨此類問題的人有用。 我還建議您閱讀“PS”中給出的有關 Kubernetes 安全性主題的其他資料清單 - 也許您會在其中找到與您相關的問題的必要詳細資訊。

聚苯乙烯

另請閱讀我們的博客:

來源: www.habr.com

添加評論