kubernetes 之訪問安全控制

October 16, 2021

Controlling Access to the Kubernetes API

API Server 是存取和管理資源對象的入口,不管是 kube-controllermanager、kube-scheduler、kubelet 和kube-proxy 等都要透過 API Server 進行存取。而每一次的訪問請求都須進行合法的驗證,如身分、操作權限等,當這些流程都為正常才能將書據存入 etcd 中。當請求到 API 時,會經歷幾個階段,如下圖所示:

當收到一個用戶端的請求後,會調用 Authentication 來驗證用戶端身分,如果前者驗證通過接著會驗證 Authorization 是否有權限去操作用戶端發送的請求(建立、讀取、刪除等),如果授權(Authorization)通過驗證必須在通過 Admission Control 檢測像是 namespace 是否存在、使否違反資源限制等。

用戶端存取 API 可以透過 kubectl、函式庫或使用 REST 方式,然而可以操作的主體被分為人和 POD 物件,其分別對應 User AccountService Account

上面兩種類型都可隸屬一或多個用戶組,而用戶組本身沒有操作權限,其本身只是一個 User Account 的邏輯集合。Kubernetes 有以下特殊目的的組

Authentication、Authorization 和 Admission Control

Kubernetes 用認證方式對 API 請求進行身份驗證,支援的認證有以下

認證過程會驗證以下屬性

API Server 支援以下幾種認證方式

authentication 官方資源

API Server 主要支援以下授權機制來定義用戶操作的權限

authorization 官方資源

最後 Admission Controller 用於在客戶端請求經過身份驗證和授權檢查之後,會在存入 etcd 時攔截該請求,進行語意驗證,其支援的方式有以下

官方資源

Service Account 管理與應用

當我們使用 kubectl run nginx --image=nginx:latest 運行一個 nginx 應用時,此 POD 會自動關連一個儲存卷,並讓該容器掛載。如下使用 kubectl describe 進行觀察

...
Containers:
  nginx:
    Container ID:
    Image:          nginx:latest
    ...
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-fmjkg (ro)
...
Volumes:
  default-token-fmjkg:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-fmjkg
    Optional:    false
....

當我們使用 kubectl describe secrets 該 SecretName 對應的物件時,會發現其有三個資料分別是 ca.crtnamespacetoken,而 token 儲存了 Service Account 的認證 token,容器中的行程使用它向 API Server 發送連接請求,接著進行 Authentication 驗證,在將其用戶名稱傳遞給 Authorization 進行下一階段驗證。每個 POD 對象都只有一個 Service Account,如果未明確指定,Admission Controller 會自動使用當前 namespace 的默認 Service Account,通常是 default,如下。

kubectl describe serviceaccounts default 
Name:                default
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   default-token-fmjkg
Tokens:              default-token-fmjkg
Events:              <none>

Kubernetes 透過 Service Account 准入控制器、令牌控制器(token controller)和 Service Account 帳戶控制器,實現自動化。

/etc/kubernetes/manifests/kube-controller-manager.yaml 這個檔案有一個 --service-account-private-key-file=/etc/kubernetes/pki/sa.key 配置它用於對生成的 Service Account token 進行簽章,以確保完整性。同樣的在 kube-apiserver.yaml 中使用了 --service-account-signing-key-file=/etc/kubernetes/pki/sa.key 參數用於認證期間的檢驗。

Create Service Account

當我們使用 kubectl get serviceaccounts --all-namespaces 進行觀察時每個 namespace 下都會存在一個 default 物件,其讓 POD 有權限讀取同一 namespace 下的其它資源。因此要讓 POD 有更大權限時,使用者必須自定義 Service Account 資源。當然一個 POD 物件最多也只能存在一個 Service Account 資源,可以透過 spec.serviceAccountName 指定要使用的 Service Account 物件,否則就是 default。

如何建立呢 ?可以透過 kubectl create servic-eaccount 或是 yaml 檔案形式如下:

apiVersion: v1
kind: ServiceAccount
metadata:
    name: emqx # 建立一個 emqx 的服務帳戶
    namespace: default

建立一個 Deployment 物件,並指定 emqx 的服務帳戶

apiVersion: apps/v1
kind: Deployment
metadata:
  name: emqx-cluster
  namespace: emqx-ns
  labels:
    app: emqx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: emqx-app
  template:
    metadata:
      labels:
        app: emqx-app
    spec:
      serviceAccountName: emqx # this
...

當 POD 向 API Server 發送請求時,其設定的 token 在通過認證後將由 Authorization 進行 Service Account 是否有權限訪問所請求資源的判定,而當前 RBAC 為主流。

配置 kubeconfig

透過 kubeconfig 配置可以提供 kubectl、kubelet 等元件提供集群相關的配置,並且能夠設定上下文環境,並在不同環境中進行切換。

                          -----> kubernetes cluster1 API Server
                         /
Kubectl -----> kubeconfig
                         \
                          -----> kubernetes cluster2 API Server

