k8s~ServiceAccount_ClusterRole_ClusterRoleBinding

张占岭發表於2024-08-26

apisix的k8s服務發現配置

名稱空間許可權是基於Kubernetes RBAC能力的授權,透過許可權設定可以讓不同的使用者或使用者組擁有操作不同Kubernetes資源的許可權。Kubernetes RBAC API定義了四種型別:Role、ClusterRole、RoleBinding與ClusterRoleBinding,這四種型別之間的關係和簡要說明如下:

  • Role:角色,其實是定義一組對Kubernetes資源(名稱空間級別)的訪問規則。
  • RoleBinding:角色繫結,定義了使用者和角色的關係。
  • ClusterRole:叢集角色,其實是定義一組對Kubernetes資源(叢集級別,包含全部名稱空間)的訪問規則。
  • ClusterRoleBinding:叢集角色繫結,定義了使用者和叢集角色的關係。

Role和ClusterRole指定了可以對哪些資源做哪些動作,RoleBinding和ClusterRoleBinding將角色繫結到特定的使用者、使用者組或ServiceAccount上。如下圖所示。

實踐部分

1 為了讓 APISIX 能查詢和監聽 Kubernetes 的 Endpoints 資源變動,我們需要建立一個 ServiceAccount:

kind: ServiceAccount
apiVersion: v1
metadata:
  name: apisix-test
  namespace: default

2 以及一個具有叢集級查詢和監聽 Endpoints 資源許可權的 ClusterRole:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: apisix-test
rules:
- apiGroups: [ "" ]
  resources: [ endpoints ]
  verbs: [ get,list,watch ]

3 再將這個 ServiceAccount 和 ClusterRole 關聯起來:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: apisix-test
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: apisix-test
subjects:
  - kind: ServiceAccount
    name: apisix-test
    namespace: default

4 然後我們需要獲取這個 ServiceAccount 的 token 值,如果 Kubernetes 是 v1.24 之前的版本,可以透過下面的方法獲取 token 值:

$ kubectl get secrets | grep apisix-test
$ kubectl get secret apisix-test-token-879xv -o jsonpath={.data.token} | base64 -d

5 Kubernetes 從 v1.24 版本開始,不能再透過 kubectl get secret 獲取 token 了,需要使用 TokenRequest API 來獲取,首先開啟代理:

$ kubectl proxy --port=8001
Starting to serve on 127.0.0.1:8001

6 然後呼叫 TokenRequest API 生成一個 token:

$ curl 'http://127.0.0.1:8001/api/v1/namespaces/default/serviceaccounts/apisix-test/token' \
  -H "Content-Type:application/json" -X POST -d '{}'
{
  "kind": "TokenRequest",
  "apiVersion": "authentication.k8s.io/v1",
  ...
  "status": {
    "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImtLdHRyVzFmNTRHWGFVUjVRS3hrLVJMSElNaXM4aENLMnpfSGk1SUJhbVkifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjc5NTMzMDQwLCJpYXQiOjE2Nzk1Mjk0NDAsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImFwaXNpeC10ZXN0IiwidWlkIjoiMzVjZWJkYTEtNGZjNC00N2JlLWIxN2QtZDA4NWJlNzU5ODRlIn19LCJuYmYiOjE2Nzk1Mjk0NDAsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmFwaXNpeC10ZXN0In0.YexM_VoumpdwZNbSkwh6IbEu59PCtZrG1lkTnCqG24G-TC0U1sGxgbXf6AnUQ5ybh-CHWbJ7oewhkg_J4j7FiSAnV_yCcEygLkaCveGIQbWldB3phDlcJ52f8YDpHFtN2vdyVTm79ECwEInDsqKhn4n9tPY4pgTodI6D9j-lcK0ywUdbdlL5VHiOw9jlnS7b60fKWBwCPyW2uohX5X43gnUr3E1Wekgpo47vx8lahTZQqnORahTdl7bsPsu_apf7LMw40FLpspVO6wih-30Ke8CNBxjpORtX2n3oteE1fi2vxYHoyJSeh1Pro_Oykauch0InFUNyEVI4kJQ720glOw",
    "expirationTimestamp": "2023-03-23T00:57:20Z"
  }
}

7 預設的 token 有效期只有一個小時,可以透過引數改為一年:

$ curl 'http://127.0.0.1:8001/api/v1/namespaces/default/serviceaccounts/apisix-test/token' \
  -H "Content-Type:application/json" -X POST \
  -d '{"kind":"TokenRequest","apiVersion":"authentication.k8s.io/v1","metadata":{"name":"apisix-test","namespace":"default"},"spec":{"audiences":["https://kubernetes.default.svc.cluster.local"],"expirationSeconds":31536000}}'

8 我們在 APISIX 的配置檔案 config.yaml 中新增如下內容( 將上面生成的 token 填寫到 token 欄位 ):

discovery:
  kubernetes:
    service:
      schema: https
      host: 127.0.0.1
      port: "6443"
    client:
      token: ...

這裡有一個比較坑的地方,port 必須是字串,否則會導致 APISIX 啟動報錯 invalid discovery kubernetes configuration: object matches none of the required

大功告成!

參考:https://www.aneasystone.com/archives/2023/03/apisix-service-discovery.html