0%

k8s 中的安全守护神 -- 你不知道不代表它不在

关于 Kubrenetes 系列其他文章的传送门

  1. 《 部署 Kubernetes 也能如此简单吗? 》

  2. 《 初识 k8s,新时代的宠儿 》

  3. 《 深度学习 Pod 》

  4. 《 学会这 5 种 Pod 控制器,搞定发布、更新、回滚,从此告别人肉运维!! 》

  5. 《 k8s 中的网络入口 – Service 资源管理 》

  6. 《 k8s 中的 7 层调度 – Ingress 》

  7. 《 k8s 中的存储系统 – Volumes 》

  8. 《 k8s 中强大的配置中心 – ConfigMap 》

  9. 《 k8s 中的部署神器 – Statefulset 控制器 》

  10. 《 k8s 中的安全守护神 – 你不知道不代表它不在 》     您当前所在位置

  11. 《 k8s 中的图形接口 – Dashboard 》

  12. 《 k8s 中的网络插件 – flannel 和 Calico 》

  13. 《 k8s 中的调度器 – 亲和性、污点和容忍性 》

  14. 《 k8s 中对资源的监控 – 资源指标、Prometheus、弹性伸缩器 HPA 》

  15. 《 k8s 中的云原生应用管理利器 – Helm 》

  16. 《 理解 k8s 高可用,让你的集群稳如泰山 》



logo

一、k8s 是如何保护集群的数据安全

etcd 其实就是一个通用键值存储,但是在 k8s 中,不允许在 etcd 中随意存储数据,所以操作都需要通过 kube-apiserver 来完成的。

为了保证安全,k8s 必须为在其之上运行的所有的资源,在访问上构建出一个安全的访问模型来。

插件机制

k8s 的安全由三类插件来完成,他们的主要工作范围有:

  • Auth:账号认证模块;
  • Authorization:根据不同的账号赋予不同的权限的授权模块;如果只有写操作,那么就到此为止了;
  • Addmission Contrl:如果涉及到写操作,那么就需要使用准入控制模块:
    • 校验类控制器:检查用户要创建的资源是否被允许创建;
    • 变异类控制器:将用户没有指定的参数进行默认值补全;

Auth 和 Authorization 类型都有很多插件可以用,激活则开启,不激活则不生效。当一个类型中有多个插件同时激活时,采用自上而下的验证顺序,执行 一票通过制。

  • 所有插件,如果一个显式许可都没有,则进入匿名用户。

而 Addmission Contrl 类型的插件是自上而下,一票否决制 的验证顺序。

  • 需要全部插件都允许,才算通过。

(Auth)认证模块

支持的认证有:证书认证(双向认证),密码认证,令牌认证,引导令牌,JWT 令牌。

  • 证书认证:采用双向认证,并且每个客户端绝对不能使用同一个证书,因为要验证身份,把 CN 字段作为用户名,O 字段为组;
  • 引导令牌:如果使用 kubeadm 部署,当一个 node 节点加入集群时,会带着引导令牌自动向 kube-apiserver 申发证书签发,之后引导令牌就无效了,转而使用证书认证。而如果是手动部署而话,则需要一台一台手动去认证。

k8s 中的用户有两类:

  • 常规用户(人类用户):
    • 是 k8s 中不存在的账号,只要有证书,并通过认证即可;
  • 服务账号(Service Account)
    • k8s 中存在的账号。

每一个 Pod 也需要令牌,使用 kubectl describe pods 查看 Pod,可以看到在 Mounts 字段中,默认会自动挂载一个存储卷,这是用来连接至 kube-apiserver 查看自己运行状态时使用的令牌,每个 Pod 的令牌都不同。

当创建一个 Pod 时,k8s 可以借助一个准入控制器,自动为 Pod 赋予一个私有的务账号,并且会自动把这个服务账号的令牌,以存储卷的方式挂载至当前 Pod。所以当这个容器内的进程需要连接至 kube-apiserver 时,就使用这个认证信息登录。

认证相关的配置文件 – kubeconfig

k8s 认证相关的配置文件保存在 /etc/kubernetes/admin.conf,是 yaml 格式的配置文件,它通常由以下 几个配置段组成:

  • users:用户账号及其认证信息列表,可以有多个用户;
  • clusters:目标集群列表,可以有多个集群;
  • contexts:user 和 cluster 的使用上下文,可以组合定义用哪个 user 接入哪个 clusters,且可以配置多组;
  • current-context:定义启用哪组上下文,可以来回切换;

