K8S初级入门系列之十一-安全
一、前言
安全是K8S重要的特性,在K8S初级入门系列之四-Namespace/ConfigMap/Secret章节,我们已经已经了解了Namespace,Secret与安全相关的知识。本篇将梳理K8S在安全方面的策略。主要包括两个方面,API安全访问策略以及Pod安全策略。
二、用户/用户组
在介绍安全前,我们先了解下用户和用户组的概念。
1、用户
在K8S中,用户分为两种:
- 真实的用户,即User,如K8S的管理员,开发者等。
- Pod的账号,即Service Account,是给运行在Pod里面的进程提供必要的身份证明,通过其来限制Pod的访问权限。
这里重点看下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-servicesaccountnamespace: default
创建完成后,查看详情
[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都关联了一个名为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-servicesaccountkubernetes.io/service-account.uid: 1f493157-13e7-4d43-9f0b-b8779dfe84aeType: kubernetes.io/service-account-tokenData
====
ca.crt: 1099 bytes
namespace: 7 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6ImpoSnJ...
其data包含ca.crt,namespace,token密钥三部分,其中ca.crt即颁发的CA证书,namespace即命名空间,token文件中存放的密钥。这三部分的用途我们待会讲到。
(2)将ServiceAccount分配给Pod
创建Pod,将上面的serviceAccount分配给Pod,其yaml内容如下:
[root@k8s-master yaml]# cat pod-read.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-read
spec:serviceAccount: my-servicesaccountcontainers:- name: netshootimage: nicolaka/netshootimagePullPolicy: IfNotPresentcommand: ["sleep","3600"]
该Pod中定义serviceAccount属性,并设置为刚创建的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 ),后续Pod将通过这三个文件协同完成身份验证。
2、用户组
多个用户可以属于一个或者多个用户组,用户组可以一次给多个用户赋予权限。K8S系统内置了一些组,如:
- system:unauthenticated组用于所有认证插件都不会认证客户端身份的请求。
- system:authenticated组会自动分配给一个成功通过认证的用户。
- system:serviceaccounts组包含所有在系统中的 ServiceAccount
- system:serviceaccounts:<namespace>组包含了所有在特定命名空间中的ServiceAccount。
三、API Server安全访问策略
在K8S初级入门系列之一-概述章节的K8S架构中,我们形象的比喻过,API Server就像是办事大厅,对外对内提供统一的访问接口,所以API Server访问安全策略至关重要。先来看下官方上的图。