當使用 kubeadm init 初始化 Kubernetes 集群後 /etc/kubernetes/admin.conf 檔案是 kubeconfig 格式的配置檔案,藉由 kubectl 加載至預設路徑 $HOME/.kube/config

透過 kubectl config view 可以獲取當前使用的環境配置。

$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://172.17.205.10:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

上面結果訊息內容包含:

結構上可以參考此圖 “https://eliu.github.io/2020/03/28/manage-kubeconfig/from https://eliu.github.io/2020/03/28/manage-kubeconfig/

簡單的說使用 kubectl 後操作 current-context 然後對應 contexts 中某一個選項。

對我們來說也可自訂義相關配置訊息至 kubeconfig 檔案中,並實現不同帳號接入集群功能。這些操作可使用 kubectl config 方式來操作

kubectl config view # 列出 kubeconfig 內容
kubectl config set-cluster # 設定 kubeconfig 中 clusters
kubectl config set-credentials # 設定 kubeconfig 中 users
kubectl config set-context # 設定 kubeconfig 中 contexts
kubectl config use-context # 設定 kubeconfig 中 current-context

初始化集群後,/etc/kubernetes/admin.conf 是默認管理及群的權限。

官方可參考資源

實作地端操作 GKE

以下是實現從本地端的 K8s 群集操作 GKE。先從 GKE 上的群集 .kube/config 進行複製並貼上至本地端主機 master 上,這邊將其複製到 gke1 檔案。

$ KUBECONFIG=gke1:~/.kube/config kubectl config view
 # gke1 是 GKE 的 key
 # DATA+OMITTED 會導致資訊不完全因此需用以下方式攤平
$ KUBECONFIG=gke1:~/.kube/config kubectl config view --flatten
$ KUBECONFIG=gke1:~/.kube/config kubectl config view --flatten > new

$ KUBECONFIG=new kubectl config get-contexts
CURRENT   NAME                                                    CLUSTER                                                 AUTHINFO                                                NAMESPACE
*         gke_sunny-catwalk-286908_us-central1-c_cluster-1-test   gke_sunny-catwalk-286908_us-central1-c_cluster-1-test   gke_sunny-catwalk-286908_us-central1-c_cluster-1-test
          gke_sunny-catwalk-286908_us-central1-c_cluster-2-test   gke_sunny-catwalk-286908_us-central1-c_cluster-2-test   gke_sunny-catwalk-286908_us-central1-c_cluster-2-test
          kubernetes-admin@kubernetes                             kubernetes                                              kubernetes-admin
$ KUBECONFIG=new kubectl config use-context kubernetes-admin@kubernetes # 切換
Switched to context "kubernetes-admin@kubernetes".
$ KUBECONFIG=new kubectl config get-contexts
CURRENT   NAME                                                    CLUSTER                                                 AUTHINFO                                                NAMESPACE
          gke_sunny-catwalk-286908_us-central1-c_cluster-1-test   gke_sunny-catwalk-286908_us-central1-c_cluster-1-test   gke_sunny-catwalk-286908_us-central1-c_cluster-1-test
          gke_sunny-catwalk-286908_us-central1-c_cluster-2-test   gke_sunny-catwalk-286908_us-central1-c_cluster-2-test   gke_sunny-catwalk-286908_us-central1-c_cluster-2-test
*         kubernetes-admin@kubernetes                             kubernetes                                              kubernetes-admin
$ KUBECONFIG=new kubectl get nodes
NAME     STATUS   ROLES    AGE     VERSION
master   Ready    master   5d18h   v1.18.8
node01   Ready    <none>   5d17h   v1.18.8
node02   Ready    <none>   5d17h   v1.18.8

切換至 GKE 叢集

cch@master:~/context$ KUBECONFIG=new kubectl config use-context gke_sunny-catwalk-286908_us-central1-c_cluster-1-test
Switched to context "gke_sunny-catwalk-286908_us-central1-c_cluster-1-test".
cch@master:~/context$ KUBECONFIG=new kubectl config current-context
gke_sunny-catwalk-286908_us-central1-c_cluster-1-test
cch@master:~/context$ KUBECONFIG=new kubectl get nodes
NAME                                            STATUS   ROLES    AGE     VERSION
gke-cluster-1-test-default-pool-255d7fb2-1f8l   Ready    <none>   4d12h   v1.15.12-gke.2
gke-cluster-1-test-default-pool-255d7fb2-lbwc   Ready    <none>   4d12h   v1.15.12-gke.2
gke-cluster-1-test-default-pool-255d7fb2-ppnm   Ready    <none>   4d12h   v1.15.12-gke.2

切記 cloud sdk 需要安裝,之後才能操作

$ echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | 
$ sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
$ sudo apt-get install apt-transport-https ca-certificates gnupg
$ curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
$ sudo apt-get update && sudo apt-get install google-cloud-sdk
$ gcloud auth login # 它會引導認證