显示配置文件信息,会隐藏证书信息;可指定配置文件路径,不指定默认为下面的路径:

1
~]# kubectl --kubeconfig=/etc/kubernates/admin.conf config view

查看 cluster 列表:

1
~]# kubectl --kubeconfig=/etc/kubernates/admin.conf config get-cluster

查看上下文列表:

1
~]# kubectl --kubeconfig=/etc/kubernates/admin.conf config get-contexts

显示当前激活的上下文:

1
~]# kubectl --kubeconfig=/etc/kubernates/admin.conf config current-context

二、创建一个客户端账号(User Account)

客户端账号通常是人类用户。

创建一个名为 ilinux 的客户端证书

创建私钥文件 ilinux.key:

1
2
~]# cd /etc/kubernetes/pki/
~]# openssl genrsa -out ilinux.key 2048

为用户创建一个证书签署请求格式(scr)的文件,其中 CN 会被识别为用户名,O 为组,组在 k8s 中可以不存在:

1
~]# openssl req -new -key ilinux.key -out ilinux.csr -subj "/CN=ilinux/O=kubeusers"

用这个 CA /etc/kubernetes/pki/ca.crt 为证书签名。

1
2
~]# cd /etc/kubernetes/pki
~]# openssl x509 -req -in ilinux.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out ilinux.crt -days 3560

签名完成后,会得到 ilinux.crt 证书文件,而证书签署请求文件 ilinux.scr 其实就没用了。

现在我们两个文件:

  • 经过 CA 认证的证书文件 ilinux.crt
  • 自己的私钥 Key 文件 ilinux.key

其实就可以认证到集群并使用集群了,不过接下来我们将它配置为 kubeconfig 文件,方便以后使用。

创建集群的 kubeconfig 文件

创建 cluster

kubectl config set-cluster:使用这个命令创建集群项:

  • --server:apiServer 的服务器地址;
  • --certificate-authority=:指明证书签署机构的证书;
  • --embed-certs=true:把证书信息打包起来,去明文化;
  • --kubeconfig=/tmp/ilinux.conf:指定把配置文件保存到哪,不指定的话默认存在自带的 /etc/kubernetes/admin.conf 中去。
1
2
3
4
5
~]# kubectl config set-cluster my_kube --server="https://192.168.50.14:6443" \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--kubeconfig=/tmp/ilinux.conf
Cluster "my_kube" set.

查看刚才创建的配置文件,在 /tmp/ilinux.conf 下,可以看到内部只有 cluster 的相关配置,下面创建用户配置。

创建 user

kubectl config set-credentials:使用这个命令创建用户项:

  • NAME:用户信息的标识;
  • --client-certificate=:客户端证书的路径;
  • --client-key=:客户端私钥的路径;
  • --username=:用户的用户名;
  • --password=:使用密码认证时指明 password;
  • --token=:使用令牌认证时指明 token
  • --embed-certs=true:把证书信息打包起来,去明文化;
1
2
3
4
5
6
~]# kubectl config set-credentials ilinux --client-certificate=/etc/kubernetes/pki/ilinux.crt \
--client-key=/etc/kubernetes/pki/ilinux.key \
--username=ilinux \
--embed-certs=true \
--kubeconfig=/tmp/ilinux.conf
User "ilinux" set.

查看配置文件 /tmp/ilinux.conf,应该就被增加了 user 的相关配置。这时应该有 cluster 和 user 的配置,下面把两者关联起来。

定义 user 和 cluster 的上下文关系(context)

kubectl config set-context NAME:使用这个命令创建 user 和 cluster 的关系上下文(context):

  • NAME:这个关系上下文的名字;
  • --cluster=:指明哪个集群;
  • --user=:用户是哪个;
1
2
3
4
~]# kubectl config set-context ilinux@my_kube --cluster=my_kube \
--user=ilinux \
--kubeconfig=/tmp/ilinux.conf
Context "ilinux@my_kube" created.

查看配置文件 /tmp/ilinux.conf,这时应该就有了 cluster 和 user 关系上下文的相关配置。

切换关系上下文

切换到名为 ilinux@my_kube 的关系上下文:

1
2
~]# kubectl config use-context ilinux@my_kube --kubeconfig=/tmp/ilinux.conf
Switched to context "ilinux@my_kube".

测试

使用我们创建的 ilinux 的用户的配置文件查看 Pod 时,可以看到因为没有权限,所以无法读取:

1
2
~]# kubectl get pods --kubeconfig=/tmp/ilinux.conf
Error from server (Forbidden): pods is forbidden: User "ilinux" cannot list resource "pods" in API group "" in the namespace "default"

如果要使用管理员账户,则不指定配置文件路径即可,默认会使用 /etc/kubernetes/admin.conf:

1
~]# kubectl get pods

三、创建一个服务账号(Service Account)

当 k8s 内部的某一个 Pod,或是之外的某一个守护进程,需要通过 apiserver 连入 k8s 的时候,也应该认证。

SA 的定义方式和其他 Pod 类似,通过 apiversion、metadata、kind 来配置基本信息,但是用户的认证信息是在 secrets 字段中保存的。

secrets 中可以使用的类型有 TLS、generic、docker-registry,而之前讲过的 TLS 类型是用来做 SSL 通信的,并不是作为 k8s 集群认证使用的,所以 SA 这里应该使用 generic 类型的 secrets。

在创建 SA 时,是不必自己手动去定义 secrets 的,因为在创建 SA 账号时,k8s 会自动生成一个 secrets,其中包括认证所需要的信息。之所以会自动生成,因为认证并不是最终目标,对这个 SA 账号的授权才是关键。

创建 SA 配置文件

1
2
3
4
5
6
7
-> # vim serviceaccount-demo.yaml 

apiVersion: v1
kind: ServiceAccount
metadata:
name: sa-demo
namespace: default

创建一个 SA

1
2
-> # kubectl apply -f serviceaccount-demo.yaml
serviceaccount/sa-demo created

查看

1
2
3
4
-> # kubectl get sa
NAME SECRETS AGE
default 1 18d # 创建 Pod 时如果没指定 SA,默认就用的这个 SA
sa-demo 1 5s # 这是刚刚创建的

可以看到对应的 secrets 也被创建好了

1
2
3
4
5
-> # kubectl get secrets   
NAME TYPE DATA AGE
default-token-mzmwh kubernetes.io/service-account-token 3 18d
sa-demo-token-kbwx9 kubernetes.io/service-account-token 3 4m29s # 这个是刚刚被自动创建的
ssltest-cert kubernetes.io/tls 2 10d

四、授权模块

授权模块的相关概念

授权模块有三种:

  • ABAC:基于属性的访问控制;
  • RBAC:基于角色的访问控制,定义“谁”能对“什么资源”做“哪些操作”;
    • 1.8 版本之后默认使用,并强制生效,需要显式授权;
  • Node:根据 Pod 对象调度的结果为 Node 进行授权。

查看当前 apiserver 启动时加载的授权插件都有哪些:

1
2
~]# cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep "authorization"
--authorization-mode=Node,RBAC

查看自己对某个操作是否有权限:

1
~]# kubectl auth can-i create deployments --namespace dev

关于 RBAC

RBAC 即:基于角色的访问控制 (Role-based access control)

RBAC 的逻辑架构:

  • Subjects:主语:
    • User Account;
    • Service Account;
  • Object:被操纵对象:
    • Resources:比如 Pod、Service;
    • SubResources:子资源;
    • URL:非对象型资源;
  • Role 和 RoleBinding:把 Subjects 与 Object 桥接的组件;
    • Role:定义了用户的操纵(Verbs)可以被施加在哪个资源(Resources)上;
    • RoleBinding:让 Subjects 扮演某个 Role,并拥有某个 Role 的权限;

可以用来使用的“操纵”选项:

HTTP verb request verb
POST create
GET,HEAD get,list
PUT update
PATCH patch
DELETE delete

在 k8s 中有两种级别的 Role:

  • Role:名称空间级别的 Role;不包含 ClusterRole;
  • ClusterRole:集群级别的 Role;包含 Role;

所以对应于 RoleBinding 也有两种级别:

  • RoleBinding:把用户绑定至名称空间级别的 Role;
  • ClusterRoleBinding:把用户绑定至集群级别的 ClusterRole;

两者可以交替绑定:

  • 当使用 ClusterRoleBinding 把一个用户和 Role 绑定时,会获得 Cluster 级别的权限,在所有名称空间内都有权限(升权);
  • 但是使用 RoleBinding 把一个用户和 ClusterRole 绑定时,那么所获得的只是 RoleBinding 所属的名称空间级别的权限(降权);
    • 降权应用场景:假设 k8s 中有 30 个名称空间,如果要使用 RoleBinding 在每个名称空间内绑定 Role,那么 RoleBinding 和 Role 要分别在这 30 个名称空间内创建 30 个,并一一绑定;而如果使用 RoleBinding 绑定 ClusterRole,那么只需要创建一个 ClusterRole,然后创建 30 个 RoleBinding,就能解决问题了。