当访问API Server时,需要经过三层关卡,分别是认证(Authentication),鉴权(Authorization)和准入控制(Admission Control)。
1、认证
认证就是识别用户的身份,对于Pod来说,在访问API Server时,携带其Service Account的token密钥(前面介绍的),由API Service进行认证,这种方式类似JWT token验证。过程如下:
(1)、Pod关联ServiceAccount,并挂载了ServiceAccount的secret。
(2)、通过HTTPS方式与API Server建立连接后,会用Pod里CA证书(文件名为ca.crt)验证API Server发来的证书,验证是否为CA证书签名的合法证书。
(3)、API Server收到Token后,采用自身私钥对Token进行合法性验证。
整个认证过程,需要用到上面介绍的var/run/secrets/kubernetes.io/serviceaccount下三个文件。我们来实验下,从Pod内部,通过curl访问Api Server的接口。其命令如下:
# 指向内部 API 服务器的主机名,一般为kubernetes.default.svc,也可以通过env查看
APISERVER=https://kubernetes.default.svc# 服务账号令牌的路径
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount# 读取 Pod 的名字空间
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)# 读取服务账号的持有者令牌
TOKEN=$(cat ${SERVICEACCOUNT}/token)# 引用内部证书机构(CA)
CACERT=${SERVICEACCOUNT}/ca.crt# 使用令牌访问 API curl --cacert ${CACERT} -H "Authorization: Bearer $TOKEN" -s ${APISERVER}/api
进入pod内部,输入上述指令
[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携带相关认证信息,Api认证成功后,正确的返回了Api的相关信息。
2、鉴权
认证是对用户合法性的认证,但用户合法,不代表可以做任何操作,而鉴权是对调用的API是否合法进行鉴权,授予用户不同的访问权限。先看一个例子,我们进入上述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
鉴权未通过被拒绝了,说明该Pod使用的ServiceAccount是没有访问该资源权限的。
下面我们来进行授权访问,授权的方式主要包括ABAC(基于属性授权),RBAC(基于角色授权),Webhook(外部REST服务对用户授权)等,其中RBAC是最主要,也是API Server默认的方式,我们来重点介绍,其模型如下:

- 资源权限,表示对何种对象,有什么的操作权限,对象包括核心资源,如Pod,Deployment,job等,也包括非资源端点,如"/healthz"等。
- Role(角色),是资源权限的集合。
- RoleBinding(角色绑定),将Role授予给ServiceAccount,User,Group等。
接下来,我们通过案例,实现对于Pod列表的访问。
(1)Role(角色)
首先创建一个Role的yaml文件,内容如下:
[root@k8s-master yaml]# cat pod-read-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:namespace: defaultname: pod-reader
rules:
- apiGroups: [""] # "" 标明 core API 组resources: ["pods"]verbs: ["get", "watch", "list"]
在rules可以定义多组资源权限,每组包含三个属性:
- apiGoups,即资源对象所在的api组,由于pods是核心对象,所以为"",比如对象为jobs,那么该值就是batch。
- resources,资源对象组,可以是pods,deploymenets,jobs等等
- verbs,对资源对象的操作权限组,包括get,list,watch,create,delete等。
该Role命名为pod-reader,并申明对于Pod对象具备get,watch,list相关权限(注意,不具备删除,创建权限)。执行文件,创建role对象,查看状态。
[root@k8s-master yaml]# kubectl get role
NAME CREATED AT
pod-reader 2023-05-28T09:24:06Z
(2)RoleBinding
接下来创建RoleBinding,将上面的Role(pod-reader)与ServiceAccount(my-serviceaccount)绑定。其yaml内容如下:
[root@k8s-master yaml]# cat pod-reader-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: pod-reader-rolebindingnamespace: default
subjects:
# 这里可以指定多个主体,User,ServiceAccount,Group
- kind: ServiceAccountname: my-servicesaccountnamespace: default apiGroup: ""
roleRef:# "roleRef" 指定与某 Role 绑定关系kind: Role name: pod-readerapiGroup: rbac.authorization.k8s.io
rolebinding包含两个属性。
- subjects,即绑定的用户主体,可以是User,ServiceAccount,Group,能同时绑定多个不同的主体。
- roleRef,即用户主体待授予的角色。
将my-servicesaccount账号与pod-reader角色绑定,执行文件,创建rolebinding,查看状态
[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
}
可以看到,由于没有授予删除相关的权限,删除指令被拒绝。
(3)ClusterRole和ClusterRoleBinding
由于NameSpace的隔离,对于某个空间的ServiceAccount是无法访问其他空间的资源对象的。如下图所示,default空间的my-serviceaccount账号是无法访问dev空间的Pod资源列表。

在实际工程中,又需要访问集群中的其他空间的资源,为了解决这一问题,K8S提供了ClusterRole和ClusterBinding。如下图所示:

ClusterRole和ClusterRoleBinding组合与Role以及RoleBinding组合的功能类似,只是它们属于整个集群,不属于具体某个命名空间,所以它们可以访问集群中任何命名空间的资源。接下来,我们来实现下这个例子。
首先创建一个NameSpace和属于该NameSpace的Pod,我们使用K8S初级入门系列之四-Namespace/ConfigMap/Secret中创建好的命名空间dev,以及ns-pod的Pod,可以查看下pod状态。
[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。接下来,创建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属性。执行该文件,创建完成后我们可以看下。
[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
...
除了创建的pod-reader-clusterrole外,还可以看到大量的系统预置的ClusterRole。继续创建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: ServiceAccountname: my-servicesaccountnamespace: default apiGroup: ""
roleRef:# "roleRef" 指定与某 Role 绑定关系kind: ClusterRole name: pod-reader-clusterroleapiGroup: rbac.authorization.k8s.io
将my-serviceaccount账号与新创建的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
....
同样,除了我们创建的pod-reader-clusterrolebinding外,也存在大量的系统预置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、准入
突破了认证和鉴权两层关卡后,对于API的请求还需要通过"准入"这道关卡,K8S配备了一个准入控制器的插件列表,发送给API Server的任何请求都需要通过列表中每个准入控制器的检查,检查通不过,则拒绝调用请求。
准入控制器 是一段代码,它会在请求通过认证和鉴权之后、对象被持久化之前拦截到达 API 服务器的请求,准入控制器又可以分为验证(Validating)和变更(Mutating),变更(mutating)控制器可以根据被其接受的请求更改相关对象,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加载的容器镜像是由开发者,甚至是三方提供,如果不在Pod层进行安全的控制,这些镜像运行的代码就有可能利用漏洞实现非法的操作。
有些同学可能会问,Pod中的容器本来就是和宿主隔离的,就算有影响,也只会影响该容器的环境,其实不然,在前面的章节,我们了解到容器的目录是可以挂在到宿主节点上的,网络也可以直接使用宿主的,如果此时容器拥有root权限,就会随意篡改宿主节点的目录,或者利用宿主机网络进行恶意访问其他主机,从而影响集群安全。
为了解决这些安全问题,K8S对于Pod提供一系列的安全策略方案。
1、安全上下文配置
安全上下文即配置securityContext属性,Pod和Container上都可以配置该属性,两者的策略项既有重复的,也有不同的,对于重复的部分,Container策略会覆盖Pod上的。我们先来看下Pod上的配置。
(1)Pod配置
我们先看下没有配置securityContext属性时,Pod都有哪些权限。创建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-volemptyDir: {}containers:- name: sec-ctx-demoimage: busyboxcommand: [ "sh", "-c", "sleep 1h" ]volumeMounts:- name: sec-ctx-volmountPath: /data/demo
执行文件,Pod创建完成后,进入容器内部,看下其默认的进程用户,组,以及文件目录属组。
[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权限,那么就可以通过Pod级别的securityContext属性配置。下面我们修改yaml文件。
[root@k8s-master yaml]# cat security-context-demo.yaml
apiVersion: v1
kind: Pod
metadata:name: security-context-demo
spec:securityContext:runAsUser: 1000runAsGroup: 3000fsGroup: 2000volumes:...
securityContext属性中有三项内容:
- 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
可以看到已经按照Pod的设置进行了更变。除了以上的三个配置项,Pod还可以设置其他的,具体参考:Kubernetes API Reference Docs
(2)容器配置
容器中也可以配置securityContext属性,首先我们看下runAsUser,runAsGroup,fsGroup属性。我们再来创建一个pod yaml
[root@k8s-master yaml]# cat security-context-demo1.yaml
apiVersion: v1
kind: Pod
metadata:name: security-context-demo
spec:securityContext:runAsUser: 1000volumes:- name: sec-ctx-volemptyDir: {}containers:- name: sec-ctx-demoimage: busyboxcommand: [ "sh", "-c", "sleep 1h" ]volumeMounts:- name: sec-ctx-volmountPath: /data/demosecurityContext:runAsUser: 2000
在container中,增加了securityContext属性,并配置了runAsUser了,其值和Pod的不同。我们进入Pod内部看下。
[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是无法使用宿主内核的功能(容器镜像没有内核),比如修改网络接口,修改系统时间等等,如果获取这些权限,就需要申请授权特权模式。
我们先来看下在没有授权特权模式下,Pod操作内核指令的情况。 创建一个新的Pod,其yaml内容如下:
[root@k8s-master yaml]# cat security-context-demo2.yaml
apiVersion: v1
kind: Pod
metadata:name: security-context-demo2
spec:volumes:- name: sec-ctx-volemptyDir: {}containers:- name: sec-ctx-demoimage: busyboxcommand: [ "sh", "-c", "sleep 1h" ]volumeMounts:- name: sec-ctx-volmountPath: /data/demo
进入Pod,访问/dev目录下的设备列表,以及修改网络接口
[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
可以看到修改网络接口指令被拒绝了。dev目录下展示内容待会进行比较。接下来,我们修改yaml内容,增加特权配置( 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-volemptyDir: {}containers:- name: sec-ctx-demoimage: busyboxcommand: [ "sh", "-c", "sleep 1h" ]volumeMounts:- name: sec-ctx-volmountPath: /data/demosecurityContext:privileged: true
再次进入Pod,执行相关指令
[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下面显示多个特权设备 ,也正确的执行了网络接口修改指令。
特权虽然能支持内核操作,但是其权限粒度较大,从Linux内核2.2开始,引入了 Capabilities 机制来对 内核操作进行了更加细粒度的控制,可以实现按需授权,我们以修改网络接口为例。修改yaml文件如下:
[root@k8s-master yaml]# cat security-context-demo2.yaml
apiVersion: v1
kind: Pod
metadata:name: security-context-demo2
spec:volumes:- name: sec-ctx-volemptyDir: {}containers:- name: sec-ctx-demoimage: busyboxcommand: [ "sh", "-c", "sleep 1h" ]volumeMounts:- name: sec-ctx-volmountPath: /data/demosecurityContext:capabilities:add: # 添加- NET_ADMINdrop: # 删除- KILL
删除了privileged: true配置,增加了capabilities的列表配置,这里仅需要网络权限,配置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
可以正确的修改了网络接口配置。
容器的securityContext还支持seLinuxOptions,allowPrivilegeEscalation等其他配置项。完整的配置项参见:SecurityContext - Kubernetes指南
2、Pod准入策略
Pod一般都是有应用开发者配置和创建的,上面的securityContext配置是否都被允许的呢?比如说容器设置了特权模式,拥有了完整的操作内核的能力,集群管理员如何进行统一管控?这里就要用到上面介绍的Pod准入策略,其作用是,在Pod创建,进行准入校验。
在V1.21版本前,通过PodSecurityPolicy统一配置Pod的安全策略,该方式在V1.25中废弃,代替的是PodSecurity准入控制器。 PodSecurity定义了三种不同的策略,其限制程度逐级提升。
- Privileged,不受限制的策略,提供最大可能范围的权限许可。通常针对由特权较高、受信任的用户所管理的系统级或基础设施级负载。
- Baseline,限制性最弱的策略,禁止已知的策略提升。允许使用默认的(规定最少)Pod 配置。这种策略是最常见的,针对的是应用运维人员和非关键性应用的开发人员。其策略内容主要有,禁止有特权容器,禁止打破网络隔离等。
- Restricted,限制性非常强的策略,遵循当前的保护 Pod 的最佳实践。这类策略会牺牲一些兼容性,主要针对运维人员和安全性很重要的应用的开发人员,以及不太被信任的用户。其策略内容主要有,要求容器以非 root 用户运行, 容器组必须弃用 ALL capabilities ,并且只允许添加 NET_BIND_SERVICE 能力等。
目前PodSecurity仅限于这三种策略,且无法进行扩展的。这些策略需要应用于命名空间,实现对命名空间下所有Pod的约束,在命名空间中也可以配置三种模式。
- enforce,策略违例会导致 Pod 被拒绝
- audit,策略违例会触发审计日志中记录新事件时添加审计注解;但是 Pod 仍是被接受的。
- warn,策略违例会触发用户可见的警告信息,但是 Pod 仍是被接受的。
这三种模式配合上述的策略使用,命名空间可以配置多种策略。下面我们来看下案例。创建一个命名空间,设定安全策略。
[root@k8s-master yaml]# cat pod-level-ns.yaml
apiVersion: v1
kind: Namespace
metadata:name: podlevellabels: #强制执行baseline安全标准,执行拒绝。适用于最新的k8s版本pod-security.kubernetes.io/enforce: baselinepod-security.kubernetes.io/enforce-version: latest#对restricted的Pod安全标准执行警告(warn)和审核(audit),适用于最新的k8s版本pod-security.kubernetes.io/warn: restrictedpod-security.kubernetes.io/warn-version: latestpod-security.kubernetes.io/audit: restrictedpod-security.kubernetes.io/audit-version: latest
在命名空间中增加了labels属性配置,下面是对其设置的解释。
# 设定模式及安全标准策略等级 # 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>
本例中我们设置了三种模式,对于enforce,配置了baseline策略,也就是违反baseline策略的Pod一律拒绝执行;对于warn和audit,配置了restricted策略,也就是违反restricted策略的Pod进行警告和审核。
接下来,我们创建一个违反restricted策略的Pod。由于它的条件比较苛刻,默认的配置也无法校验通过。
[root@k8s-master yaml]# cat level-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: level-podnamespace: podlevel
spec:containers:- image: nginxname: nginxports:- containerPort: 80
执行该文件,创建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最终还是创建成功的。我们继续修改上面的Pod,让其违反baseline策略,baseline策略不允许有特权容器存在。
[root@k8s-master yaml]# cat level-pod.yaml
apiVersion: v1
kind: Pod
metadata:name: level-podnamespace: podlevel
spec:containers:- image: nginxname: nginxports:- containerPort: 80securityContext:allowPrivilegeEscalation: trueprivileged: truecapabilities:drop:- ALL
执行该文件,可以看到,拒绝执行Pod创建。
[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安全上下文配置实现了对于容器镜像的约束,Pod准入策略,实现了Pod的约束。逐级构建了安全防护网,实现Pod安全。
五、总结
本篇我们介绍了K8S的安全相关内容,主要从API安全访问策略以及Pod安全策略两个方面。
API安全访问策略,主要是对API Server的访问安全控制,其设置了认证,鉴权,准入三道关卡。认证是针对用户的身份合法性验证,鉴权是对访问的API接口合法性验证,准入是通过一系列的准入控制器进行准入检查。只有经过了这三层关卡,才能访问API Server的资源。
Pod安全策略,主要介绍了安全上下文配置和Pod的准入检查。安全上下文配置是在Pod或者Container中设置securityContext属性;Pod的准入检查通过在命名空间下配置不同的策略,实现Pod创建时准入检查。
附:
K8S初级入门系列之一-概述
K8S初级入门系列之二-集群搭建
K8S初级入门系列之三-Pod的基本概念和操作
K8S初级入门系列之四-Namespace/ConfigMap/Secret
K8S初级入门系列之五-Pod的高级特性
K8S初级入门系列之六-控制器(RC/RS/Deployment)
K8S初级入门系列之七-控制器(Job/CronJob/Daemonset)
K8S初级入门系列之八-网络
K8S初级入门系列之九-共享存储
K8S初级入门系列之十-控制器(StatefulSet)
K8S初级入门系列之十一-安全
K8S初级入门系列之十二-计算资源管理
相关文章:
K8S初级入门系列之十一-安全
一、前言 安全是K8S重要的特性,在K8S初级入门系列之四-Namespace/ConfigMap/Secret章节,我们已经已经了解了Namespace,Secret与安全相关的知识。本篇将梳理K8S在安全方面的策略。主要包括两个方面,API安全访问策略以及Pod安全策略…...
【雕爷学编程】MicroPython动手做(02)——尝试搭建K210开发板的IDE环境6
#尝试搭建K210的Micropython开发环境(Win10) #实验程序之六:测试Microphone阵列算法 #尝试搭建K210的Micropython开发环境(Win10) #实验程序之六:测试Microphone阵列算法from Maix import MIC_ARRAY as mi…...
“深入解析Spring Boot:从入门到精通“
标题:深入解析Spring Boot:从入门到精通 摘要:本文深入解析了Spring Boot框架,从入门到精通,包括核心概念、特性、使用方法和示例代码。通过阅读本文,读者将对Spring Boot有一个全面的了解,并可…...
[自然语言处理] 自然语言处理库spaCy使用指北
spaCy是一个基于Python编写的开源自然语言处理库。基于自然处理领域的最新研究,spaCy提供了一系列高效且易用的工具,用于文本预处理、文本解析、命名实体识别、词性标注、句法分析和文本分类等任务。 spaCy的官方仓库地址为:spaCy-github。本…...
【新日语(2)】第6課 拓哉もさしみを食べたがってします
第6課 拓哉もさしみを食べたがっています 注释: 食べたがっています:食べ+たが+ています、想要吃。たがっています:たがる+ています、想要。 练习A 一、 例句 わたしは、明日、デパートへ行きます。 …...
uni-app 经验分享,从入门到离职(一)——初始 uni-app,快速上手(文末送书福利1.0)
文章目录 📋前言🎯什么是 uni-app🎯创建第一个 uni-app 项目🧩前期工作🧩创建项目(熟悉默认项目、结构)🧩运行项目 📝最后🎯文末送书🔥参与方式 &…...
Python爬虫实例之淘宝商品页面爬取(api接口)
可以使用Python中的requests和BeautifulSoup库来进行网页爬取和数据提取。以下是一个简单的示例: import requests from bs4 import BeautifulSoupdef get_product_data(url):# 发送GET请求,获取网页内容headers {User-Agent: Mozilla/5.0 (Windows NT…...
并发编程 | CompletionService - 如何优雅地处理批量异步任务
引言 上一篇文章中,我们详细地介绍了 CompletableFuture,它是一种强大的并发工具,能帮助我们以声明式的方式处理异步任务。虽然 CompletableFuture 很强大,但它并不总是最适合所有场景的解决方案。 在这篇文章中,我们…...
医学案例|ROC曲线之面积对比
一、案例介绍 为评价CT和CT增强对肝癌的诊断效果,共检查了32例患者,每例患者分别用两种方法检查,由医生盲态按4个等级诊断,最后经手术病理检查确诊其中有16例患有肝癌,评价CT个CT增强对肝癌是有有诊断效果并且试着比较…...
Kotlin线程的基本用法
线程的基本用法 新建一个类继承自Thread,然后重写父类的run()方法 class MyThread : Thread() {override fun run() {// 编写具体的逻辑} }// 使用 MyThread().start()实现Runnable接口 class MyThread : Runnable {override fun run() {// 编写具体的逻辑} }// …...
2.03 PageHelper分页工具
步骤1:在application.yml中添加分页配置 # 分页插件配置 pagehelper:helperDialect: mysqlsupportMethodsArguments: true步骤2:在顶级工程pom文件下引入分页插件依赖 <!--5.PageHelper --> <dependency><groupId>com.github.pagehe…...
VUE中使用ElementUI组件的单选按钮el-radio-button实现第二点击时取消选择的功能
页面样式为: html 代码为: 日志等级: <el-radio-group v-model"logLevel"><el-radio-button label"DEBUG" click.native.prevent"changeLogLevel(DEBUG)">DEBUG</el-radio-button><el-r…...
瓴羊Quick BI:可视化大屏界面设计满足企业个性需求
大数据技术成为现阶段企业缩短与竞争对手之间差距的重要抓手,依托以瓴羊Quick BI为代表的工具开展内部数据处理分析工作,也成为诸多企业持续获取竞争优势的必由之路。早年间国内企业倾向于使用进口BI工具,但随着瓴羊Quick BI等一众国内数据处…...
617. 合并二叉树
题目 题解一:递归 /*** 递归* param root1* param root2* return*/public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {//结束条件if (root1 null) {return root2;} //结束条件if (root2 null) {return root1;}//两节点数值相加TreeNode me…...
【T1】存货成本异常、数量为零金额不为零的处理方法。
【问题描述】 使用T1飞跃专业版的过程中, 由于业务问题或者是操作问题, 经常会遇到某个商品成本异常不准确, 或者是遇到数量为0金额不为0的情况,需要将其成本调为0。 但是T1软件没有出入库调整单,并且结账无法针对数量…...
EtherNet IP转PROFINET网关连接西门子与欧姆龙方法
本文主要介绍了捷米特JM-PN-EIP(EtherNet/IP转PROFINET)网关西门子200智能PLC(PROFINET)和欧姆龙系统EtherNet/IP通信的配置过程。 1, 将 EDS 文件复制到欧姆龙软件的对应文件夹下 2, 首先添加捷米特JM-PN-EIP网关的全局变量&…...
低代码开发重要工具:jvs-flow(流程引擎)审批功能配置说明
流程引擎场景介绍 流程引擎基于一组节点与执行界面,通过人机交互的形式自动地执行和协调各个任务和活动。它可以实现任务的分配、协作、路由和跟踪。通过流程引擎,组织能够实现业务流程的优化、标准化和自动化,提高工作效率和质量。 在企业…...
[SQL挖掘机] - GROUP BY语句
介绍: group by 是 sql 中用于对结果集进行分组的关键字。通过使用 group by,可以根据一个或多个列的值将结果集中的行分组,并对每个分组应用某种聚合函数(如 count、sum、avg 等)以生成汇总信息。这样可以方便地对数据进行分类、…...
【ubuntu|内核】ubuntu 22.04修改内核为指定版本
every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 ubuntu 22.04 安装指定内核 1. 正文 查看已安装的内核镜像 dpkg --get-selections | grep linux-image1.1 安装指定版本的内核 安装镜像 sudo apt-g…...
Carla教程一:动力学模型到LQR
Carla教程一、动力学模型到LQR 从运动学模型和动力学模型到LQR 模型就是可以描述车辆运动规律的模型。车辆建模都是基于自行车模型的设定,也就是将四个轮子抽象为自行车一样的两个轮子来建模。 1、运动学模型 运动学模型是基于几何关系分析出来的,一般适用于低俗情况下,…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
Oracle实用参考(13)——Oracle for Linux物理DG环境搭建(2)
13.2. Oracle for Linux物理DG环境搭建 Oracle 数据库的DataGuard技术方案,业界也称为DG,其在数据库高可用、容灾及负载分离等方面,都有着非常广泛的应用,对此,前面相关章节已做过较为详尽的讲解,此处不再赘述。 需要说明的是, DG方案又分为物理DG和逻辑DG,两者的搭建…...
【Pandas】pandas DataFrame dropna
Pandas2.2 DataFrame Missing data handling 方法描述DataFrame.fillna([value, method, axis, …])用于填充 DataFrame 中的缺失值(NaN)DataFrame.backfill(*[, axis, inplace, …])用于**使用后向填充(即“下一个有效观测值”)…...
Git 切换到旧提交,同时保证当前修改不丢失
在 Git 中,可以通过以下几种方式切换到之前的提交,同时保留当前的修改 1. 使用 git checkout 创建临时分离头指针(推荐用于查看代码) git checkout <commit-hash>这会让你进入"分离头指针"状态,你可…...
React 样式方案与状态方案初探
React 本身只提供了基础 UI 层开发范式,其他特性的支持需要借助相关社区方案实现。本文将介绍 React 应用体系中样式方案与状态方案的主流选择,帮助开发者根据项目需求做出合适的选择。 1. React 样式方案 1.1. 内联样式 (Inline Styles) 通过 style …...
STM32CubeMX-H7-19-ESP8266通信(中)--单片机控制ESP8266实现TCP地址通信
前言 上篇文章我们已经能够使用串口助手实现esp8266的几种通信,接下来我们使用单片机控制实现。这篇文章会附带教程,增加.c和,.h,把串口和定时器放到对应的编号,然后调用初始化就可以使用了。 先讲解,然后末尾再放源码…...
2025年ESWA SCI1区TOP,自适应学习粒子群算法AEPSO+动态周期调节灰色模型,深度解析+性能实测
目录 1.摘要2.粒子群算法PSO原理3.改进策略4.结果展示5.参考文献6.代码获取7.算法辅导应用定制读者交流 1.摘要 能源数据的科学预测对于能源行业决策和国家经济发展具有重要意义,尤其是短期能源预测,其精度直接影响经济运行效率。为了更好地提高预测模型…...
