许吉友 - 运维

深入分析集群安全机制

参考《Kubernetes 权威指南(第四版)》第六章。

k8s 的集群的安全控制机制包括:API Server 的认证授权、准入控制机制及保护敏感信息的 Secret 机制等。

集群安全性的目标:

  1. 保证容器与其所在宿主机的隔离。
  2. 限制容器给基础设施或其他容器带来的干扰。
  3. 最小权限原则 --- 合理限制所有组件的权限,确保组件只执行它被授权的行为,通过限制单个组件的能力来限制他的权限范围
  4. 明确组件间边界的划分。
  5. 划分普通用户和管理员的角色。
  6. 在必要时允许将管理员权限赋给普通用户。
  7. 允许拥有 Secret 数据(Keys,Certs,Passwords)的应用在集群中运行。

下面分别从 Authentication、Authorization、Admission Control、Secret 和 Service Accounnt 等方面学习。

API Server 认证管理

API Server的安全关键点在于认证和授权。这一节先学习认证。

K8s 集群提供了三种级别的客户端认证方式:

API Server 授权管理

API Server 目前支持一下几种授权策略(通过 API Server 的启动参数 --authorization-mode 设置)

下面重点学习一下 RBAC。

RBAC 有如下优势:

RBAC 的 API 资源使用说明

RBAC 引入来了4个新的顶级资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding。

Role

一个角色就是一组权限的集合,所有的权限都是许可形式的,不存在拒绝规则。在一个命名空间中,可以用 Role 来来定义一个角色,如果是集群级别的,就需要使用 ClusteerRole 了。

Role 只能对命名空间内资源进行授权。一个 Role 的定义如下,设置角色具有 Pod 读取的权限:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # 空字符串""表明使用core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

使用如下命令可以看到资源及其操作方法列表:

$ kubectl api-resources -o wide
NAME  SHORTNAMES APIGROUP   NAMESPACED   KIND    VERBS
pods  po                    true         Pod     [create delete deletecollection get list patch update watch]

ClusterRole

ClusterRole 除了具有和 Role 一致的功能外,还能管理集群级别的范围。可以用于一下特殊元素的授权:

下面的这个 ClusterRole 可以让用户有权访问任意一个或所有命名空间的 secrets:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  # 鉴于ClusterRole是集群范围对象,所以这里不需要定义"namespace"字段
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

RoleBindingClusterRoleBinding

这两个对象用于将角色绑定到一个目标上,绑定的目标可以是 User (用户)、Group(组)、或者 Service Account。

下面的例子将读取 pods 的权限授予用户 jane。

# 以下角色绑定定义将允许用户"jane"从"default"命名空间中读取pod。
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

更多例子见:https://jimmysong.io/kubernetes-handbook/guide/rbac.html

API Server 会创建一套默认的 ClusterRole 和 ClusterRoleBinding,其中很多是以 system: 为前缀的,以表面这些资源属于基础架构。

Admission Control

Admission Control 赔本了一个准入控制器的插件列表。发送给 API Server 的任何请求都需要通过列表中每个准入控制器的检查,检查不通过,则 API Server 拒绝此调用操作。

Service Account

Service Account 是给 Pod 中的进程使用的,它为 Pod 里的进程提供了必要的身份证明。

Pod 访问 API Server 是通过访问 default 命名空间下的 kubernetes 服务来实现的。

Pod 中有以下三个文件,可以去 Pod 中检查:

这三个文件会参与到 Pod 进程与 API Server 的认证过程中,起到了类似 secret(私钥凭据) 的作用。所以他们被称为 Kubernetes Secrert 对象。Secret 从属于 Service Account 资源对象,属于 Service Account 的一部分,在一个 Service Account 中可以包含多个不同的 Secret 对象,分别用于不同目的的认证活动。

实战:

$ kubectl describe serviceaccoounts
Name:                default
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   default-token-nkp26
Tokens:              default-token-nkp26
Events:              <none>

查看 default-token-nkp26 这个 Secret:

[admin@fueltank-1 ~]$ kubectl describe  secrets default-token-nkp26
Name:         default-token-nkp26
Namespace:    default
Labels:       <none>
Annotations:  field.cattle.io/projectId: local:p-68c8g
              kubernetes.io/service-account.name: default
              kubernetes.io/service-account.uid: 7fea01e3-c24d-4641-ab08-c59ca18d0d17

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1017 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6Ilp3NEFnZDBBRUV4ZXlUZGhQaENvUE5UbVIxRm5xLVRsSUxNbVNKNXExblkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tbmtwMjYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjdmZWEwMWUzLWMyNGQtNDY0MS1hYjA4LWM1OWNhMThkMGQxNyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.x3Hw-MZqh0kd1WomvSpIiVYpkNFtUoSy98XlnHlpfoyN9LrDKFg2qTWoNxnMd8kN_10sfbiCrY2BBcvxpsl0zE2vrDYKWcKL7PLCRtulXwxI5g3Ucvx8tg-GsKNd-IbKcyGKPCUhUC_D4kFaWUdVQ__hgyL5pnFC6QupCv7qFj_lyNd4ymVT6ZpJ-G5oyP69FIrgHpzR1oSVTjQ7Zc3msuPjjBEJclzJzDjJRKL3gt-q8w_h2NQpWi_miK-Vo9u_RGkgf9Lmw5IR-kbI6XinID6FDwgiVsgofNgZiFpmIZa03jt_A9Uo93AfZWB4vs9CeU4mtH-kK4SA-SP6GDkDLQ

可以看到,这个 secrets 包含三个数据项,其内容正好对应上边的那三个文件!!!

实际上,在每个 命名空间 下,都有一个名为 default 的默认 Service Account 对象。在这个 Service Account 里面有一个名为 token 的可以当作 Volume 被挂在到 Pod 里。

Secret 私密凭据

Secret 的作用主要是保管私密数据,比如密码,OAuth Tokens、SSH Keys 等信息。将这些私密信息放在 Secret 对象中比直接放在 Pod 或 Docker Image 中更安全,也更便于使用和分发。

创建一个 Secret:

$ echo -n 'my-app' | base64
bXktYXBw
$ echo -n '39528$vdg7Jb' | base64
Mzk1MjgkdmRnN0pi

Secret.yaml:

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  username: bXktYXBwCg==
  password: Mzk1MjgkdmRnN0piCg==

data 域的各子域值必须是 BASE64 编码的。

可以使用三种方式使用 Secret:

最后,需要注意一点,如果 Secret 更改了,Pod 中已经使用的 Secret 并不会更改,所以需要重新创建 Pod !!!!!!

Pod 的安全策略配置

PodSecurityPolicy 用于对 Pod 的安全策略进行管理,可以更精细的控制 Pod 对资源的使用方式。

PodSecurityPolicy 的工作机制

若想启用 PodSecurityPolicy ,需要在 kube-apiserver 服务中添加如下启动参数:

--enable-admission-plugins=PodSecurityPolicy

在开启 PodSecurityPolicy 之后,Kubernetes 默认不允许创建任何 Pod,需要创建 PodSecurityPolicy 策略和相应的 RBAC 授权策略,Pod 才能创建成功。