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 类似,通过 apiversionmetadatakind 来配置基本信息,但是用户的认证信息是在 secrets 字段中保存的。

secrets 中可以使用的类型有 TLSgenericdocker-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.activeDeadlineSecondsnil 的 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