深刻浅出 Kubernetes 安全机制

《深刻浅出 Kubernetes 安全机制》最先发布在 blog.hdls.me/15432142284…html

在 Kubernetes 中,全部资源的访问和变动都是围绕 APIServer 展开的。好比说 kubectl 命令、客户端 HTTP RESTFUL 请求,都是去 call APIServer 的 API 进行的,本文就重点解读 k8s 为了集群安全,都作了些什么。node

首先,Kubernetes 官方文档给出了上面这张图。描述了用户在访问或变动资源的以前,须要通过 APIServer 的认证机制、受权机制以及准入控制机制。这三个机制能够这样理解,先检查是否合法用户,再检查该请求的行为是否有权限,最后作进一步的验证或添加默认参数。web

用户

Kubernetes 中有两种用户,一种是内置“用户” ServiceAccount,另外一种我称之为天然人。json

所谓天然人就是指区别于 pod 等资源概念的“人”,能够理解成实际操做 "kubectl" 命令的人。admin 能够分发私钥,但天然人能够储存相似 KeyStone 甚至包含帐号密码的文件,因此 k8s 中没有对天然人以 API 对象描述之。bootstrap

在典型的 Kubernetes 集群中,API 一般服务在 443 端口,APIServer 提供自签名证书。当你使用 kube-up.sh 建立集群用户时,证书会自动在 $USER/.kube/config 中建立出来,然后续用 kubectl 命令访问 APIServer 时,都是用这个证书。api

与之相反,k8s 中以 API 对象的形式描述和管理 ServiceAccount。它们被绑定在某个具体的 namespace 中,能够由 APIServer 自动建立出来或手动 call k8s API。安全

认证机制(Authentication)

k8s 中的认证机制,是在用户访问 APIServer 的第一步。一般是一个完整的 HTTP 请求打过来,可是这一步每每只检测请求头或客户端证书。bash

认证机制目前有客户端证书、bearer tokens、authenticating proxy、HTTP basic auth 这几种模式。使用方式一般有如下几种:ide

  1. X509 Client Certs: 客户端证书模式须要在 kubectl 命令中加入 --client-ca-file=<SOMEFILE> 参数,指明证书所在位置。ui

  2. Static Token File: --token-auth-file=<SOMEFILE> 参数指明 bearer tokens 所在位置。

  3. bearer tokens: 在 HTTP 请求头中加入 Authorization: Bearer <TOKEN>

  4. Bootstrap Tokens: 与 bearer tokens 一致,但 TOKEN 格式为 [a-z0-9]{6}.[a-z0-9]{16}。该方式称为 dynamically-managed Bearer token,以 secret 的方式保存在 kube-system namespace 中,能够被动态的建立和管理。同时,启用这种方式还须要在 APIServer 中打开 --enable-bootstrap-token-auth ,这种方式还处于 alpha 阶段。

  5. Static Password File: 以参数 --basic-auth-file=<SOMEFILE> 指明 basic auth file 的位置。这个 basic auth file 以 csv 文件的形式存在,里面至少包含三个信息:password、username、user id,同时该模式在使用时须要在请求头中加入 Authorization: Basic BASE64ENCODED(USER:PASSWORD)

  6. Service Account Tokens: 该方式一般被 pod 所使用,在 PodSpec 中指明 ServiceAccount 来访问 ApiServer。

除了以上列出来的几种方式外,还有一些比较特殊的访问方式,这里再也不详细解读。

受权机制(Authorization)

当用户经过认证后,k8s 的受权机制将对用户的行为等进行受权检查。换句话说,就是对这个请求自己,是否对某资源、某 namespace、某操做有权限限制。

受权机制目前有 4 种模式:RBAC、ABAC、Node、Webhook。下面对这 4 种模式分别作分析。

RBAC

Role-based access control (RBAC) 是基于角色的权限访问控制,一般是对于“内置用户”而言的。该模式是在 k8s v1.6 开发出来的。若要开启该模式,须要在 APIServer 启动时,设置参数 --authorization-mode=RBAC

