本次目標
API Server 是存取和管理資源對象的入口,不管是 kube-controllermanager、kube-scheduler、kubelet 和kube-proxy 等都要透過 API Server 進行存取。而每一次的訪問請求都須進行合法的驗證,如身分、操作權限等數據存入至 etcd 中。當請求到 API 時,會經歷幾個階段,如下圖所示:
當收到一個用戶端的請求後,會調用 Authentication 來驗證用戶端身分,如果前者驗證通過接著會驗證 Authorization 是否有權限去操作用戶端發送的請求(建立、讀取、刪除等),如果授權(Authorization)通過驗證必須在通過 Admission Control 檢測像是 namespace 是否存在、使否違反資源限制等。
使用者存取 API 可以透過 kubectl、函式庫或使用 REST 方式,然而可以操作的主體被分為人和 Pod 資源,其分別對應 User Account 和 Service Account。
上面兩種類型都可隸屬一或多個用戶組,而用戶組本身沒有操作權限,其本身只是一個 User Account 的邏輯集合。Kubernetes 有以下特殊目的的組
Kubernetes 用認證方式對 API 請求進行身份驗證,支援的認證有以下
認證過程會驗證以下屬性
API Server 支援以下幾種認證方式
--client-ca-file=SOMEFILE
啟用 API Server 客戶端證書身份驗證選項--token-auth-file=SOMEFILE
,API Server 從中讀取 bearer tokentoken,user,uid,"group1,group2,group3"
--basic-auth-file
加載,用戶名和密碼等令牌以明文格式儲存的 CSV 格式檔案--service-account-key-file
加載system:anonymous
,並屬於 system:unauthenticated
用戶組;在 API Server 啟用了除 AlwaysAllow
以外的認證機 制時,匿名用戶處於啟用狀態,但管理員可通過 --anonymousauth=false` 選項將其禁用API Server 主要支援以下授權機制來定義用戶操作的權限
最後 Admission Controller 用於在客戶端請求經過身份驗證和授權檢查之後,會在存入 etcd 時攔截該請求,進行語意驗證,其支援的方式有以下
當我們使用 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.crt
、namespace
和 token
,而 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 帳戶控制器,實現自動化。
ImagePullSecerts
,則將 Service Account 的 ImagePullSecerts
添加上去volumeMounts
,掛載至 /var/run/secrets/kubernetes.io/serviceaccount
在 /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
參數用於認證期間的檢驗。
當我們使用 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.crt
與 token
。
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 配置可以提供 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
上面結果訊息內容包含:
users
中某個使用者和 clusters
中某個集群名稱組合contexts
中某一個選項結構上可以參考此圖 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
是默認管理及群的權限。
以下是實現從本地端的 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 # 它會引導認證