创建授权,并绑定给之前创建的 ilinux 用户

创建一个名称空间级别的 Role 规则,目标是只允许读 default 名称空间下的 Pods 和 Services:

1
2
3
4
5
6
7
8
9
10
11
-> # vim recouse-reader.yaml

kind: Role ### 如果要创建集群级别的 Role,这里要写为 kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default # 这里是名称空间级别的,要指明创建在哪个名称空间;# 如果创建的是集群级别的 ClusterRole,这行要省略不能定义
name: recouse-reader
rules:
- apiGroups: [""] # 指定资源所在的 API 群组,"" 表示 core API group,也就是 v1,而 * 表示所有群组
resources: ["pods", "pods/log", "services"] # 定义允许操作的资源
verbs: ["get", "list", "watch"] # 定义对资源可用哪种操作

使用 RoleBinding 把某个用户绑在 Role 上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-> #  vim read-pods.yaml

kind: RoleBinding ### 如果要创建集群级别的 ClusterRoleBinding,要写为 kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: ilinux-recouse-reader
namespace: default ### 当绑定至集群级别的 ClusterRole 时,权限会降级至这里定义的名称空间
subjects:
- kind: User
name: ilinux # 指定哪个用户
apiGroup: rbac.authorization.k8s.io # 这里要使用创建 Role 时的 apiVersion
roleRef:
kind: Role ### 如果要绑定至集群级别的 ClusterRole,要写为 kind: ClusterRole
name: recouse-reader # 指定绑在哪个 Role 上
apiGroup: rbac.authorization.k8s.io

使配置生效:

1
2
3
4
5
~]# kubectl apply -f recouse-reader.yaml
role.rbac.authorization.k8s.io/recouse-reader created

~]# kubectl apply -f read-pods.yaml
rolebinding.rbac.authorization.k8s.io/ilinux-recouse-reader created

授权后,再次使用之前创建的 ilinux 用户尝试读取 Pods 和 Services,就会有权限读取了,只是现在没有 Pod 而已:

1
~]# kubectl get pods --kubeconfig=/tmp/ilinux.conf

内键的 ClusterRole

k8s 内置了 4 个,集群级别的,核心组件角色 ClusterRole,意义如下:

默认 ClusterRole 默认 ClusterRoleBinding 描述
cluster-admin system:masters group 允许超级用户对任何资源执行任何操作。当使用 ClusterRoleBinding 绑定授权时,它可以完全控制集群中所有名称空间中的每个资源;而使用 RoleBinding 绑定授权时,它可以完全控制角色绑定的名称空间中的每个资源,包括名称空间本身。
admin None 使用 RoleBinding 在指定的名称空间中绑定授权后,则允许对名称空间内的大多数资源进行读/写访问,包括在命名空间中创建角色和角色绑定的能力。它不允许对资源配额或名称空间本身进行写访问。
edit None 只允许对指定的命名空间内的大多数对象进行读/写访问,它不允许查看或修改角色或角色绑定。
view None 只允许以只读的方式查看指定名称空间中的大多数对象,它不允许查看角色或角色绑定,它不允许查看 Secret。

五、准入控制

先对经常使用的插件做个介绍

  • DefaultStorageClass:为没有定义 SC 的 PV 和 PVC 默认分配一个 SC;
  • LimitRanger(限制范围):主要防止 单个 Pod 使用的资源过多。是一个准入控制器,它允许在某个名称空间上创建一个叫 LimitRange 类型的资源,这是一个标准的 k8s 资源,并且是名称空间级别的。可以为这个名称空间内所有的 Pod,限制一个默认的资源使用的上、下限规则,过高或过低都不行。LimitRange 资源只负责去检查用户的资源是否违反了限制,而真正执行的是 LimitRanger 控制器,所以要使用 LimitRange 资源的前提是 k8s 集群在启动时加载了 LimitRanger 控制器。
  • ResourceQuota(资源配额):主要防止 单个名称空间 使用的资源总量过多。这也是一个标准的 k8s 资源,允许用户自已定义一个 ResourceQuota 类型的资源,并生效在某个名称空间上,用于定义整个名称空间在集群内部最低使用多少资源。同样,ResourceQuots 资源只负责去检查用户的资源是否违反了限制,而真正执行的是 ResourceQuots 控制器,所以要使用 ResourceQuots 资源的前提是 k8s 在启动时加载了 ResourceQuots 控制器。
  • PodSecurityPolicy(Pod 安全策略):这也是一个标准的 k8s 资源类型,可以通过这个资源,限制运行在某个名称空间中的某个 Pod,必须明确符合在 PSP 中定义的 Pod 安全策略,任何违反的 Pod 都不允许创建。PSP 资源的生效也是需要使用 PSP 准入控制器的,并且 PSP 资源需要显式指明,任何没有明确允许的操作都是不允许的,所以 PSP 默认没有开启。

