在 kubernetes 中使用 rbac 設置服務帳戶權限¶
原文: https://blog.dudaji.com/kubernetes/2019/05/01/k8s-authorization-of-sa-with-rbac.html
想像一下,您的組織正在運行由多個工程團隊使用的單個 Kubernetes 集群。這些團隊中的每一個都獨立部署了相關的應用程序來開發和測試它。您希望每個團隊只處理他們自己的應用程序套件實例——每個團隊只想看到他們創建的對象,而不是其他團隊創建的對象。在單一個 Kubernetes 的集群裡可使用命名空間(namespace
)來實現。
使用多個namespace
允許您將具有大量組件的複雜系統劃分為由不同團隊管理的區域。它們還可用於在mult-tenant environment
的情境中來進行團隊的隔離。
大多數 Kubernetes API 物件類型都有命名空間,但也有少數沒有。 Pod
、ConfigMaps
、Secrets
、PersistentVolumeClaims
和 Events
都是命名空間。Nodes
, PersistentVolumes
, StorageClasses
, 和 Namespaces
本身則不是。
要查看資源
是命名空間還
是集群範圍
,請在運行 kubectl api-resources
時檢查 NAMESPACED
列。
場景¶
-
admin
:擁有所有權限 -
department-leader
:對命名空間 team-a 和 team-b 擁有權限 -
team-a-user
: 擁有命名空間 team-a 的權限,而沒有命名空間 team-b 的權限 -
team-b-user
: 擁有命名空間 team-b 的權限,對沒有命名空間 team-a 的權限
如何使用 Kubernetes 進行身份驗證¶
Kubernetes中有多種認證方式,如token、proxy、webhook、ID/PW、OAuth2等。更多詳細信息可在此處獲得。除了服務帳戶令牌身份驗證之外,Kubernetes 建議使用一種或多種用戶身份驗證方法。在本文中,我們將通過服務帳戶(Service account
)身份驗證方法來測試 kubernetes api 調用。
創建命名空間¶
創建 namespace:
檢查 namespace:
$ kubectl get ns
NAME STATUS AGE
default Active 6m14s
kube-node-lease Active 6m16s
kube-public Active 6m16s
kube-system Active 6m16s
team-a Active 8s
team-b Active 4s
創建服務帳戶¶
# sa-team-a-create.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa-team-a
namespace: team-a
# sa-team-b-create.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa-team-b
namespace: team-b
創建 service account:
檢查在不同 namespace 裡的 service account:
$ kubectl get sa -n team-a
NAME SECRETS AGE
default 1 5m47s
sa-team-a 1 22s
$ kubectl get sa -n team-b
NAME SECRETS AGE
default 1 5m46s
sa-team-b 1 17s
角色和角色綁定¶
角色定義了有關權限的事情。它定義了可以訪問的位置以及可以對哪些資源進行哪些操作。
RoleBinding
是連接 Role
和 User
的橋樑。換句話說,用戶被授予權限,但是關於權限的信息是由**角色**決定的。
我們可以直接定義一個新的角色,也可以使用 Kubernetes 預定義的角色來給予權限。ClusterRole
中預定義的權限是 cluster-admin
、admin
、edit
和 view
,根據綁定的類型(Rolebinding
、ClusterRolebinding
)來確定權限訪問範圍是命名空間還是整個集群。
來源:https ://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles
讓我們來創建一個客制的角色:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: custom-role
namespace: team-a
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: custom-rolebinding
namespace: team-a
subjects:
- kind: ServiceAccount
name: sa-team-a
namespace: team-a
roleRef:
kind: Role
name: custom-role
apiGroup: rbac.authorization.k8s.io
構建角色與權限並且進行綁定:
$ kubectl create -f custom-role-binding.yaml
role.rbac.authorization.k8s.io/custom-role created
rolebinding.rbac.authorization.k8s.io/custom-rolebinding created
使用內建的角色:
# default-role-binding.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: default-rolebinding
namespace: team-b
subjects:
- kind: ServiceAccount
name: sa-team-b
namespace: team-b
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
將清單應用於 Kubernetes
$ kubectl create -f default-role-binding.yaml
rolebinding.rbac.authorization.k8s.io/default-rolebinding created
創建一個 Pod¶
apiVersion: v1
kind: Pod
metadata:
name: pod-team-a
namespace: team-a
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 8080
apiVersion: v1
kind: Pod
metadata:
name: pod-team-b
namespace: team-b
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 8080
分別在兩個 namespace 各創建一個 pod:
$ kubectl create -f pod-team-a-create.yaml
pod/pod-team-a created
$ kubectl create -f pod-team-b-create.yaml
pod/pod-team-b created
API 測試¶
api服務器ip檢查
$ kubectl config view | grep server | cut -f 2- -d ":" | tr -d " " # display list of your api server
https://192.168.49.2:8443
也可用:
設定環境變數:
檢查 sa-team-a
的令牌:
NAMESPACE=team-a
SA=sa-team-a
TOKEN=$(kubectl -n $NAMESPACE describe secret $(kubectl get -n $NAMESPACE secrets | grep $SA | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ')
呼叫 Kubernetes API:
$ curl -X GET $APISERVER/api/v1/namespaces/$NAMESPACE/pods/ \
-H "Authorization: Bearer $TOKEN" --insecure
檢查 sa-team-b
的令牌:
NAMESPACE=team-b
SA=sa-team-b
TOKEN=$(kubectl -n $NAMESPACE describe secret $(kubectl get -n $NAMESPACE secrets | grep $SA | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ')
呼叫 Kubernetes API:
$ curl -X GET $APISERVER/api/v1/namespaces/$NAMESPACE/pods/ \
-H "Authorization: Bearer $TOKEN" --insecure
如果 system account
想要去訪問沒有權限的的 namespace
, 舉例: sa-team-b
訪問 team-a
。
$ SA=sa-team-b
$ NAMESPACE=team-b
$ TOKEN=$(kubectl -n $NAMESPACE describe secret $(kubectl get -n $NAMESPACE secrets | grep $SA | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ')
$ NAMESPACE=team-a
$ curl -X GET $APISERVER/api/v1/namespaces/$NAMESPACE/pods/ \
-H "Authorization: Bearer $TOKEN" --insecure
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:team-b:sa-team-b\" cannot list resource \"pods\" in API group \"\" in the namespace \"team-a\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
department-leader 和 admin¶
創建 department-leader
¶
department-leader
有命名空間 team-a
和 team-b
的權限,而對於 admin
,則擁有所有區域的權限。
# sa-leader.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa-leader
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: department-leader-team-a
namespace: team-b
subjects:
- kind: ServiceAccount
name: sa-leader
namespace: default
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: department-leader-team-b
namespace: team-a
subjects:
- kind: ServiceAccount
name: sa-leader
namespace: default
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
$ kubectl create -f sa-leader.yaml
serviceaccount/sa-leader created
rolebinding.rbac.authorization.k8s.io/department-leader-team-a created
rolebinding.rbac.authorization.k8s.io/department-leader-team-b created
$ SA=sa-leader
$ NAMESPACE=default
$ TOKEN=$(kubectl -n $NAMESPACE describe secret $(kubectl get -n $NAMESPACE secrets | grep $SA | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ')
$ NAMESPACE=team-a
$ curl -X GET $APISERVER/api/v1/namespaces/$NAMESPACE/pods/ \
-H "Authorization: Bearer $TOKEN" --insecure
$ NAMESPACE=team-b
$ curl -X GET $APISERVER/api/v1/namespaces/$NAMESPACE/pods/ \
-H "Authorization: Bearer $TOKEN" --insecure
創建 admin
¶
# sa-admin-create.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa-admin
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: admin-all-cluster
subjects:
- kind: ServiceAccount
name: sa-admin
namespace: default
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io