一、前言
? ? 安全是K8S重要的特性,在K8S初級入門系列之四-Namespace/ConfigMap/Secret章節(jié),我們已經(jīng)已經(jīng)了解了Namespace,Secret與安全相關(guān)的知識。本篇將梳理K8S在安全方面的策略。主要包括兩個方面,API安全訪問策略以及Pod安全策略。
二、用戶/用戶組
在介紹安全前,我們先了解下用戶和用戶組的概念。
?1、用戶
在K8S中,用戶分為兩種:
- 真實的用戶,即User,如K8S的管理員,開發(fā)者等。
- Pod的賬號,即Service Account,是給運行在Pod里面的進程提供必要的身份證明,通過其來限制Pod的訪問權(quán)限。
? ? ? ?這里重點看下Service Account,每個命名空間(namespace)都有一個默認的Service Account。如果Pod不指定ServiceAccount,則使用該空間中默認的。
[root@k8s-master ~]# kubectl get sa
NAME SECRETS AGE
default 1 203d
(1)自定義ServiceAccount
當然,我們也可以自定義一個ServiceAccount,其yaml如下:
[root@k8s-master yaml]# cat my-serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-servicesaccount
namespace: default
創(chuàng)建完成后,查看詳情
[root@k8s-master yaml]# kubectl describe sa my-servicesaccount
Name: my-servicesaccount
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: my-servicesaccount-token-cz8kp
Tokens: my-servicesaccount-token-cz8kp
Events: <none>
? ?可以看到 mountable secret和tokens都關(guān)聯(lián)了一個名為my-servicesaccount-token-cz8kp的secret,我們查看其secret的詳情
[root@k8s-master yaml]# kubectl describe secret my-servicesaccount-token-cz8kp
Name: my-servicesaccount-token-cz8kp
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: my-servicesaccount
kubernetes.io/service-account.uid: 1f493157-13e7-4d43-9f0b-b8779dfe84ae
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1099 bytes
namespace: 7 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6ImpoSnJ...
? ? ? 其data包含ca.crt,namespace,token密鑰三部分,其中ca.crt即頒發(fā)的CA證書,namespace即命名空間,token文件中存放的密鑰。這三部分的用途我們待會講到。
(2)將ServiceAccount分配給Pod
? ?創(chuàng)建Pod,將上面的serviceAccount分配給Pod,其yaml內(nèi)容如下:
[root@k8s-master yaml]# cat pod-read.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-read
spec:
serviceAccount: my-servicesaccount
containers:
- name: netshoot
image: nicolaka/netshoot
imagePullPolicy: IfNotPresent
command: ["sleep","3600"]
? ? ? ? ?該Pod中定義serviceAccount屬性,并設(shè)置為剛創(chuàng)建的my-servicesaccount。我們進入該pod,查看下/var/run/secrets/kubernetes.io/serviceaccount目錄。
[root@k8s-master ~]# kubectl exec -it pod-read sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
~ # cd /var/run/secrets/kubernetes.io/serviceaccount
/run/secrets/kubernetes.io/serviceaccount # ls
ca.crt namespace token
/run/secrets/kubernetes.io/serviceaccount # cat token
eyJhbGciOiJSUzI1NiIsImtpZCI6ImpoSnJ
? ? ? 該目錄下,包含了my-servicesaccount的secret的三個文件。實際上,ServiceAcccount分配給Pod,就是將serviceAccount的secret作為volume掛載到pod的的固定目錄下(即/var/run/secrets/kubernetes.io/serviceaccount ),后續(xù)Pod將通過這三個文件協(xié)同完成身份驗證。
2、用戶組
? ? ?多個用戶可以屬于一個或者多個用戶組,用戶組可以一次給多個用戶賦予權(quán)限。K8S系統(tǒng)內(nèi)置了一些組,如:
- system:unauthenticated組用于所有認證插件都不會認證客戶端身份的請求。
- system:authenticated組會自動分配給一個成功通過認證的用戶。
- system:serviceaccounts組包含所有在系統(tǒng)中的 ServiceAccount
- system:serviceaccounts:<namespace>組包含了所有在特定命名空間中的ServiceAccount。
三、API? Server安全訪問策略
? ? ? 在K8S初級入門系列之一-概述章節(jié)的K8S架構(gòu)中,我們形象的比喻過,API Server就像是辦事大廳,對外對內(nèi)提供統(tǒng)一的訪問接口,所以API Server訪問安全策略至關(guān)重要。先來看下官方上的圖。
? ? ?當訪問API Server時,需要經(jīng)過三層關(guān)卡,分別是認證(Authentication),鑒權(quán)(Authorization)和準入控制(Admission Control)。
1、認證
? ? ? 認證就是識別用戶的身份,對于Pod來說,在訪問API Server時,攜帶其Service Account的token密鑰(前面介紹的),由API Service進行認證,這種方式類似JWT token驗證。過程如下:
?(1)、Pod關(guān)聯(lián)ServiceAccount,并掛載了ServiceAccount的secret。
(2)、通過HTTPS方式與API Server建立連接后,會用Pod里CA證書(文件名為ca.crt)驗證API Server發(fā)來的證書,驗證是否為CA證書簽名的合法證書。
(3)、API Server收到Token后,采用自身私鑰對Token進行合法性驗證。
? ? ? ?整個認證過程,需要用到上面介紹的var/run/secrets/kubernetes.io/serviceaccount下三個文件。我們來實驗下,從Pod內(nèi)部,通過curl訪問Api Server的接口。其命令如下:
# 指向內(nèi)部 API 服務(wù)器的主機名,一般為kubernetes.default.svc,也可以通過env查看
APISERVER=https://kubernetes.default.svc# 服務(wù)賬號令牌的路徑
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount# 讀取 Pod 的名字空間
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)# 讀取服務(wù)賬號的持有者令牌
TOKEN=$(cat ${SERVICEACCOUNT}/token)# 引用內(nèi)部證書機構(gòu)(CA)
CACERT=${SERVICEACCOUNT}/ca.crt# 使用令牌訪問 API?curl --cacert ${CACERT} -H "Authorization: Bearer $TOKEN" -s ?${APISERVER}/api
進入pod內(nèi)部,輸入上述指令
[root@k8s-master ~]# kubectl exec -it pod-read sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
~ # APISERVER=https://kubernetes.default.svc
~ # SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
~ # NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
~ # TOKEN=$(cat ${SERVICEACCOUNT}/token)
~ # CACERT=${SERVICEACCOUNT}/ca.crt
~ # curl --cacert ${CACERT} -H "Authorization: Bearer $TOKEN" -s ${APISERVER}/api
{
"kind": "APIVersions",
"versions": [
"v1"
],
"serverAddressByClientCIDRs": [
{
"clientCIDR": "0.0.0.0/0",
"serverAddress": "192.168.16.4:6443"
}
]
}
可以看下,HTTPS攜帶相關(guān)認證信息,Api認證成功后,正確的返回了Api的相關(guān)信息。
2、鑒權(quán)
? ? ? 認證是對用戶合法性的認證,但用戶合法,不代表可以做任何操作,而鑒權(quán)是對調(diào)用的API是否合法進行鑒權(quán),授予用戶不同的訪問權(quán)限。先看一個例子,我們進入上述Pod,訪問下pod列表。
# curl --cacert ${CACERT} -H "Authorization: Bearer $TOKEN" -X GET ${APISERVER}/api/v1/namespaces/default/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "default \"pods\" is forbidden: User \"system:serviceaccount:default:default\" cannot get resource \"default\" in API group \"\" at the cluster scope",
"reason": "Forbidden",
"details": {
"name": "pods",
"kind": "default"
},
"code": 403
? ? ? ?鑒權(quán)未通過被拒絕了,說明該Pod使用的ServiceAccount是沒有訪問該資源權(quán)限的。
? ? ? 下面我們來進行授權(quán)訪問,授權(quán)的方式主要包括ABAC(基于屬性授權(quán)),RBAC(基于角色授權(quán)),Webhook(外部REST服務(wù)對用戶授權(quán))等,其中RBAC是最主要,也是API Server默認的方式,我們來重點介紹,其模型如下:
- ??資源權(quán)限,表示對何種對象,有什么的操作權(quán)限,對象包括核心資源,如Pod,Deployment,job等,也包括非資源端點,如"/healthz"等。
- ?Role(角色),是資源權(quán)限的集合。
- RoleBinding(角色綁定),將Role授予給ServiceAccount,User,Group等。
接下來,我們通過案例,實現(xiàn)對于Pod列表的訪問。
(1)Role(角色)
首先創(chuàng)建一個Role的yaml文件,內(nèi)容如下:
[root@k8s-master yaml]# cat pod-read-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" 標明 core API 組
resources: ["pods"]
verbs: ["get", "watch", "list"]
在rules可以定義多組資源權(quán)限,每組包含三個屬性:
- apiGoups,即資源對象所在的api組,由于pods是核心對象,所以為"",比如對象為jobs,那么該值就是batch。
- resources,資源對象組,可以是pods,deploymenets,jobs等等
- verbs,對資源對象的操作權(quán)限組,包括get,list,watch,create,delete等。
? ? ?該Role命名為pod-reader,并申明對于Pod對象具備get,watch,list相關(guān)權(quán)限(注意,不具備刪除,創(chuàng)建權(quán)限)。執(zhí)行文件,創(chuàng)建role對象,查看狀態(tài)。
[root@k8s-master yaml]# kubectl get role
NAME CREATED AT
pod-reader 2023-05-28T09:24:06Z
(2)RoleBinding
? ? ? ?接下來創(chuàng)建RoleBinding,將上面的Role(pod-reader)與ServiceAccount(my-serviceaccount)綁定。其yaml內(nèi)容如下:
[root@k8s-master yaml]# cat pod-reader-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-rolebinding
namespace: default
subjects:
# 這里可以指定多個主體,User,ServiceAccount,Group
- kind: ServiceAccount
name: my-servicesaccount
namespace: default
apiGroup: ""
roleRef:
# "roleRef" 指定與某 Role 綁定關(guān)系
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
rolebinding包含兩個屬性。
- subjects,即綁定的用戶主體,可以是User,ServiceAccount,Group,能同時綁定多個不同的主體。
- roleRef,即用戶主體待授予的角色。
將my-servicesaccount賬號與pod-reader角色綁定,執(zhí)行文件,創(chuàng)建rolebinding,查看狀態(tài)
[root@k8s-master yaml]# kubectl get rolebinding
NAME ROLE AGE
pod-reader-rolebinding Role/pod-reader 10h
此時,我們進入Pod,再看下能否獲取pod列表。
[root@k8s-master yaml]# kubectl exec -it pod-read sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
~ # APISERVER=https://kubernetes.default.svc
~ # SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
~ # NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
~ # TOKEN=$(cat ${SERVICEACCOUNT}/token)
~ # CACERT=${SERVICEACCOUNT}/ca.crt
~ # curl --cacert ${CACERT} -H "Authorization: Bearer $TOKEN" -X GET ${APISERVER}/api/v1/namespaces/default/pods
{
[
"metadata": {
"name": "taint-pod",
"namespace": "default",
"uid": "12603b58-86b9-4e95-a6d5-b5d8c86a5e9c",
"resourceVersion": "4812227",
...
]
...
}
可以看到,能正確的獲取了。我們嘗試刪除其中一個pod
# curl --cacert ${CACERT} -H "Authorization: Bearer $TOKEN" -X DELETE ${APISERVER}/api/v1/namespaces/default/pods/busybox-pod
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods \"busybox-pod\" is forbidden: User \"system:serviceaccount:default:my-servicesaccount\" cannot delete resource \"pods\" in API group \"\" in the namespace \"default\"",
"reason": "Forbidden",
"details": {
"name": "busybox-pod",
"kind": "pods"
},
"code": 403
}
可以看到,由于沒有授予刪除相關(guān)的權(quán)限,刪除指令被拒絕。
(3)ClusterRole和ClusterRoleBinding
? ? ? 由于NameSpace的隔離,對于某個空間的ServiceAccount是無法訪問其他空間的資源對象的。如下圖所示,default空間的my-serviceaccount賬號是無法訪問dev空間的Pod資源列表。
? ? ? 在實際工程中,又需要訪問集群中的其他空間的資源,為了解決這一問題,K8S提供了ClusterRole和ClusterBinding。如下圖所示:
? ? ? ?ClusterRole和ClusterRoleBinding組合與Role以及RoleBinding組合的功能類似,只是它們屬于整個集群,不屬于具體某個命名空間,所以它們可以訪問集群中任何命名空間的資源。接下來,我們來實現(xiàn)下這個例子。
? ? ? ?首先創(chuàng)建一個NameSpace和屬于該NameSpace的Pod,我們使用K8S初級入門系列之四-Namespace/ConfigMap/Secret中創(chuàng)建好的命名空間dev,以及ns-pod的Pod,可以查看下pod狀態(tài)。
[root@k8s-master yaml]# kubectl get pod -n dev
NAME READY STATUS RESTARTS AGE
ns-pod 1/1 Running 0 8s
? ? ? ?在沒有使用ClusterRole和ClusterRoleBinding之前,我們看下能否從default空間中訪問dev空間的資源。
[root@k8s-master yaml]# kubectl exec -it pod-read sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
~ # APISERVER=https://kubernetes.default.svc
~ # SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
~ # NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
~ # TOKEN=$(cat ${SERVICEACCOUNT}/token)
~ # CACERT=${SERVICEACCOUNT}/ca.crt
~ # curl --cacert ${CACERT} -H "Authorization: Bearer $TOKEN" -X GET ${APISERVER}/api/v1/namespaces/dev/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:default:my-servicesaccount\" cannot list resource \"pods\" in API group \"\" in the namespace \"dev\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
? ? ? 訪問被拒絕了,無法訪問到其他命名空間pod。接下來,創(chuàng)建ClusterRole,命名為pod-reader-clusterrole
[root@k8s-master yaml]# cat pod-read-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-reader-clusterrole
rules:
- apiGroups: [""] # "" 標明 core API 組
resources: ["pods"]
verbs: ["get", "watch", "list"]
? ? ? ?與Role比較,ClusterRole沒有NameSpace屬性。執(zhí)行該文件,創(chuàng)建完成后我們可以看下。
[root@k8s-master yaml]# kubectl get clusterrole
NAME CREATED AT
admin 2022-11-04T15:44:14Z
calico-kube-controllers 2022-11-05T03:09:48Z
calico-node 2022-11-05T03:09:48Z
cluster-admin 2022-11-04T15:44:14Z
edit 2022-11-04T15:44:14Z
ingress-nginx 2023-04-02T10:47:54Z
ingress-nginx-admission 2023-04-02T10:47:54Z
kubeadm:get-nodes 2022-11-04T15:44:15Z
kubernetes-dashboard 2022-11-05T09:53:47Z
pod-reader-clusterrole 2023-05-30T15:36:51Z
system:aggregate-to-admin 2022-11-04T15:44:14Z
system:aggregate-to-edit 2022-11-04T15:44:14Z
...
? ? ? 除了創(chuàng)建的pod-reader-clusterrole外,還可以看到大量的系統(tǒng)預(yù)置的ClusterRole。繼續(xù)創(chuàng)建ClusterRoleBinding,命名為pod-reader-clusterrolebinding。
[root@k8s-master yaml]# cat pod-reader-clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pod-reader-clusterrolebinding
subjects:
# 這里可以指定多個主體,User,ServiceAccount,Group
- kind: ServiceAccount
name: my-servicesaccount
namespace: default
apiGroup: ""
roleRef:
# "roleRef" 指定與某 Role 綁定關(guān)系
kind: ClusterRole
name: pod-reader-clusterrole
apiGroup: rbac.authorization.k8s.io
? ? ? 將my-serviceaccount賬號與新創(chuàng)建的pod-reader-clusterrole角色綁定。
[root@k8s-master yaml]# kubectl get clusterrolebinding
NAME ROLE AGE
...
pod-reader-clusterrolebinding ClusterRole/pod-reader-clusterrole 16s
system:controller:attachdetach-controller ClusterRole/system:controller:attachdetach-controller 209d
system:controller:certificate-controller ClusterRole/system:controller:certificate-controller 209d
....
? ? ? 同樣,除了我們創(chuàng)建的pod-reader-clusterrolebinding外,也存在大量的系統(tǒng)預(yù)置ClusterRoleBinding對象。再次進入default空間pod,訪問dev空間的pod列表
[root@k8s-master yaml]# kubectl exec -it pod-read sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
~ # APISERVER=https://kubernetes.default.svc
~ # SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
~ # NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
~ # TOKEN=$(cat ${SERVICEACCOUNT}/token)
~ # CACERT=${SERVICEACCOUNT}/ca.crt
~ # curl --cacert ${CACERT} -H "Authorization: Bearer $TOKEN" -X GET ${APISERVER}/api/v1/namespaces/dev/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "31415719"
},
"items": [
{
"metadata": {
"name": "ns-pod",
"namespace": "dev",
"uid": "31bc247f-6c5a-496a-8805-2631f03e7df2",
"resourceVersion": "31324908",
"creationTimestamp": "2023-06-02T01:26:27Z",
"labels": {
"app": "nginx-pod"
},
...
? ? ? 此時可以正確訪問pod列表了。
3、準入
? ? ? ?突破了認證和鑒權(quán)兩層關(guān)卡后,對于API的請求還需要通過"準入"這道關(guān)卡,K8S配備了一個準入控制器的插件列表,發(fā)送給API Server的任何請求都需要通過列表中每個準入控制器的檢查,檢查通不過,則拒絕調(diào)用請求。
? ??準入控制器 是一段代碼,它會在請求通過認證和鑒權(quán)之后、對象被持久化之前攔截到達 API 服務(wù)器的請求,準入控制器又可以分為驗證(Validating)和變更(Mutating),變更(mutating)控制器可以根據(jù)被其接受的請求更改相關(guān)對象,Validating 控制器不會。如果任何一個階段中的任何控制器拒絕了請求,則會立即拒絕整個請求,并將錯誤返回給最終的用戶。
? ?K8S定義了多個準入控制器,可以查看官方文檔準入控制器參考 | Kubernetes,用戶也可以自定義擴展插件。通過如下的命令可以查看K8S默認開啟的準入控制器。
[root@k8s-master ~]# kubectl exec -it kube-apiserver-k8s-master -n kube-system -- kube-apiserver -h | grep enable-admission-plugins
.....
--enable-admission-plugins strings admission plugins that should be enabled in addition to default enabled ones (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, PodSecurity, .....
? ? ?稍后我們專門分析其中的PodSecurity準入控制器。
四、Pod安全策略
? ? ? ?Pod除了對于API Server訪問需要控制,Pod自身的安全策略也非常重要,因為Pod加載的容器鏡像是由開發(fā)者,甚至是三方提供,如果不在Pod層進行安全的控制,這些鏡像運行的代碼就有可能利用漏洞實現(xiàn)非法的操作。
? ? ? ? 有些同學(xué)可能會問,Pod中的容器本來就是和宿主隔離的,就算有影響,也只會影響該容器的環(huán)境,其實不然,在前面的章節(jié),我們了解到容器的目錄是可以掛在到宿主節(jié)點上的,網(wǎng)絡(luò)也可以直接使用宿主的,如果此時容器擁有root權(quán)限,就會隨意篡改宿主節(jié)點的目錄,或者利用宿主機網(wǎng)絡(luò)進行惡意訪問其他主機,從而影響集群安全。
? ? ? 為了解決這些安全問題,K8S對于Pod提供一系列的安全策略方案。
1、安全上下文配置
? ? ? ? 安全上下文即配置securityContext屬性,Pod和Container上都可以配置該屬性,兩者的策略項既有重復(fù)的,也有不同的,對于重復(fù)的部分,Container策略會覆蓋Pod上的。我們先來看下Pod上的配置。
(1)Pod配置
? ? ? ? 我們先看下沒有配置securityContext屬性時,Pod都有哪些權(quán)限。創(chuàng)建security-context-demo.yaml文件
[root@k8s-master yaml]# cat security-context-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
執(zhí)行文件,Pod創(chuàng)建完成后,進入容器內(nèi)部,看下其默認的進程用戶,組,以及文件目錄屬組。
[root@k8s-master yaml]# kubectl exec -it security-context-demo sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # id
uid=0(root) gid=0(root) groups=0(root),10(wheel)
/ # cd /data
/data # ls -l
total 4
drwxrwxrwx 2 root root 4096 Jun 4 05:58 demo
? ? ? ?可以看到uid,gid,以及文件目錄的屬主都是root,為了安全起見,我們認為該Pod下的容器不需要root權(quán)限,那么就可以通過Pod級別的securityContext屬性配置。下面我們修改yaml文件。
[root@k8s-master yaml]# cat security-context-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
volumes:
...
securityContext屬性中有三項內(nèi)容:
- runAsUser,指定容器中運行進程的用戶(用戶 ID )
- runAsGroup,指定容器中運行組(組?ID )
- fsGroup,文件屬主組(組ID)
再進入容器看下
[root@k8s-master yaml]# kubectl exec -it security-context-demo sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ $ id
uid=1000 gid=3000 groups=2000,3000
/ $ cd /data
/data $ ls -l
total 4
drwxrwsrwx 2 root 2000 4096 Jun 4 06:30 demo
? ? ? ?可以看到已經(jīng)按照Pod的設(shè)置進行了更變。除了以上的三個配置項,Pod還可以設(shè)置其他的,具體參考:Kubernetes API Reference Docs
(2)容器配置
? ? ? ? 容器中也可以配置securityContext屬性,首先我們看下runAsUser,runAsGroup,fsGroup屬性。我們再來創(chuàng)建一個pod yaml
[root@k8s-master yaml]# cat security-context-demo1.yaml
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo
spec:
securityContext:
runAsUser: 1000
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
runAsUser: 2000
? ? ? 在container中,增加了securityContext屬性,并配置了runAsUser了,其值和Pod的不同。我們進入Pod內(nèi)部看下。
[root@k8s-master yaml]# kubectl exec -it security-context-demo1 sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ $ id
uid=2000 gid=0(root) groups=0(root)
? ? ? ?可以看到,Container定義的uid=2000覆蓋了Pod定義的uid=1000。
? ? ? ? 默認的情況下,Pod是無法使用宿主內(nèi)核的功能(容器鏡像沒有內(nèi)核),比如修改網(wǎng)絡(luò)接口,修改系統(tǒng)時間等等,如果獲取這些權(quán)限,就需要申請授權(quán)特權(quán)模式。
? ? ? 我們先來看下在沒有授權(quán)特權(quán)模式下,Pod操作內(nèi)核指令的情況。?創(chuàng)建一個新的Pod,其yaml內(nèi)容如下:
[root@k8s-master yaml]# cat security-context-demo2.yaml
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo2
spec:
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
? ? ?進入Pod,訪問/dev目錄下的設(shè)備列表,以及修改網(wǎng)絡(luò)接口
[root@k8s-master yaml]# kubectl exec -it security-context-demo2 sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # cd /dev
/dev # ls
core full null pts shm stdin termination-log urandom
fd mqueue ptmx random stderr stdout tty zero
/dev # ip link add dummy0 type dummy
ip: RTNETLINK answers: Operation not permitted
? ? ? 可以看到修改網(wǎng)絡(luò)接口指令被拒絕了。dev目錄下展示內(nèi)容待會進行比較。接下來,我們修改yaml內(nèi)容,增加特權(quán)配置(?privileged: true)。
[root@k8s-master yaml]# cat security-context-demo2.yaml
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo2
spec:
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
privileged: true
?再次進入Pod,執(zhí)行相關(guān)指令
[root@k8s-master yaml]# kubectl exec -it security-context-demo2 sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # cd /dev
/dev # ls
autofs input raw tty12 tty26 tty4 tty53 ttyS0 vcs3 vhci
bsg kmsg rtc0 tty13 tty27 tty40 tty54 ttyS1 vcs4 vhost-net
bus loop-control sg0 tty14 tty28 tty41 tty55 ttyS2 vcs5 vhost-vsock
core mapper shm tty15 tty29 tty42 tty56 ttyS3 vcs6 watchdog
cpu mcelog snapshot tty16 tty3 ....
/dev # ip link add dummy0 type dummy
/dev #
? ? ? ?可以看到,/dev下面顯示多個特權(quán)設(shè)備?,也正確的執(zhí)行了網(wǎng)絡(luò)接口修改指令。
? ? ? ?特權(quán)雖然能支持內(nèi)核操作,但是其權(quán)限粒度較大,從Linux內(nèi)核2.2開始,引入了 Capabilities 機制來對 內(nèi)核操作進行了更加細粒度的控制,可以實現(xiàn)按需授權(quán),我們以修改網(wǎng)絡(luò)接口為例。修改yaml文件如下:
[root@k8s-master yaml]# cat security-context-demo2.yaml
apiVersion: v1
kind: Pod
metadata:
name: security-context-demo2
spec:
volumes:
- name: sec-ctx-vol
emptyDir: {}
containers:
- name: sec-ctx-demo
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
volumeMounts:
- name: sec-ctx-vol
mountPath: /data/demo
securityContext:
capabilities:
add: # 添加
- NET_ADMIN
drop: # 刪除
- KILL
? ? ? 刪除了privileged: true配置,增加了capabilities的列表配置,這里僅需要網(wǎng)絡(luò)權(quán)限,配置NET_ADMIN即可。
[root@k8s-master yaml]# kubectl exec -it security-context-demo2 sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # ip link add dummy0 type dummy
? ? 可以正確的修改了網(wǎng)絡(luò)接口配置。
? ? ?容器的securityContext還支持seLinuxOptions,allowPrivilegeEscalation等其他配置項。完整的配置項參見:SecurityContext - Kubernetes指南
2、Pod準入策略
? ? ? Pod一般都是有應(yīng)用開發(fā)者配置和創(chuàng)建的,上面的securityContext配置是否都被允許的呢?比如說容器設(shè)置了特權(quán)模式,擁有了完整的操作內(nèi)核的能力,集群管理員如何進行統(tǒng)一管控?這里就要用到上面介紹的Pod準入策略,其作用是,在Pod創(chuàng)建,進行準入校驗。
? ? ? 在V1.21版本前,通過PodSecurityPolicy統(tǒng)一配置Pod的安全策略,該方式在V1.25中廢棄,代替的是PodSecurity準入控制器。?PodSecurity定義了三種不同的策略,其限制程度逐級提升。
- Privileged,不受限制的策略,提供最大可能范圍的權(quán)限許可。通常針對由特權(quán)較高、受信任的用戶所管理的系統(tǒng)級或基礎(chǔ)設(shè)施級負載。
- Baseline,限制性最弱的策略,禁止已知的策略提升。允許使用默認的(規(guī)定最少)Pod 配置。這種策略是最常見的,針對的是應(yīng)用運維人員和非關(guān)鍵性應(yīng)用的開發(fā)人員。其策略內(nèi)容主要有,禁止有特權(quán)容器,禁止打破網(wǎng)絡(luò)隔離等。
- Restricted,限制性非常強的策略,遵循當前的保護 Pod 的最佳實踐。這類策略會犧牲一些兼容性,主要針對運維人員和安全性很重要的應(yīng)用的開發(fā)人員,以及不太被信任的用戶。其策略內(nèi)容主要有,要求容器以非 root 用戶運行,?容器組必須棄用 ALL capabilities ,并且只允許添加 NET_BIND_SERVICE 能力等。
? ? ?目前PodSecurity僅限于這三種策略,且無法進行擴展的。這些策略需要應(yīng)用于命名空間,實現(xiàn)對命名空間下所有Pod的約束,在命名空間中也可以配置三種模式。
- enforce,策略違例會導(dǎo)致 Pod 被拒絕
- audit,策略違例會觸發(fā)審計日志中記錄新事件時添加審計注解;但是 Pod 仍是被接受的。
- warn,策略違例會觸發(fā)用戶可見的警告信息,但是 Pod 仍是被接受的。
? ? ? 這三種模式配合上述的策略使用,命名空間可以配置多種策略。下面我們來看下案例。創(chuàng)建一個命名空間,設(shè)定安全策略。
[root@k8s-master yaml]# cat pod-level-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
name: podlevel
labels:
#強制執(zhí)行baseline安全標準,執(zhí)行拒絕。適用于最新的k8s版本
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: latest
#對restricted的Pod安全標準執(zhí)行警告(warn)和審核(audit),適用于最新的k8s版本
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
在命名空間中增加了labels屬性配置,下面是對其設(shè)置的解釋。
# 設(shè)定模式及安全標準策略等級 # MODE必須是 `enforce`, `audit`或`warn`其中之一。 # LEVEL必須是`privileged`, `baseline`或 `restricted`其中之一 pod-security.kubernetes.io/<MODE>: <LEVEL> # 此選項是非必填的,用來鎖定使用哪個版本的的安全標準 # MODE必須是 `enforce`, `audit`或`warn`其中之一。 # VERSION必須是一個有效的kubernetes minor version(例如v1.23),或者 `latest` pod-security.kubernetes.io/<MODE>-version: <VERSION>
? ? ?本例中我們設(shè)置了三種模式,對于enforce,配置了baseline策略,也就是違反baseline策略的Pod一律拒絕執(zhí)行;對于warn和audit,配置了restricted策略,也就是違反restricted策略的Pod進行警告和審核。
? ? 接下來,我們創(chuàng)建一個違反restricted策略的Pod。由于它的條件比較苛刻,默認的配置也無法校驗通過。
[root@k8s-master yaml]# cat level-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: level-pod
namespace: podlevel
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
? ?執(zhí)行該文件,創(chuàng)建Pod
[root@k8s-master yaml]# kubectl apply -f level-pod.yaml
Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "nginx" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "nginx" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
pod/level-pod created
[root@k8s-master yaml]# kubectl get pod -n podlevel
NAME READY STATUS RESTARTS AGE
level-pod 1/1 Running 0 78s
? ? 可以看到,違反了restricted策略,對用戶進行了告警提示,但是Pod最終還是創(chuàng)建成功的。我們繼續(xù)修改上面的Pod,讓其違反baseline策略,baseline策略不允許有特權(quán)容器存在。
[root@k8s-master yaml]# cat level-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: level-pod
namespace: podlevel
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
securityContext:
allowPrivilegeEscalation: true
privileged: true
capabilities:
drop:
- ALL
執(zhí)行該文件,可以看到,拒絕執(zhí)行Pod創(chuàng)建。
[root@k8s-master yaml]# kubectl apply -f level-pod.yaml
Error from server (Forbidden): error when creating "level-pod.yaml": pods "level-pod" is forbidden: violates PodSecurity "baseline:latest": privileged (container "nginx" must not set securityContext.privileged=true)
? ? 綜上所述,Pod安全上下文配置實現(xiàn)了對于容器鏡像的約束,Pod準入策略,實現(xiàn)了Pod的約束。逐級構(gòu)建了安全防護網(wǎng),實現(xiàn)Pod安全。
五、總結(jié)
? ? 本篇我們介紹了K8S的安全相關(guān)內(nèi)容,主要從API安全訪問策略以及Pod安全策略兩個方面。
? ?API安全訪問策略,主要是對API Server的訪問安全控制,其設(shè)置了認證,鑒權(quán),準入三道關(guān)卡。認證是針對用戶的身份合法性驗證,鑒權(quán)是對訪問的API接口合法性驗證,準入是通過一系列的準入控制器進行準入檢查。只有經(jīng)過了這三層關(guān)卡,才能訪問API Server的資源。
? ?Pod安全策略,主要介紹了安全上下文配置和Pod的準入檢查。安全上下文配置是在Pod或者Container中設(shè)置securityContext屬性;Pod的準入檢查通過在命名空間下配置不同的策略,實現(xiàn)Pod創(chuàng)建時準入檢查。
?附:
K8S初級入門系列之一-概述
K8S初級入門系列之二-集群搭建
K8S初級入門系列之三-Pod的基本概念和操作
K8S初級入門系列之四-Namespace/ConfigMap/Secret
K8S初級入門系列之五-Pod的高級特性
K8S初級入門系列之六-控制器(RC/RS/Deployment)
K8S初級入門系列之七-控制器(Job/CronJob/Daemonset)
K8S初級入門系列之八-網(wǎng)絡(luò)
K8S初級入門系列之九-共享存儲
K8S初級入門系列之十-控制器(StatefulSet)
K8S初級入門系列之十一-安全文章來源:http://www.zghlxwxcb.cn/news/detail-600266.html
K8S初級入門系列之十二-計算資源管理文章來源地址http://www.zghlxwxcb.cn/news/detail-600266.html
到了這里,關(guān)于K8S初級入門系列之十一-安全的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!