如何启用准入控制器:

  • 使用 kubeadm 部署的集群,如果想定义启动哪些准入控制器,需要编辑 apiServer 的配置文件 /etc/kubernetes/manifests/kube-apiserver.yaml,在 --enable-admission-plugins=NodeRestriction 字段添加。可以看到默认这里定义开启了一个。其实一些这里没指明的准入控制器也默认开启了,比如 LimitRanger,不过不同版本的 k8s 对于默认启用哪些模块都不太一样,具体需要查看官方文档。

LimitRange(限制范围)

在名称空间的级别,为所创建的每一个 Pod 定义以下几个属性:

  • 如果 Pod 没有定义默认的资源请求和资源限制,可以为 Pod 自动施加一个默认的 Request 和 Limit;
    • 如果 Pod 自己定义了,那么默认的就不生效;
  • 限制名称空间内的每个 Pod 或 Container 可使用资源的最小(min)和最大值(max);
    • 如果 Pod 自己定义了,那么不可以超过此处定义的值的上下限。

示例:

limitrange-demo.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-limit-range
spec:
limits:
- default: # 当 Pod 自己没定义时,默认的上限
cpu: 1000m
defaultRequest: # 当 Pod 自己没定义时,默认的下限
cpu: 1000m
min: # 如果 Pod 定义了,不可以低于此处定义的最小值
cpu: 500m
max: # 如果 Pod 定义了,不可以超过此处定义的最大值
cpu: 2000m
maxLimitRequestRatio: # 上限值需要是下限值的多少倍
cpu: 4
type: Container

创建,使用 -n 指定哪个名称空间,就对哪个生效:

1
2
-> # kubectl apply -f limitrange-demo.yaml -n myns
limitrange/cpu-limit-range created

查看详情:

1
2
3
4
5
6
-> # kubectl describe limitrange -n myns
Name: cpu-limit-range
Namespace: myns
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container cpu 500m 2 1 1 4

ResourceQuota(资源配额)

计算资源配额

用户可以对指定命名空间下的可被请求的 计算资源 总量进行限制。

配额机制所支持的资源类型:

资源名称 描述
limits.cpu 所有非终止状态的 Pod 中,其 CPU 限额总量不能超过该值。
limits.memory 所有非终止状态的 Pod 中,其内存限额总量不能超过该值。
requests.cpu 所有非终止状态的 Pod 中,其 CPU 需求总量不能超过该值。
requests.memory 所有非终止状态的 Pod 中,其内存需求总量不能超过该值。
cpu 与 requests.cpu 相同。
memory 与 requests.memory 相同。

存储资源配额

用户可以对给定命名空间下的 存储资源 总量进行限制。

此外,还可以根据相关的存储类(Storage Class)来限制存储资源的消耗。

资源名称 描述
requests.storage 所有 PVC 请求的存储空间总和不能超过此值。
persistentvolumeclaims 在名称空间中 PVC 的总数不能超过此值。
<storage-class-name>.storageclass.storage.k8s.io/requests.storage 在所有与 <storage-class-name> 相关的持久卷申领中,所有 PVC 请求的存储空间总和不能超过此值。
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims 在与 storage-class-name 相关的所有持久卷申领中,命名空间中可以存在的最大持久卷申领总数。

举例:如果一个操作人员针对 gold 类型存储与 bronze 类型存储设置配额,操作人员可以定义如下配额:

  • gold.storageclass.storage.k8s.io/requests.storage: 500Gi
  • bronze.storageclass.storage.k8s.io/requests.storage: 100Gi

在版本 1.8 后,添加了对 本地临时存储 的配额支持,已经是 Alpha 功能:

