Kubernetes in Action笔记 - (14) API Server服务器的安全防护
如果攻击者获得了访问API服务器的权限, 他们可以通过在容器镜像中打包自己的代码并在pod中运行来做任何事
认证机制
API 服务器可以配置一个认证插件列表。列表中的每个插件都可以检查这个请求和尝试确定谁在发送这个请求。当通过认证后,返回用户名、用户 ID 和组信息给 API 服务器,API服务器就会停止调用剩余的认证插件井继续进入授权阶段。
用户与组
k8s 区分了两种连接到 API 服务器的客户端 :
- 用户(真实的人)
- pod (更准确地说是运行在 pod 中的应用)
用户应该被管理在外部系统中,例如单点登录系统。没有资源代表用户账户,这也就意味着不能通过 API 服务器来创建、更新或删除用户。
pod 使用一种称为 service accounts 的机制, 该机制被创建和存储在集群中作为 ServiceAccount 资源。
正常用户和 ServiceAccount 都可以属于一个或多个组。可以通过组对一批用户进行授权。
由插件返回的组仅仅是表示组名称的字符串,但是系统内置的组会有一些特殊的含义。
- system:unauthenticated 组用于所有认证插件都不会认证客户端身份的请求。
- system:authenticated 组会自动分配给一个成功通过认证的用户。
- system:serviceaccounts 组包含所有在系统中的 ServiceAccount 。
- system:serviceaccounts:
组包含了所有在特定命名空间中的ServiceAccount。
ServiceAccount
ServiceAccount介绍
ServiceAccount就像Pod、 Secret、 ConfigMap等一样都是资源, 它们作用在单独的命名空间, 为每个命名空间自动创建一个默认的ServiceAccount
可以像其他资源那样查看ServiceAccount列表:
kubectl get sa
在 pod 的 manifest 文件中, 可以用指定账户名称的方式将一个 ServiceAccount赋值给一个 pod。如果不显式地指定 ServiceAccount 的账户名称, pod 会使用在这个命名空间中的默认 ServiceAccount。
可以通过将不同的 ServiceAccount 赋值给 pod 来控制每个 pod 可以访问的资源。当 API 服务器接收到一个带有认证 token 的请求时, 服务器会用这个 token 来验证发送请求的客户端所关联的 ServiceAccount 是否允许执行请求的操作。
为了集群的安全性,根据需要,对不同的Pod赋予不一样的ServiceAccount。
创建serviceaccount
创建serviceaccount
kubectl create serviceaccount foo
查看serviceaccount
$ kubectl describe sa foo
Namespace: default
Labels: <none>
Image pull secrets: <none>
Mountable secrets: foo-token-qzq7j
Tokens: foo-token-qzq7j
查看密钥里面的数据
$ kubectl describe secret foo-token-qzq7j
...
ca.crt: 1066 bytes
namespace: 7 bytes
token: eyJhbGdOiJSUzI1NiisinRScCI6IkpXVCJ9...
在默认情况下,pod 可以挂载任何它需要的密钥。但是可以通过对 ServiceAccount 进行配置,让 pod 只允许挂载ServiceAccount 中列出的可挂载密钥。为了开启这个功能,ServiceAccount 必须包含以下注解: kubernetes.io/enforce-mountable-secrets=“true”。如果 ServiceAccount 被加上了这个注解,任何使用这个ServiceAccount的pod只能挂载进 ServiceAccount 的可挂载密钥,而不能使用其他的密钥。
ServiceAccount 也可以包含镜像拉取密钥的 list:
apiVersion: vl
kind: ServiceAccount
metadata:
name: my-service-account
imagePullSecrets:
- name: my-dockerhub-secret
ServiceAccount和可挂载密钥不同的是,ServiceAccount 中的镜像拉取密钥不是用来确定以个 pod 可以使用哪些镜像拉取密钥的。添加到 ServiceAccount 中的镜像拉取密钥会自动添加到所有使用这个 ServiceAccount 的 pod 中。
分配ServiceAccount给Pod
ServiceAccount需要将它们赋值给 pod。通过在 pod 定义文件中的 spec.serviceAccountName 字段上设置 ServiceAccount 的名称来进行分配。
注意: pod 的 ServiceAccount 必须在 pod 创建时进行设置,后续不能被修改。
通过基于角色的权限控制加强集群安全
在Kubernetes1.8.0版本中,RBAC授权插件升级为GA(通用可用性),并且在很多集群上默认开启。RBAC会阻止未授权的用户查看和修改集群状态。
注意:除了RBAC插件, k8s也包含其他的授权插件,比如基于属性的访问控制插件 (ABAC)、WebHook插件和自定义插件实现。但是,RBAC插件是标准的。
RBAC授权插件
动作
RBAC授权插件会决定一个客户端是否允许在请求的资源上执行请求的动词。下面是认证动词和HTTP方法之间的映射关系:
HTTP方法 | 单一资源的动词 | 集合的动词 |
---|---|---|
GET、HEAD | get (以及watch用于监听) | list以及watch |
POST | create | n/a |
PUT | update | n/a |
PATCH | patch | n/a |
DELETE | delete | deletecollection |
注意: 额外的动词 use 用于 PodSecurityPolicy 资源
除了可以对全部资源类型应用安全权限, RBAC 规则还可以应用于特定的资源实例(例如, 一个名为 myservice 的服务), 也可以应用于non-resource (非资源) URL路径, 因为并不是 API 服务器对外暴露的每个路径都映射到一个资源(例如 /api 路径本身或服务器健康信息在的路径 /health)。
角色与授权规则
RBAC 授权插件将用户角色作为决定用户能否执行操作的关键因素。主体可以是一个人、一个 ServiceAccount, 或者一组用户或 ServiceAccount和一个或多个角色相关联, 每个角色被允许在特定的资源上执行特定的动词。如果一个用户有多个角色, 他们可以做任何他们的角色允许他们做的事情。
RBAC 授权规则是通过四种资源来进行配置的, 它们可以分为两个组:
- Role(角色)和 ClusterRole (集群角色), 它们指定了在资源上可以执行哪些动词。
- RoleBinding (角色绑定) 和 ClusterRoleBinding (集群角色绑定), 它们将上述角色绑定到特定的用户、组或 ServiceAccounts 上。
角色和角色绑定是命名空间的资源, 而集群角色和集群角色绑定是集群级别的资源。
使用Role和RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
namespace: foo # Role所在命名空间,没有填写则使用当前命名空间
metadata: server-reader
rules:
- apiGroups: [""] # Service是核心apiGroup的资源,所以没有apiGroup名,就是""
verbs: ["get", "list"] #获取独立的service(通过名字)并且列出所有允许的服务
resources: ["services"] #这条规则与服务有关(必须使用复数的名字)
注意:在指定资源时必须使用复数的形式。
绑定角色到service account
kubectl create rolebinding te st --role=service-reader --serviceaccount=foo:default -n foo
注意: 如果要绑定一个角色到一个 user (用户)而不是 ServiceAccount 上, 使用 --user
作为参数来指定用户名。如果要绑定角色到组,可以使用 --group
参数 。
使用 ClusterRole 和 ClusterRoleBinding
一个 RoleBinding 不能授予集群级别的资源访问权限,即使它引用了一个 ClusterRoleBinding。
在授予集群级别的资源访问权限时,必须使用一个 ClusterRole和一个 ClusterRoleBinding。
ClusterRole不是必须一直和集群级别的ClusterRoleBinding捆绑使用。它们也可以和常规的有命名空间的RoleBinding进行捆绑
何时使用具体的role和binding的组合:
访问的资源 | 使用的角色类型 | 使用的绑定类型 |
---|---|---|
集群级别的资源(Nodes、 Pers1stentVolumes、…) | ClusterRole | ClusterRoleBinding |
非资源型URL(/api、/healthz、…) | ClusterRole | ClusterRoleBinding |
在任何命名空间中的资源(和跨所有命名空间的资源) | ClusterRole | ClusterRoleBinding |
在具体命名空间中的资源(在多个命名空间中重用这个相同的ClusterRole) | ClusterRole | RoleBinding |
在具体命名空间中的资源(Role必须在每个命名空间中定义好) | Role | RoleBinding |
默认的 ClusterRole 和 ClusterRoleBinding
k8s 提供了一 组默认的ClusterRole和ClusterRoleBinding, 每次API服务器启动时都会更新它们。 这保证了在你错误地删除角色和绑定, 或者Kubernetes的新版本使用了不同的集群角色和绑定配置时, 所有的默认角色和绑定都会被重新创建。
可以执行下面的命令查看:
kubectl get clusterrolebindings
kubectl get clusterroles
view、edit、admin和 cluster-admin 这些ClusterRole是最重要的角色, 它们应该绑定到用户定义pod中的ServiceAccount上
默认的ClusterRole列表包含了大量其他的ClusterRole, 它们以system:
为前缀。这些角色用于各种k8s组件中
理性地授予授权权限
在默认情况下, 命名空间中的默认ServiceAccount除了包含未经身份验证的用户之外,没有其他任何权限。因此,在默认情况下, pod甚至不能查看集群状态。
目标是减少入侵者获得集群控制的可能性。
一个好的想法是,为每一个pod(或一组pod的副本)创建一个特定ServiceAccount, 并且把它和一个定制的Role (或ClusterRole)通过RoleBinding联系起来(不是ClusterRoleBinding, 因为这样做会给其他命名空间的pod对资源的访 问权限,这可能不是想要的)。
图书资料: