iT邦幫忙

2024 iThome 鐵人賽

DAY 12
0

本次目標

  1. 了解 Authentication、Authorization
  2. 了解 Service Account
  3. 配置 配置 kubeconfig

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

From Kubernetes.io

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

使用者存取 API 可以透過 kubectl、函式庫或使用 REST 方式,然而可以操作的主體被分為人和 Pod 資源,其分別對應 User Account 和 Service Account。

  • User Account
    • 非 kubernetes 所使用的管理帳號,像是密鑰、Keystone 或是以檔案方式的使用者和密碼列表名稱需是唯一值
  • Service Account
    • 是 Kubernetes API 所管理的帳號,使用在 POD 之中的服務行程訪問 Kubernetes API 時提供的身分標識
    • 一般會綁定特定 namespace,會附帶 Secret 資源的憑證(token)用於訪問 API Server

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

  • system:unauthenticated
    • 未能通過任何一個 Authentication 檢驗的帳號
  • system:authenticated
    • 驗證中的用戶自動加入的一個組,用於快速引用所有通過認證的用戶帳號
  • system:serviceaccounts
    • 當前系統尚所有 Service Account 物件
  • system:serviceaccounts:
    • 特定 namespace 下的 Service Account 帳號

Authentication、Authorization 和 Admission Control

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

  • 證書
  • bearer tokens
  • authenticating proxy
  • HTTP basic

認證過程會驗證以下屬性

  • Username
  • UID
  • Groups
  • Extra

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

  • X509
    • 藉由 --client-ca-file=SOMEFILE 啟用 API Server 客戶端證書身份驗證選項
  • Static Token File
    • 使用 --token-auth-file=SOMEFILE,API Server 從中讀取 bearer token
    token,user,uid,"group1,group2,group3"
    
  • Bootstrap Tokens
  • 靜態密碼檔案
    • 使用 --basic-auth-file 加載,用戶名和密碼等令牌以明文格式儲存的 CSV 格式檔案
  • Service Account Token
    • 使用 --service-account-key-file 加載
  • OpenID Connect Tokens
    • OAuth2 風格
  • Webhook Token
  • Authentication Proxy
  • Keystone
  • 匿名請求
    • 未被任何驗證機制明確拒絕的用戶即為匿名用戶,其會被自動標識為用戶名 system:anonymous,並屬於 system:unauthenticated 用戶組;在 API Server 啟用了除 AlwaysAllow 以外的認證機 制時,匿名用戶處於啟用狀態,但管理員可通過 --anonymousauth=false` 選項將其禁用

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

  • Node
    • 基於 POD 資源的目標調度節點來實現的對 kubelet 的訪問控制
  • ABAC(attribute-based access control)
  • RBAC(role-based access control)
  • WebHook
    • 基於 HTTP 回調機制由外部 REST 服務檢查確認用戶授權的訪問控制

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

  • AlwaysAdmit
  • AlwaysDeny
  • AlwaysPullImages
  • NamespaceLifecycle
  • LimitRanger
  • ServiceAccount
  • PersistentVolumeLabel
  • DefaultStorageClass
  • ResourceQuota
  • DefaultTolerationSeconds
  • ValidatingAdmissionWebhook
  • MutatingAdmissionWebhook

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 帳戶控制器,實現自動化。

  • Service Account 帳戶控制器負責為 namespace 管理相應資源,且確保每個 namespace 中都存在一個 default 的 Service Account 物件。
  • Service Account 准入控制器是 API Server 的一部分,負責在建立更新 POD 時對其按需進行 Service Account 物件相關資訊的修改,包括如下操作:
    • POD 沒有明確定義使用哪個 Service Account 物件時,則將設定為 default
    • 確定 POD 正確引用已存在的 Service Account
    • POD 中未定義 ImagePullSecerts,則將 Service Account 的 ImagePullSecerts 添加上去
    • 為帶有訪問 API 的 Token 的 POD 添加一個儲存卷
    • 為 POD 中每個容器添加一個 volumeMounts,掛載至 /var/run/secrets/kubernetes.io/serviceaccount
  • token controller 是 controller-manager 的子元件,負責以下
    • 監控 Service Account 的建立操作,且為其新增用於訪問 API 的 Secret 物件
    • 監控 Service Account 的刪除操作,且刪除其相關的所有 Service Account token
    • 監控 Secret 物件的新增操作,確保其引用的 Service Account 已存在,且在必要時為 Secret 物件新增認證 token
    • 監控 Secret 物件的刪除操作,確保刪除每個 Service Account 中對此 Secret 的引用

/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

如果該 Service Account 需要 token 時需要透過一個 Secret 進行綁定。綁定後該 Secret 資源將會有 ca.crttoken


apiVersion: v1
kind: Secret
metadata:
  name: emqx
  namespace: default
  annotations:
    kubernetes.io/service-account.name: emqx
type: kubernetes.io/service-account-token

建立一個 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
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://ithome.cch.com:6500
  name: k3d-ithome-lab-cluster
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
- context:
    cluster: k3d-ithome-lab-cluster
    user: admin@k3d-ithome-lab-cluster
  name: k3d-ithome-lab-cluster
current-context: k3d-ithome-lab-cluster
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: admin@k3d-ithome-lab-cluster
  user:
    client-certificate-data: DATA+OMITTED
    client-key-data: DATA+OMITTED

上面結果訊息內容包含:

  • clusters
    • 包含訪問 API Server 的 URL 和所屬集群名稱
  • users
    • 包含訪問 API Server 時使用者名稱和認證訊息
  • contexts
    • kubelete 的可用上下文,從 users 中某個使用者和 clusters 中某個集群名稱組合
  • current-context
    • 當前使用的上下文名稱,contexts 中某一個選項

結構上可以參考此圖 &quot;https://eliu.github.io/2020/03/28/manage-kubeconfig/&quot;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 # 它會引導認證

參考資源


上一篇
當 Quarkus 遇到 HPA
下一篇
Kubernetes 的 Role-Based Access Control
系列文
當 Quarkus 想要騎乘駱駝並用8腳章魚掌控舵手 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言