资源名称 描述
requests.ephemeral-storage 在命名空间中的所有 Pod 中,本地临时存储请求的总和不能超过此值。
limits.ephemeral-storage 在命名空间的所有 Pod 中,本地临时存储限制的总和不能超过此值。
ephemeral-storage 与 requests.ephemeral-storage 相同。

对象数量配额

1.9 版本之后,增加了对 对象数量 配额设置。

可以使用以下语法,对名称空间内的所有资源类型进行配额分配:

  • count/<resource>.<group>:用于非核心(core)组的资源
  • count/<resource>:用于核心组的资源

例如:限制使用的 PVC 的总数:

1
count/persistentvolumeclaims  

配额作用域

每个配额都有一组相关的 scope(作用域),配额只会对作用域内的资源生效。配额机制仅统计所列举的作用域的交集中的资源用量。

当一个作用域被添加到配额中后,它会对作用域相关的资源数量作限制。如配额中指定了允许(作用域)集合之外的资源,会导致验证错误。

  • 配额只会作用到指定的作用域上:
资源名称 描述
Terminating 匹配所有 spec.activeDeadlineSeconds 不小于 0 的 Pod。
NotTerminating 匹配所有 spec.activeDeadlineSeconds 是 nil 的 Pod。
BestEffort 匹配所有 Qos 是 BestEffort 的 Pod。
NotBestEffort 匹配所有 Qos 不是 BestEffort 的 Pod。
PriorityClass 匹配所有引用了所指定的优先级类的 Pods。

更多关于配额作用域的参数:https://kubernetes.io/zh/docs/concepts/policy/resource-quotas/#quota-scopes

示例

vim resoucequota-demo.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-example
spec:
hard:
pods: "5" # Pod 数量不能超过此值
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
count/deployments.apps: "2" # deploy 控制器的数量上限
count/deployments.extensions: "2"
persistentvolumeclaims: "2"

创建并查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-> # kubectl apply -f resoucequota-demo.yaml -n myns
resourcequota/quota-example created


-> # kubectl describe resourcequota -n myns
Name: quota-example
Namespace: myns
Resource Used Hard
-------- ---- ----
count/deployments.apps 0 2
count/deployments.extensions 0 2
limits.cpu 0 2
limits.memory 0 2Gi
persistentvolumeclaims 0 2
pods 0 5
requests.cpu 0 1
requests.memory 0 1Gi

PodSecurityPolicy(Pod 安全策略)

与 PSP 相关的参数和详细教程:https://kubernetes.io/zh/docs/concepts/policy/pod-security-policy/

PSP 在生产环境中实现的模板:

先创建两个 PSP 清单,一个定义特权操作,一个定义受限操作。

特权 PSP 清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-> # cat psp-privileged.yaml 
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: privileged
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
privileged: true
allowPrivilegeEscalation: true
allowedCapabilities:
- '*'
volumes:
- '*'
hostNetwork: true
hostPorts:
- min: 0
max: 65535
hostIPC: true
hostPID: true
runAsUser:
rule: 'RunAsAny'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'

受限的 PSP 清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
-> # cat psp-restricted.yaml 
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
spec:
privileged: false
allowPrivilegeEscalation: false
requiredDropCapabilities:
- ALL
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
hostNetwork: false
hostIPC: false
hostPID: false
runAsUser:
rule: 'MustRunAsNonRoot'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
fsGroup:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
readOnlyRootFilesystem: false

然后创建两个集群角色,一个为特权角色,并绑定特权 PSP 清单,另一个为受限的角色,并绑定受限的 PSP 清单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-> # vim clusterrole-with-psp.yaml 

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp:restricted
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames:
- restricted
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: psp:privileged
rules:
- apiGroups: ['policy']
resources: ['podsecuritypolicies']
verbs: ['use']
resourceNames:
- privileged

之后将两个集群角色,使用 ClusterRoleBinging 绑定至合适的组即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-> # vim clusterrolebinding-with-psp.yaml 

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: restricted-psp-user
roleRef:
kind: ClusterRole
name: psp:restricted
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: Group
apiGroup: rbac.authorization.k8s.io
name: system:authenticated # 通过认证登录的用户会被自动归类到此组,使用非特权角色
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: privileged-psp-user # 下面绑定的都是一些需要特权操作的组,以保证 k8s 集群能正常运行
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: psp:privileged
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:masters
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:node
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:serviceaccounts:kube-system