vlambda博客
学习文章列表

【云原生渗透】- k8s的安全机制

1. 认证阶段2. 鉴权阶段3. RBAC、角色、账号、命名空间参考链接

访问k8s集群的时候,需要经过三个安全步骤完成具体操作。过程中都要经过apiserver,apiserver做统一协调

第一步 认证,判断用户是否为能够访问集群的合法用户。

第二步 鉴权,通过鉴权策略决定一个API调用是否合法。

第三步 准入控制,就算通过了上面两步,客户端的调用请求还需要通过准入控制的层层考验,才能获得成功的响应。大致意思就是到了这步还有一个类似acl的列表,如果列表有请求内容,就通过,否则不通。它以插件的形式运行在API Server进程中,会在鉴权阶段之后,对象被持久化etcd之前,拦截API Server的请求,对请求的资源对象执行自定义(校验、修改、拒绝等)操作。

这里学习认证和鉴权的安全机制。

1. 认证阶段

认证策略大概有4种:

匿名认证:(Anonymous requests)

匿名认证一般默认是关闭的。

白名单认证:(BasicAuth认证)

白名单认证一般是服务启动时加载的basic用户配置文件,并且通常没有更多设置的话basic认证仅仅只能访问但是没有操作权限。

Token认证:(Webhooks、ServiceAccount Tokens、OpenID Connect Tokens等)

token认证更涉及到对集群和pod的操作,这是我们比较关注的。

X509证书认证:(clientCA认证,TLS bootstrapping等)

X509证书认证是kubernetes组件间内部默认使用的认证方式,同时也是kubectl客户端对应的kube-config中经常使用到的访问凭证,是一种比较安全的认证方式。

2. 鉴权阶段

当API Server内部通过用户认证后,就会执行用户鉴权流程,即通过鉴权策略决定一个API调用是否合法,API Server目前支持以下鉴权策略:

Always:当集群不需要鉴权时选择AlwaysAllow

ABAC:基于属性的访问控制

RBAC:基于角色的访问控制

RBAC是目前k8s中最主要的鉴权方式。

Node:一种对kubelet进行授权的特殊模式

Node鉴权策略主要是用于对kubelet发出的请求进行访问控制,限制每个Node只访问它自身运行的Pod及相关Service、Endpoints等信息。

Webhook:通过调用外部REST服务对用户鉴权

可自行编写鉴权逻辑并通过Webhook方式注册为kubernetes的授权服务,以实现更加复杂的授权规则。

3. RBAC、角色、账号、命名空间

RBAC,基于角色的访问控制(Role-Based Access Control)

在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

在k8s中,只有对角色的权限控制,访问主体都必须通过角色绑定,绑定成k8s集群中对应的角色,然后根据绑定的角色去访问资源。而每种角色又只能访问它所对应的命名空间中的资源。

命名空间

k8s支持多个虚拟集群,它们底层依赖于同一个物理集群。这些虚拟集群被称为命名空间(namespace)。

# 查看命名空间
kubectl get ns

【云原生渗透】- k8s的安全机制

系统默认4个命名空间,分别是:

default:没有指明使用其它命名空间的对象所使用的默认命名空间

kube-system:Kubernetes 系统创建对象所使用的命名空间

kube-public:此命名空间下的资源可被所有人访问(包括未授权用户)

kube-node-lease:集群之间的心跳维护

重点关注defaultkube-system两个命名空间。

角色分配

RBAC中一直强调角色,这里角色也分为两种,一种是普通角色role,一种是集群角色clusterrole

普通角色role用于平常分配给运行的容器,而集群角色更多承担管理工作。

查看普通角色,没有特别指明的话查看都是在default空间中。

指定kube-system空间,可以看到很多系统自带的角色。

kubectl get role -n kube-system

【云原生渗透】- k8s的安全机制

集群角色在default和kube-system中都是一样的。

kubectl get clusterrole

【云原生渗透】- k8s的安全机制

集群中有个最高权限角色cluster-admin,它的拥有集群所有资源的所有权限。因此如果访问主体绑定到该角色的话,就会引发很大的安全问题,后续说到的未授权访问就是基于此种情形。

普通的admin权限也比较大,但是比起cluster-admin还是差了太多。

角色权限授予用户:

# 创建一个clusterrolebinding,名称为cluster-admin
# --clusterrole=cluster-admin 角色
# --user=user1 授权给user1用户
# --group=group1 授权给group1组

kubectl create clusterrolebinding cluster-admin --clusterrole=cluster-admin --user=user1 --user=user2 --group=group1

服务账号 service account

访问主体中除了常用的用户,组以外,还有一类叫做服务账号,service account。service account是k8s为pod内部的进程访问apiserver创建的一种用户。因为是pod里面的,所以也会对应各自的命名空间。

在k8s中设计了一种资源对象叫做Secret,分为两类,其中一类是容器运行时配置的敏感信息(如密码等),另一类就是用于记录ServiceAccount的service-account-token

看看kube-system中的secret存储的serviceaccount信息。

可以看到很多serviceaccount name,每个name下都有3个标识,分别是Tokenca.crtnamespace

token是使用API Server私钥签名的JWT。用于访问API Server时,Server端认证。

ca.crt,根证书。用于Client端验证API Server发送的证书。

namespace, 标识这个service-account-token的作用域名空间,这里的namespace就是kube-system。

举个例子:

账号名在-token前,就叫default。

给这个服务账号绑定cluster-admin这个角色:

kubectl create clusterrolebinding default-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default

# namespace:账号名

我们把这个账号赋予新角色名default-admin,成功绑定到集群角色cluster-admin了,这就意味着我们的default这个serviceaccount拥有了集群最高权限,自然以它建立的pod也是集群最高权限的pod。

参考链接