当前位置: 首页 > news >正文

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重要的特性&#xff0c;在K8S初级入门系列之四-Namespace/ConfigMap/Secret章节&#xff0c;我们已经已经了解了Namespace&#xff0c;Secret与安全相关的知识。本篇将梳理K8S在安全方面的策略。主要包括两个方面&#xff0c;API安全访问策略以及Pod安全策略…...

【雕爷学编程】MicroPython动手做(02)——尝试搭建K210开发板的IDE环境6

#尝试搭建K210的Micropython开发环境&#xff08;Win10&#xff09; #实验程序之六&#xff1a;测试Microphone阵列算法 #尝试搭建K210的Micropython开发环境&#xff08;Win10&#xff09; #实验程序之六&#xff1a;测试Microphone阵列算法from Maix import MIC_ARRAY as mi…...

“深入解析Spring Boot:从入门到精通“

标题&#xff1a;深入解析Spring Boot&#xff1a;从入门到精通 摘要&#xff1a;本文深入解析了Spring Boot框架&#xff0c;从入门到精通&#xff0c;包括核心概念、特性、使用方法和示例代码。通过阅读本文&#xff0c;读者将对Spring Boot有一个全面的了解&#xff0c;并可…...

[自然语言处理] 自然语言处理库spaCy使用指北

spaCy是一个基于Python编写的开源自然语言处理库。基于自然处理领域的最新研究&#xff0c;spaCy提供了一系列高效且易用的工具&#xff0c;用于文本预处理、文本解析、命名实体识别、词性标注、句法分析和文本分类等任务。 spaCy的官方仓库地址为&#xff1a;spaCy-github。本…...

【新日语(2)】第6課 拓哉もさしみを食べたがってします

第6課 拓哉もさしみを食べたがっています 注释&#xff1a; 食べたがっています&#xff1a;食べ&#xff0b;たが&#xff0b;ています、想要吃。たがっています&#xff1a;たがる&#xff0b;ています、想要。 练习A 一、 例句 わたしは、明日、デパートへ行きます。 …...

uni-app 经验分享,从入门到离职(一)——初始 uni-app,快速上手(文末送书福利1.0)

文章目录 &#x1f4cb;前言&#x1f3af;什么是 uni-app&#x1f3af;创建第一个 uni-app 项目&#x1f9e9;前期工作&#x1f9e9;创建项目&#xff08;熟悉默认项目、结构&#xff09;&#x1f9e9;运行项目 &#x1f4dd;最后&#x1f3af;文末送书&#x1f525;参与方式 &…...

Python爬虫实例之淘宝商品页面爬取(api接口)

可以使用Python中的requests和BeautifulSoup库来进行网页爬取和数据提取。以下是一个简单的示例&#xff1a; import requests from bs4 import BeautifulSoupdef get_product_data(url):# 发送GET请求&#xff0c;获取网页内容headers {User-Agent: Mozilla/5.0 (Windows NT…...

并发编程 | CompletionService - 如何优雅地处理批量异步任务

引言 上一篇文章中&#xff0c;我们详细地介绍了 CompletableFuture&#xff0c;它是一种强大的并发工具&#xff0c;能帮助我们以声明式的方式处理异步任务。虽然 CompletableFuture 很强大&#xff0c;但它并不总是最适合所有场景的解决方案。 在这篇文章中&#xff0c;我们…...

医学案例|ROC曲线之面积对比

一、案例介绍 为评价CT和CT增强对肝癌的诊断效果&#xff0c;共检查了32例患者&#xff0c;每例患者分别用两种方法检查&#xff0c;由医生盲态按4个等级诊断&#xff0c;最后经手术病理检查确诊其中有16例患有肝癌&#xff0c;评价CT个CT增强对肝癌是有有诊断效果并且试着比较…...

Kotlin线程的基本用法

线程的基本用法 新建一个类继承自Thread&#xff0c;然后重写父类的run()方法 class MyThread : Thread() {override fun run() {// 编写具体的逻辑} }// 使用 MyThread().start()实现Runnable接口 class MyThread : Runnable {override fun run() {// 编写具体的逻辑} }// …...

2.03 PageHelper分页工具

步骤1&#xff1a;在application.yml中添加分页配置 # 分页插件配置 pagehelper:helperDialect: mysqlsupportMethodsArguments: true步骤2&#xff1a;在顶级工程pom文件下引入分页插件依赖 <!--5.PageHelper --> <dependency><groupId>com.github.pagehe…...

VUE中使用ElementUI组件的单选按钮el-radio-button实现第二点击时取消选择的功能

页面样式为&#xff1a; html 代码为&#xff1a; 日志等级&#xff1a; <el-radio-group v-model"logLevel"><el-radio-button label"DEBUG" click.native.prevent"changeLogLevel(DEBUG)">DEBUG</el-radio-button><el-r…...

瓴羊Quick BI:可视化大屏界面设计满足企业个性需求

大数据技术成为现阶段企业缩短与竞争对手之间差距的重要抓手&#xff0c;依托以瓴羊Quick BI为代表的工具开展内部数据处理分析工作&#xff0c;也成为诸多企业持续获取竞争优势的必由之路。早年间国内企业倾向于使用进口BI工具&#xff0c;但随着瓴羊Quick BI等一众国内数据处…...

