K8S之安全認證
訪問控制
簡介
K8S 作為一個分布式集群管理工具,其內部部署大量應用,如何保證內部應用的安全性是重中之重,所謂的安全性其實就是保證對 K8S 的各種客戶端進行認證和授權操作
客戶端
在 K8S 集群中客戶端通常分為兩類
- User Account:一般是獨立於kubernetes之外的其他服務管理的用戶賬號。
- Service Account:kubernetes管理的賬號,用於為Pod的服務進程在訪問kubernetes時提供身份標識。
認證/授權/准入控制
API Service 是訪問和管理資源的唯一入口,任何一個請求都需要訪問 API Service,經歷如下流程
- Authentication(認證):身份鑒別,只有正確的賬號才能訪問
- Authorization(授權):判斷賬號是否有權限執行相應的動作
- Admission Control(注入控制):用於補充授權機制以實現更加精細的訪問控制功能
認證管理
K8S 客戶端認證方式
上述中說到 K8S 需要對賬戶進行認證,在 K8S 中提供了三種認證方式
- HTTP Base 認證
- 通過用戶名 + 密碼進行認證
- 該方式通過將用戶名與密碼通過 base64 進行編碼之后放入 HTTP 請求的 Header 的 Authorization 域里面發生給服務端,服務端接受到信息,提取用戶名與密碼之后在進行解碼,之后在進行用戶認證
- 由於使用 base64 進行編碼可以通過反編碼得到用戶名密碼因此該方式不安全
- HTTP Token
- 通過一個 Token 來標識一個合法的用戶
- 在該方式中每個用戶有一個唯一的 Token 用來標識用戶,當客戶端發起請求的時候在 HTTP 的 Header 中放入 Token,當服務端收到客戶端請求之后提取客戶端的 Token 信息,然后與服務器中保存的 Token 進行對比,進而驗證用戶信息
- HTTPS 證書認證
- 基於 CA 根證書簽名的雙向證書認證方式
- 這種認證方式是安全性最高的一種方式,但是同時也是操作起來最麻煩的一種方式。
HTTPS 認證
- 證書申請和下發,HTTPS 通信雙方想 CA 機構進行證書申請,CA機構下發根證書,服務端證書以及私鑰給申請者
- 客戶端和服務端進行雙向認證
- 客戶端向服務端發起請求,服務端向客戶端發送自己的證書,客戶端通過自己的私鑰對服務端的證書進行解密獲取服務端的公鑰,客戶端利用服務端的公鑰認證證書信息,如果信息一致則信任服務端
- 客戶端發送自己的證書給服務端,服務端接受到客戶端的證書之后使用私鑰解密獲取客戶端的公鑰,之后使用客戶的公鑰進行認證證書信息,如果一致則認可客戶端
- 服務端和客戶端進行通信
- 服務端和客戶端協商解密方案,並且產生一個隨機的秘鑰進行加密
- 客戶端將秘鑰發給服務端,之后雙方使用該加密秘鑰進行數據通信
注意: Kubernetes允許同時配置多種認證方式,只要其中任意一個方式認證通過即可
授權管理
概述
-
授權發生在認證成功之后,通過認證就可以知道請求用戶是誰,然后kubernetes會根據事先定義的授權策略來決定用戶是否有權限訪問,這個過程就稱為授權。
-
每個發送到API Server的請求都帶上了用戶和資源的信息:比如發送請求的用戶、請求的路徑、請求的動作等,授權就是根據這些信息和授權策略進行比較,如果符合策略,則認為授權通過,否則會返回錯誤。
授權策略
-
AlwaysDeny:表示拒絕所有請求,一般用於測試。
-
AlwaysAllow:允許接收所有的請求,相當於集群不需要授權流程(kubernetes默認的策略)。
-
ABAC:基於屬性的訪問控制,表示使用用戶配置的授權規則對用戶請求進行匹配和控制。
-
Webhook:通過調用外部REST服務對用戶進行授權。
-
Node:是一種專用模式,用於對kubelet發出的請求進行訪問控制。
-
RBAC:基於角色的訪問控制(kubeadm安裝方式下的默認選項)。
RBAC
概述
-
RBAC(Role Based Access Control):基於角色的訪問控制,主要是在描述一件事情:給哪些對象授權了哪些權限。
-
RBAC涉及到了下面幾個概念:
-
- 對象:User、Groups、ServiceAccount。
-
- 角色:代表着一組定義在資源上的可操作的動作(權限)的集合。
-
- 綁定:將定義好的角色和用戶綁定在一起。
RBAC還引入了4個頂級資源對象
- Role、ClusterRole:角色,用於指定一組權限。
- RoleBinding、ClusterRoleBinding:角色綁定,用於將角色(權限的集合)賦予給對象。
Role/ClusterRole
一個角色就是一組權限的集合,這里的權限都是許可形式的(白名單)。
role 資源清單文件
# Role只能對命名空間的資源進行授權,需要指定namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: authorization-role
namespace: dev
rules:
- apiGroups: [""] # 支持的API組列表,""空字符串,表示核心API群
resources: ["pods"] # 支持的資源對象列表
verbs: ["get","watch","list"]
ClusterRole的資源清單文件:
# ClusterRole可以對集群范圍內的資源、跨namespace的范圍資源、非資源類型進行授權
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: authorization-clusterrole
rules:
- apiGroups: [""] # 支持的API組列表,""空字符串,表示核心API群
resources: ["pods"] # 支持的資源對象列表
verbs: ["get","watch","list"]
rules中的參數說明:
apiGroups:
- 支持的API組列表。
- “”,”apps”,”autoscaling”,”batch”。
resources:
- 支持的資源對象列表。
- "services","endpoints","pods","secrets","configmaps","crontabs","deployments","jobs","nodes","rolebindings","clusterroles","daemonsets","replicasets","statefulsets","horizontalpodautoscalers","replicationcontrollers","cronjobs"。
verbs:
- 對資源對象的操作方法列表。
- "get", "list", "watch", "create", "update", "patch", "delete", "exec"。
RoleBinding、ClusterRoleBinding
角色綁定用來把一個角色綁定到一個目標對象上,綁定目標可以是User、Group或者ServiceAccount。
RoleBinding的資源清單文件:
# RoleBinding可以將同一namespace中的subject對象綁定到某個Role下,則此Subject具有該Role定義的權限
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: authorization-role-binding
namespace: dev
subjects:
- kind: User
name: SR
apiGroup: rbac.authorization.k8s.io
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: authorization-role
ClusterRoleBinding的資源清單文件:
# ClusterRoleBinding在整個集群級別和所有namespaces將特定的subject與ClusterRole綁定,授予權限
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: authorization-clusterrole-binding
subjects:
- kind: User
name: SR
apiGroup: rbac.authorization.k8s.io
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: authorization-clusterrole
RoleBinding引用ClusterRole進行授權
-
RoleBinding可以引用ClusterRole,對屬於同一命名空間內ClusterRole定義的資源主體進行授權。
-
一種很常用的做法是,集群管理員為集群范圍預定義好一組角色(ClusterRole),然后在多個命名空間中重復使用這些ClusterRole。這樣可以大幅度提高授權管理工作效率,也使得各個命名空間下的基礎性授權規則和使用體驗保持一致。
# 雖然authorization-clusterrole是一個集群角色,但是因為使用了RoleBinding
# 所以SR只能讀取dev命名空間中的資源
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: authorization-clusterrole-binding
subjects:
- kind: User
name: SR
apiGroup: rbac.authorization.k8s.io
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: authorization-clusterrole
RBAC實戰
創建一個只能管理dev命名空間下Pods資源的賬號。
創建賬號
# 創建證書
cd /etc/kubernetes/pki/ && (umask 077;openssl genrsa -out devman.key 2048)
# 簽名申請 申請的用戶是devman,組是devgroup
openssl req -new -key devman.key -out devman.csr -subj "/CN=devman/O=devgroup"
# 簽署證書
openssl x509 -req -in devman.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out devman.crt -days 3650
# 設置集群/用戶/上下文
kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://172.16.137.128:6443
kubectl config set-credentials devman --embed-certs=true --client-certificate=/etc/kubernetes/pki/devman.crt --client-key=/etc/kubernetes/pki/devman.key
kubectl config set-context devman@kubernetes --cluster=kubernetes --user=devman
# 切換devman 賬號
kubectl config use-context devman@kubernetes
# 查看
kubectl get pods -n dev
# 切換到 admin 賬戶
kubectl config use-context kubernetes-admin@kubernetes
創建Role和RoleBinding,為devman授權
# 創建配置文件
cat > dev-role.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dev-role
namespace: dev
rules:
- apiGroups: [""] # 支持的API組列表,""空字符串,表示核心API群
resources: ["pods"] # 支持的資源對象列表
verbs: ["get","watch","list"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: authorization-role-binding
namespace: dev
subjects:
# 針對用戶類型
- kind: User
name: devman
apiGroup: rbac.authorization.k8s.io
roleRef:
# 針對 role
kind: Role
name: dev-role
apiGroup: rbac.authorization.k8s.io
EOF
# 加載配置文件
[root@master k8s]# kubectl create -f dev-role.yaml
# 切換用戶再次驗證
kubectl config use-context devman@kubernetes
[root@master k8s]# kubectl get -n dev pod -o wide
准入控制
概述
-
通過了前面的認證和授權之后,還需要經過准入控制通過之后,API Server才會處理這個請求。
-
准入控制是一個可配置的控制器列表,可以通過在API Server上通過命令行設置選擇執行哪些注入控制器。
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
當前可配置的Admission Control(准入控制)
-
AlwaysAdmit:允許所有請求。
-
AlwaysDeny:禁止所有請求,一般用於測試。
-
AlwaysPullImages:在啟動容器之前總去下載鏡像。
-
DenyExecOnPrivileged:它會攔截所有想在Privileged Container上執行命令的請求。
-
ImagePolicyWebhook:這個插件將允許后端的一個Webhook程序來完成admission controller的功能。
-
Service Account:實現ServiceAccount實現了自動化。
-
SecurityContextDeny:這個插件將使用SecurityContext的Pod中的定義全部失效。
-
ResourceQuota:用於資源配額管理目的,觀察所有請求,確保在namespace上的配額不會超標。
-
LimitRanger:用於資源限制管理,作用於namespace上,確保對Pod進行資源限制。
-
InitialResources:為未設置資源請求與限制的Pod,根據其鏡像的歷史資源的使用情況進行設置。
-
NamespaceLifecycle:如果嘗試在一個不存在的namespace中創建資源對象,則該創建請求將被拒 絕。當刪除一個namespace時,系統將會刪除該namespace中所有對象。
-
DefaultStorageClass:為了實現共享存儲的動態供應,為未指定StorageClass或PV的PVC嘗試匹配默認StorageClass,盡可能減少用戶在申請PVC時所需了解的后端存儲細節。
-
DefaultTolerationSeconds:這個插件為那些沒有設置forgiveness tolerations並具有notready:NoExecute和unreachable:NoExecute兩種taints的Pod設置默認的“容忍”時間,為5min。
-
PodSecurityPolicy:這個插件用於在創建或修改Pod時決定是否根據Pod的security context和可用的 PodSecurityPolicy對Pod的安全策略進行控制