RBAC 所使用的 API Group 是 rbac.authorization.k8s.io/v1beta1,直到 Kubernetes v1.8 后,RBAC 模块达到稳定水平,所使用的 API Group 为 rbac.authorization.k8s.io/v1

所谓基于角色的权限访问控制,就是对某个用户赋予某个角色,而这个角色一般决定了对哪些资源拥有怎样的权限。

ServiceAccount

首先来看看这个 “内置用户”,在大多时候咱们都不使用 “天然人” 这个功能,而是使用 ServiceAccount,再对其余资源授予某个 ServiceAccount,就使得其可以以 “内置用户” 的身份去访问 APIServer。

建立一个 ServiceAccount 很简单,只须要指定其所在 namespace 和 name 便可。举个例子:

apiVersion: v1
kind: ServiceAccount
metadata:
 namespace: hdls
 name: hdls-sa
复制代码

Role & Rolebinding

RBAC 中最重要的概念就是 RoleRoleBindingRole 定义了一组对 Kubernetes API 对象的操做权限,而 RoleBinding 则定义的是具体的 ServiceAccount 和 Role 的对应关系。

举个 Role 的例子以下:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
	namespace: hdls
	name: hdls-role
rules:
- apiGroups: [""]
 resources: ["pods"]
 verbs: ["get", "list"]
复制代码

其中: namespace: 在这里仅限于逻辑上的“隔离”,并不会提供任何实际的隔离或者多租户能力; rules:定义的是权限规则,容许“被做用者”,对 hdls 下面的 Pod 对象,进行 GET 和 LIST 操做; apiGroups:为 "" 表明 core API Group; resources:指的是资源类型,对此还能够进行详细的划分,指定能够操做的资源的名字,好比:

rules:
- apiGroups: [""]
 resources: ["configmaps"]
 resourceNames: ["my-config"]
 verbs: ["get"]
复制代码

verbs: 指的是具体的操做,当前 Kubernetes(v1.11)里可以对 API 对象进行的全部操做有 "get", "list", "watch", "create", "update", "patch", "delete"。

再看 RoleBinding 的例子:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
	name: hdls-rolebinding
	namespace: hdls
subjects:
- kind: ServiceAccount
	name: hdls-sa
	apiGroup: rbac.authorization.k8s.io
roleRef:
	kind: Role
	name: hdls-role
	apiGroup: rbac.authorization.k8s.io
复制代码

能够看到,这个 RoleBinding 对象里定义了一个 subjects 字段,即“被做用者”。它的类型是 ServiceAccount,就是上面建立的 sa。这个 subjects 还能够是 User 和 Group,User 是指 k8s 里的用户,而 Group 是指 ServiceAccounts。

roleRef 字段是用来直接经过名字,引用咱们前面定义的 Role 对象(hdls-role),从而定义了 Subject 和 Role 之间的绑定关系。

此时,咱们再用 kubectl get sa -n hdls -o yaml 命令查看以前的 ServiceAccount,就能够看到 ServiceAccount.secret,这是由于 k8s 会为一个 ServiceAccount 自动建立并分配一个 Secret 对象,而这个 Secret 就是用来跟 APIServer 进行交互的受权文件: TokenToken 文件的内容通常是证书或者密码,以一个 Secret 对象的方式保存在 etcd 当中。

这个时候,咱们在咱们的 Pod 的 YAML 文件中定义字段 .spec.serviceAccountName 为上面的 ServiceAccount name 便可声明使用。

若是一个 Pod 没有声明 serviceAccountName,Kubernetes 会自动在它的 Namespace 下建立一个名叫 default 的默认 ServiceAccount,而后分配给这个 Pod。然而这个默认 ServiceAccount 并无关联任何 Role。也就是说,此时它有访问 APIServer 的绝大多数权限。

ClusterRole & ClusterRoleBinding

须要注意的是 Role 和 RoleBinding 对象都是 Namespaced 对象,它们只对本身的 Namespace 内的资源有效。

而某个 Role 须要对于非 Namespaced 对象(好比:Node),或者想要做用于全部的 Namespace 的时候,咱们须要使用 ClusterRole 和 ClusterRoleBinding 去作受权。