617. 合并二叉树

题目 题解一&#xff1a;递归 /*** 递归* 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飞跃专业版的过程中&#xff0c; 由于业务问题或者是操作问题&#xff0c; 经常会遇到某个商品成本异常不准确&#xff0c; 或者是遇到数量为0金额不为0的情况&#xff0c;需要将其成本调为0。 但是T1软件没有出入库调整单&#xff0c;并且结账无法针对数量…...

EtherNet IP转PROFINET网关连接西门子与欧姆龙方法

本文主要介绍了捷米特JM-PN-EIP&#xff08;EtherNet/IP转PROFINET&#xff09;网关西门子200智能PLC&#xff08;PROFINET&#xff09;和欧姆龙系统EtherNet/IP通信的配置过程。 1, 将 EDS 文件复制到欧姆龙软件的对应文件夹下 2, 首先添加捷米特JM-PN-EIP网关的全局变量&…...

低代码开发重要工具:jvs-flow(流程引擎)审批功能配置说明

流程引擎场景介绍 流程引擎基于一组节点与执行界面&#xff0c;通过人机交互的形式自动地执行和协调各个任务和活动。它可以实现任务的分配、协作、路由和跟踪。通过流程引擎&#xff0c;组织能够实现业务流程的优化、标准化和自动化&#xff0c;提高工作效率和质量。 在企业…...

[SQL挖掘机] - GROUP BY语句

介绍: group by 是 sql 中用于对结果集进行分组的关键字。通过使用 group by&#xff0c;可以根据一个或多个列的值将结果集中的行分组&#xff0c;并对每个分组应用某种聚合函数&#xff08;如 count、sum、avg 等&#xff09;以生成汇总信息。这样可以方便地对数据进行分类、…...

【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、运动学模型 运动学模型是基于几何关系分析出来的,一般适用于低俗情况下,…...

IDE/mingw下动态库(.dll和.a文件)的生成和部署使用(对比MSVC下.dll和.lib)

文章目录 概述问题的产生基于mingw的DLL动态库基于mingw的EXE可执行程序Makefile文件中使用Qt库的\*.a文件mingw下的*.a 文件 和 *.dll 到底谁起作用小插曲 mingw 生成的 \*.a文件到底是什么为啥mingw的dll可用以编译链接过程转换为lib引导文件 概述 本文介绍了 QtCreator mi…...

点击加号添加新的输入框

实现如上图的效果 html部分&#xff1a; <el-form-item class"forminput" v-for"(item,index) in formdata.description" :key"index" :label"描述(index1)" prop"description"><el-input v-model"formdata…...

SQL AND OR 运算符

AND & OR 运算符用于基于一个以上的条件对记录进行过滤。 如果第一个条件和第二个条件都成立&#xff0c;则 AND 运算符显示一条记录。 如果第一个条件和第二个条件中只要有一个成立&#xff0c;则 OR 运算符显示一条记录。 下面是选自 "students" 表的数据&a…...

6、C++内存模型

原文&#xff1a; https://my.oschina.net/u/2516597/blog/805489 背景 C11开始支持多线程&#xff0c;其中提供了原子类型atomic, 和atomic关系比较密切的是memory_order&#xff0c;所有的内存模型都是指atomic类型 enum memory_order {memory_order_relaxed,memory_order…...

上海市青少年算法2023年1月月赛(丙组)

上海市青少年算法2023年1月月赛(丙组)T1 实验日志 题目描述 小爱正在完成一个物理实验,为期n天,其中第i天,小爱会记录ai条实验数据在实验日志中。 已知小爱的实验日志每一页最多纪录m条数据,每天做完实验后他都会将日志合上,第二天,他便从第一页开始依次翻页,直到找到…...

移动开发之Wifi列表获取功能

一、场景 业务需要通过App给设备配置无线网络连接&#xff0c;所以需要App获取附近的WiFi列表&#xff0c;并进行网络连接验证。 二、安卓端实现 1、阅读谷歌官网文档&#xff0c;关于Wifi 接口使用 https://developer.android.com/guide/topics/connectivity/wifi-scan?hl…...

MyBatisPlus - 实体类 的 常用注解

TableName(“表名”) 假设 表名是 book&#xff0c;实体类类名是 Book MyBatisPlus会进行自动映射 但如果 表名是 tab_book&#xff0c;实体类类名是 Book 那么MyBatisPlus就无法进行自动映射&#xff0c;需要我们使用 TableName注解 去指定实体类对应的表 如下 TableNa…...

vue3+ts+elementui-plus二次封装树形表格实现不同层级展开收起的功能

一、TableTreeLevel组件 <template><div classmain><div class"btns"><el-button type"primary" click"expandLevel(1)">展开一级</el-button><el-button type"primary" click"expandLevel(2…...

Qt之切换语言的方法(传统数组法与Qt语言家)

http://t.csdn.cn/BVigB 传统数组法&#xff1a; 定义一个字符串二维数组&#xff0c; QString weekStr[2][7] {"星期一","星期二","星期三","星期四","星期五","星期六","星期日",\ "Monday&…...

qt root start faild

深入解析chown -r root:root命令_笔记大全_设计学院 ffmpeg第五弹&#xff1a;QtSDLffmpeg视频播放演示_txp玩Linux的博客-CSDN博客...