用戶賬戶與服務賬戶
Kubernetes 區分用戶賬戶和服務賬戶的概念主要基於以下原因:
- 用戶賬戶是針對人而言的。 服務賬戶是針對運行在pod中的進程而言的。
- 用戶賬戶是全局性的。 其名稱在集群各namespace中都是全局唯一的,未來的用戶資源不會做namespace隔離, 服務賬戶是namespace隔離的。
- 通常情況下,集群的用戶賬戶可能會從企業數據庫進行同步,其創建需要特殊權限,並且涉及到復雜的業務流程。 服務賬戶創建的目的是為了更輕量,允許集群用戶為了具體的任務創建服務賬戶 (即權限最小化原則)。
- 對人員和服務賬戶審計所考慮的因素可能不同。
- 針對復雜系統的配置可能包含系統組件相關的各種服務賬戶的定義。 因為服務賬戶可以定制化地創建,並且有namespace級別的名稱,這種配置是很輕量的。
UserAccount常用於復雜業務邏輯管控,作用於系統全局,獨立於K8s之外 ServiceAccount僅用於實現某些特定操作任務,隸屬於名稱空間,由API Server管理
訪問控制過程
客戶端 -> API Server -> 認證插件 -> 授權插件 -> 准入控制插件 -> 寫入成功
需要注意:認證授權過程只存在HTTPS形式的API中。也就是說,如果客戶端使用HTTP連接到kube-apiserver,是不會進行認證授權的。所以說,可以這么設置,在集群內部組件間通信使用HTTP集群, 外部就使用HTTPS,這樣既增加了安全性,也不至於太復雜。 |
- system:unauthenticated,未通過認證測試的用戶所屬的組
- system:authenticated,認證成功的用戶自動加入的組,用於快捷引用所有正常通過認證的用戶帳號
- system:serviceaccounts,當前系統上所有Service Account對象
- system:serviceaccounts:<namespace>,特定名稱空間內所有Service Account對象
認證. 授權與准入控制
- API Server支持同時啟用多種認證機制, 但至少包括UserAccount和ServiceAccount中的一種
- 啟用多種認證插件時, 認證過程會以串行方式進行, 直到一種成功即可, 認證失敗會返回401
認證方式
- X509客戶端證書認證:客戶端請求報文中攜帶X509格式證書,通過后,CN字段是用戶名,O字段是所屬的組,O可以有多個,即屬於多個組
- 靜態令牌文件:由kube-apiserver 選項--token-auth-file加載,啟動后不可更改;HTTP客戶端也能使用承載令牌進行身份驗證,將令牌編碼后,請求報文中Authorization承載傳遞
- 引導令牌:kubeadm join將節點加入集群時,就是這種方式
- 靜態密碼文件:用戶名密碼等以明文存儲的CSV格式文件,由kube-apiserver通過--basic-auth-file加載
- 服務帳戶令牌:由kube-apiserver自動啟用。ServiceAccount通常由API Server自動創建,並通過ServiceAccount准入控制器將其注入Pod對象,容器中應用請求API Server的服務時將以此完成身份證
- OpenID連接令牌:OAuth2認證
- Webhook令牌:客戶端使用kubeconfig格式的配置文件
- 認證代理:X-Remote-User
- Keystone密碼:借助Keystone服務器進行身份認證
- 匿名請求:未被任何驗證機制明確拒絕的用戶即匿名用戶,system:anonymous 屬於 system:unauthenticated組;匿名用戶可通過 --anonymous-auth=false禁用
內建的授權插件:
-
Node,基於Pod資源的目標調度節點來實現對kubelet的訪問控制
-
ABAC,基於屬性的訪問控制,attribute-based access control
-
RBAC,基於角色的訪問控制,role-based access control
-
Webhook,基於HTTP回調機制通過外部REST服務檢查確認用戶授權的訪問控制
-
AlwaysDeny,總是拒絕,僅用於測試
-
AlwaysAllow,總是允許
啟用API Server時 --authorization-mode定義要啟用的授權機制,多個選項以逗號分隔
准入控制器
在對象持久化存儲etcd前,強制執行對象的語義驗證等功能
讀取資源信息的請求不會經過准入控制器檢查
- AlwaysAdmit,允許所有請求
- AlwaysDeny,拒絕所有請求,僅用於測試
- AlwaysPullImages,總是下載鏡像
- NamespaceLifecycle,拒絕在不存在的名稱空間創建資源,刪除名稱空間會級聯刪除其下所有資源
- LimitRanger,可用資源范圍界定,確保資源請求不會超限
- ServiceAccount,實現ServiceAccount管理機制自動化,創建Pod對象時自動為其附加相關ServiceAccount對象
- PersistnetVolumeLabel,為由雲計算服務商提供的PV自動附加region或zone標簽
- DefaultStorageClass,監控所有創建PVC對象的請求,保證沒有附加專用StorageClass的請求會自動設定一個默認值
- ResourceQuota,對名稱空間設置可用資源上限,確保在其中創建的設置了資源限額的對象不會超出名稱空間的資源配額
- DefaultTolerationSeconds,如果Pod對象上不存在污點寬容期限,則為它們設置默認寬容期,以寬容 notready:NoExecute 和 unreachable:NoExctute 類污點5min
- ValidatingAdmissionWebhook,並行調用匹配當前請求的所有驗證類Webhook,任何一個校驗失敗,請求即失敗
- MutatingAdmissionWebhook,串行調用匹配當前請求的所有變異類Webhook,每個調用都可能會更改對象
ServiceAccount管理與應用
Service Account 資源一般由用戶名和相關的Secret對象組成 用於讓Pod對象內的容器進程訪問其他服務時提供身份認證信息,這些其他服務包括:API 調度器 Pod控制器 節點控制器 私有Registry服務等 |
Service Account 自動化
每個Pod都會自動關聯一個存儲卷,掛載至 /var/run/secrets/kubernetes.io/serviceaccount
[root@master ~]# kubectl exec nginx-554b9c67f9-r5852 ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt # 這是API Server的CA公鑰證書,用於Pod中的Process對API Server的服務端數字證書進行校驗時使用的
namespace
token # token保存了Service Account的認證token 容器中進程使用它向API Server發起連接請求
每個Pod對象都只有一個服務帳戶,若創建時未明確指定,會自動附加當前名稱空間中默認服務帳戶default |
K8s中的SSL/TLS認證
- etcd集群內對等節點通信:默認2380端口,基於SSL/TLS通信
- etcd服務器與客戶端通信:Restful API 默認2379端口,基於SSL/TLS通信
創建一個ServiceAccount
#測試
[root@master ~]# kubectl create serviceaccount admin -o yaml --dry-run #干跑
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: null
name: admin
kubectl create serviceaccount admin
#查看以創建的service帳號
[root@master ~]# kubectl get sa
NAME SECRETS AGE
admin 1 6s
default 1 24d
#查看詳細信息
kubectl describe sa admin
##簡潔輸出
kubectl get pods myapp-0 -o yaml --export
pod使用上述創建的ServiceAccount
apiVersion: v1
kind: Pod
metadata:
name: pod-sa-demo
namespace: default
labels:
app: myapp
tier: frontend
annotations:
leiyan.com/reatedby: "cluster admin"
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
serviceAccountName: admin
客戶端配置文件kubeconfig
包括kubectl、kubelet、kube-controller-manager等在內的API Server的各類客戶端都可以使用kubeconfig配置文件提供接入多個集群的相關配置信息
包括API Server的URL及認證信息,且可設置不同的上下文,並在各環境之間快速切換
/etc/kubernetes/admin.conf
即為kubeconfig
格式的配置文件
查看當前正在使用的配置文件, 上下文是集群和用戶的配對 |
[root@master ~]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.0.0.50: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
kubeconfig配置文件可通過kubectl config命令進行設定
kubectl config view,打印文件內容
kubectl config set-cluster,設置clusters段
kubectl config set-credentials,設置users段
kubectl config set-context,設置contexts段
kubectl config set-use-context,設置current-context段
添加ServiceAccount
-
為帳號kube-user1創建私鑰及證書文件,保存於/etc/kubernetes/pki目錄中 #需要在master節點以root用戶執行
cd /etc/kubernetes/pki (umask 077; openssl genrsa -out kube-user1.key 2048) openssl req -new -key kube-user1.key -out kube-user1.csr -subj "/CN=kube-user1/O=kubeusers" # 其中 CN是用戶名,O是用戶組 openssl x509 -req -in kube-user1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out kube-user1.crt -days 3650 openssl x509 -in kube-user1.crt -text -noout # 驗證證書(可選)
-
以默認管理員 kubernetes-admin@kubernetes為新用戶kube-user1設定配置文件,默認保存於 .kube/config 也可使用 --kubeconfig指定自定義路徑
2.1 配置集群信息,存在可省略此步驟
kubectl config set-cluster kubernetes-new --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server="https://10.0.0.50:6443"
2.2 配置客戶端證書及密鑰,用戶名組名會自動提取
kubectl config set-credentials kube-user1 --embed-certs=true --client-certificate=/etc/kubernetes/pki/kube-user1.crt --client-key=/etc/kubernetes/pki/kube-user1.key
2.3 配置context,組合cluster和credentials
kubectl config set-context kube-user1@kubernetes-new --cluster=kubernetes-new --user=kube-user1
2.4 指定當前上下文
kubectl config use-context kube-user1@kubernetes-new
2.5 測試
[root@master pki]# kubectl get pods Error from server (Forbidden): pods is forbidden: User "kube-user1" cannot list resource "pods" in API group "" in the namespace "default" #切換回來 kubectl config use-context kubernetes-admin@kubernetes [root@master pki]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-554b9c67f9-r5852 1/1 Running 0 89m pod-cm-1 1/1 Running 0 6d pod-cm-2 1/1 Running 0 6d pod-hostpath-demo 1/1 Terminating 0 7d21h
角色訪問控制RBAC (Role-Based Access Control)
相關概念
Role與ClusterRole
在RBAC API中,一個角色包含了一套表示一組權限的規則。 權限以純粹的累加形式累積(沒有”否定”的規則)。 角色可以由命名空間(namespace)內的Role
對象定義,而整個Kubernetes集群范圍內有效的角色則通過ClusterRole
對象實現。
一個Role對象只能用於授予對某一單一命名空間中資源的訪問權限。 以下示例描述了”default”命名空間中的一個Role對象的定義,用於授予對pod的讀訪問權限: |
[root@master manifests]# cat role-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pods-reader
namespace: default
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
[root@master manifests]# kubectl apply -f role-demo.yaml
role.rbac.authorization.k8s.io/pods-reader created
將role和user綁定, 並驗證已經生效, 可以get到pod資源
# 將kube-user1和pods-reader綁定
[root@master manifests]# kubectl create rolebinding kube-user1-read-pods --role=pods-reader --user=kube-user1
rolebinding.rbac.authorization.k8s.io/kube-user1-read-pods created
# 切換用戶到kube-user1
[root@master manifests]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
# 測試可以get到pod信息
[root@master manifests]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-0 1/1 Running 0 5d4h
myapp-1 1/1 Running 0 5d4h
myapp-2 1/1 Running 0 5d4h
myapp-3 1/1 Running 0 5d4h
ClusterRole對象可以授予與Role對象相同的權限,但由於它們屬於集群范圍對象, 也可以使用它們授予對以下幾種資源的訪問權限: |
創建ClusterRole
[root@master manifests]# cat cluster-role-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-role
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
[root@master manifests]# kubectl apply -f cluster-role-demo.yaml
clusterrole.rbac.authorization.k8s.io/cluster-role created
將ClusterRole
和User
綁定, 並驗證權限是否生效
[root@master manifests]# cat clusterrolebinding-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: user1-read-all-pods
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kube-user1
[root@master manifests]# kubectl apply -f clusterrolebinding-demo.yaml
clusterrolebinding.rbac.authorization.k8s.io/user1-read-all-pods created
驗證權限
# 切換用戶到kube-user1
[root@master manifests]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
# 成功獲取到默認namespace的pod信息
[root@master manifests]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-0 1/1 Running 0 5d4h
myapp-1 1/1 Running 0 5d4h
myapp-2 1/1 Running 0 5d4h
myapp-3 1/1 Running 0 5d4h
# 成功獲取到其他namespace的pod信息
[root@master manifests]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-7995bd9c47-crpwt 1/1 Running 0 12d
RoleBinding與ClusterRoleBinding
角色綁定將一個角色中定義的各種權限授予一個或者一組用戶。 角色綁定包含了一組相關主體(即subject, 包括用戶——User、用戶組——Group、或者服務賬戶——Service Account)以及對被授予角色的引用。 在命名空間中可以通過RoleBinding
對象授予權限,而集群范圍的權限授予則通過ClusterRoleBinding
對象完成。
RoleBinding可以引用在同一命名空間內定義的Role對象。 下面示例中定義的RoleBinding對象在”default”命名空間中將”pod-reader”角色授予用戶”kube-user1”。 這一授權將允許用戶”kube-user1”從”default”命名空間中讀取pod。 |
RoleBinding對象也可以引用一個ClusterRole對象用於在RoleBinding所在的命名空間內授予用戶對所引用的ClusterRole中 定義的命名空間資源的訪問權限。這一點允許管理員在整個集群范圍內首先定義一組通用的角色,然后再在不同的命名空間中復用這些角色。 |
[root@master manifests]# cat rolebinding-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: user1-read-pods
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kube-user1
[root@master manifests]# kubectl apply -f rolebinding-clusterrole.yaml
rolebinding.rbac.authorization.k8s.io/user1-read-pods created
這時候發現只能獲取到RoleBinding
設置的namespace
中的pod
了
[root@master ~]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-0 1/1 Running 0 5d4h
myapp-1 1/1 Running 0 5d4h
myapp-2 1/1 Running 0 5d4h
myapp-3 1/1 Running 0 5d4h
[root@master ~]# kubectl get pod -n ingress-nginx
Error from server (Forbidden): pods is forbidden: User "kube-user1" cannot list resource "pods" in API group "" in the namespace "ingress-nginx"
最后將ClusterRole
和User
通過ClusterRoleBinding
綁定到一起
允許用戶kube-user1讀取所有namespace的pod信息
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: user1-read-all-pods
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kube-user1
[root@master manifests]# kubectl apply -f clusterrolebinding-demo.yaml
clusterrolebinding.rbac.authorization.k8s.io/user1-read-all-pods created
[root@master manifests]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
[root@master manifests]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-0 1/1 Running 0 5d7h
myapp-1 1/1 Running 0 5d7h
myapp-2 1/1 Running 0 5d7h
myapp-3 1/1 Running 0 5d7h
[root@master manifests]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-7995bd9c47-crpwt 1/1 Running 0 13d