这两个 API 对象的用法跟 Role 和 RoleBinding 彻底同样。只不过,它们的定义里,没有了 Namespace 字段。

值得一提的是,Kubernetes 已经内置了不少个为系统保留的 ClusterRole,它们的名字都以 system: 开头。通常来讲,这些系统级别的 ClusterRole,是绑定给 Kubernetes 系统组件对应的 ServiceAccount 使用的。

除此以外,Kubernetes 还提供了四个内置的 ClusterRole 来供用户直接使用:

cluster-admin:整个集群的最高权限。若是在 ClusterRoleBinding 中使用,意味着在这个集群中的全部 namespace 中的全部资源都拥有最高权限,随心所欲;若是在 RoleBinding 中使用,即在某个 namespace 中随心所欲。

admin:管理员权限。若是在 RoleBinding 中使用,意味着在某个 namespace 中,对大部分资源拥有读写权限,包括建立 Role 和 RoleBinding 的权限,但没有对资源 quota 和 namespace 自己的写权限。

edit:写权限。在某个 namespace 中,拥有对大部分资源的读写权限,但没有对 Role 和 RoleBinding 的读写权限。

view:读权限。在某个 namespace 中,仅拥有对大部分资源的读权限,没有对 Role 和 RoleBinding 的读权限,也没有对 seccrets 的读权限。

Aggregated ClusterRoles

在 Kubernetes v1.9 以后,ClusterRole 有一种新的定义方法,就是使用 aggregationRule 将多个 ClusterRole 合成一个新的 ClusterRole

首先看个 k8s 官网的例子:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: monitoring
aggregationRule:
 clusterRoleSelectors:
 - matchLabels:
      rbac.example.com/aggregate-to-monitoring: "true"
rules: []
复制代码

其中 rules 字段没必要定义,会被 controller manager 自动填充。

能够看出 aggregationRule 就是将全部知足 label 条件的 ClusterRole 的合成一个 ClusterRole,而这个新的 ClusterRole 权限为其余总和。

Group

相对于 User 而言,k8s 还拥有“用户组”(Group)的概念,也就是一组“用户”的意思。而对于“内置用户” ServiceAccount 来讲,“用户组”的概念也一样适用。

实际上,一个 ServiceAccount,在 Kubernetes 里对应的“用户”的名字是: system:serviceaccount:<ServiceAccount 名字 > ;而它对应的内置“用户组”的名字,就是 system:serviceaccounts:<Namespace 名字 >

对于 Group 的运用,咱们举个例子,在 RoleBinding 里这样定义 subjects:

subjects:
- kind: Group
	name: system:serviceaccounts:hdls
	apiGroup: rbac.authorization.k8s.io
复制代码

这就意味着这个 Role 的权限规则,做用于 hdls 里的全部 ServiceAccount。

而若是 Group 不指定 Namespace,即直接定义为 system:serviceaccounts,意味着做用于整个系统里的全部 ServiceAccount。

ABAC

Attribute-based access control (ABAC) 是基于属性的权限访问控制。若要开启该模式,须要在 APIServer 启动时,开启 --authorization-policy-file=<SOME_FILENAME>--authorization-mode=ABAC 两个参数。

其 policy 文件用来指定权限规则,必须知足每行都是一个 json 对象的格式。能够指定 user 或 group 为某个特定的对象,并描述其拥有的权限。

与 Yaml 文件一致,必须描述的属性有 apiVersion、kind、spec,而 spec 里描述了具体的用户、资源和行为。看个例子:

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "bob", "namespace": "projectCaribou", "resource": "pods", "readonly": true}}
复制代码

这就描述了用户 bob 只有在 namespace projectCaribou 下对 pod 的读权限。相似的,这个 User 能够是某我的,也能够是 kubelet 或者某个 ServiceAccount,这里 ServiceAccount 须要写全,好比:system:serviceaccount:kube-system:default

若是是描述某个 namespace 下的全部人,须要用到 group,好比:

{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group": "system:serviceaccounts:default", "readonly": true, "resource": "pods"}}
复制代码

Node

Node 受权机制是一种特殊的模式,是 kubelet 发起的请求受权。开启该模式,须要开启参数 --authorization-mode=Node

经过启动 --enable-admission-plugins=...,NodeRestriction,...,来限制 kubelet 访问 node,endpoint、pod、service以及secret、configmap、PV 和 PVC 等相关的资源。

Webhook

Webhook 模式是一种 HTTP 回调模式,是一种经过 HTTP POST 方式实现的简单事件通知。该模式须要 APIServer 配置参数 –authorization-webhook-config-file=<SOME_FILENAME>,HTTP 配置文件的格式跟 kubeconfig 的格式相似。

# Kubernetes API version
apiVersion: v1
# kind of the API object
kind: Config
# clusters refers to the remote service.
clusters:
 - name: name-of-remote-authz-service
 cluster:
      # CA for verifying the remote service.
 certificate-authority: /path/to/ca.pem
      # URL of remote service to query. Must use 'https'. May not include parameters.
 server: https://authz.example.com/authorize

# users refers to the API Server's webhook configuration.
users:
 - name: name-of-api-server
 user:
 client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
 client-key: /path/to/key.pem          # key matching the cert

# kubeconfig files require a context. Provide one for the API Server.
current-context: webhook
contexts:
- context:
 cluster: name-of-remote-authz-service
 user: name-of-api-server
 name: webhook
复制代码

其中,Cluster 指须要回调的地方的客户端,指定其访问证书和 URL;user 指回调处访问的身份,指明其所需证书和 key;contexts 指回调的内容。

准入控制(Admission Controllers)

在一个请求经过了认证机制和受权认证后,须要通过最后一层筛查,即准入控制。这个准入控制模块的代码一般在 APIServer 中,并被编译到二进制文件中被执行。这一层安全检查的意义在于,检查该请求是否达到系统的门槛,便是否知足系统的默认设置,并添加默认参数。

准入控制以插件的形式存在,开启的方式为: kube-apiserver --enable-admission-plugins=NamespaceLifecycle,LimitRanger ...

关闭的方式为: kube-apiserver --disable-admission-plugins=PodNodeSelector,AlwaysDeny ...

经常使用的准入控制插件有:

  • AlwaysAdmit:容许全部请求经过,被官方反对,由于没有实际意义;
  • AlwaysPullImages:将每一个 pod 的 image pull policy 改成 always,在多租户的集群被使用;
  • AlwaysDeny:禁止全部请求经过,被官方反对,由于没有实际意义;
  • DefaultStorageClass:为每一个 PersistentVolumeClaim 建立默认的 PV;
  • DefaultTolerationSeconds:若是 pod 对污点 node.kubernetes.io/not-ready:NoExecutenode.alpha.kubernetes.io/unreachable:NoExecute 没有容忍,为其建立默认的 5 分钟容忍 notready:NoExecuteunreachable:NoExecute
  • LimitRanger:确保每一个请求都没有超过其 namespace 下的 LimitRange,若是在 Deployment 中使用了 LimitRange 对象,该准入控制插件必须开启;
  • NamespaceAutoProvision:检查请求中对应的 namespace 是否存在,若不存在自动建立;
  • NamespaceExists:检查请求中对应的 namespace 是否存在,若不存在拒绝该请求;
  • NamespaceLifecycle:保证被删除的 namespace 中不会建立新的资源;
  • NodeRestriction:不容许 kubelet 修改 Node 和 Pod 对象;
  • PodNodeSelector:经过读取 namespace 的注解和全局配置,来控制某 namespace 下哪些 label 选择器可被使用;
  • PodPreset:知足预先设置的标准的 pod 不容许被建立;
  • Priority:经过 priorityClassName 来决定优先级;
  • ResourceQuota:保证 namespace 下的资源配额;
  • ServiceAccount:保证 ServiceAccount 的自动建立,若是用到 ServiceAccount,建议开启;

以上只列举了部分,详情请移步 Kubernetes 官方文档。

官方建议:

  • 版本 > v1.10:
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota
复制代码
  • v1.9
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota
复制代码
  • v1.6 - v1.8
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds
复制代码
  • v1.4 - v1.5
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota
复制代码

相关文章
相关标签/搜索