【DevOps基础篇之k8s】如何应用Kubernetes中的Role Based Access Control(RBAC)
@TOC
推荐超级课程:
背景
访问控制过程和技术使您能够控制应用程序和用户是否被允许或被拒绝访问或权限。 访问控制是Kubernetes安全的基础。Kubernetes提供了两种主要的访问控制选项,基于角色的访问控制(RBAC)和基于属性的访问控制(ABAC)。
在本文中,我将讨论RBAC。
Kubernetes身份验证和授权
假设您使用kubectl apply
命令部署一个pod。
当您输入kubectl apply
时,会发生一些事情,
1)从您的KUBECONFIG读取配置,
2)从API中发现API和对象,
3)在客户端验证资源(是否有任何明显的错误?),
4)将携带有效载荷的请求发送到kube-apiserver。
当kube-apiserver接收到请求时,它不会立即将其存储在etcd中。 首先,它必须验证请求者的合法性。换句话说,它必须对请求进行身份验证。 仅仅因为您可以访问集群并不意味着您可以创建或读取所有资源。 因此,一旦经过身份验证,它会检查请求者是否具有创建资源的权限。 换句话说,检查请求授权。授权通常使用基于角色的访问控制(RBAC)完成。
下面的图表显示了API服务器处理这些身份验证和授权请求的流程。
基于角色的访问控制(RBAC)
如果您在您的组织中有一个小团队和小型集群设置(例如仅包含几个节点),您可能还没有一种系统化的方式处理授权。也许您甚至授予团队中的每个人集群管理员权限,以简化管理。 但并非每个用户都需要无限制地创建、修改和删除资源的能力。 随着集群节点、应用程序和团队成员数量的增加,您将希望限制团队成员和应用程序可以访问的资源,以及他们可以执行的操作。
Kubernetes中的RBAC框架允许您做到这一点。 例如,它可以帮助确保开发人员只能将某些应用程序部署到给定的命名空间,或者确保您的基础设施管理团队具有用于监控任务的只读访问权限。 基本上,RBAC通过使用附加到用户身上的角色来定义限制和控制用户对系统资源的访问的策略。
用户账户 vs. 服务账户
在Kubernetes中,RBAC权限/策略可用于定义人类用户(或人类用户组)的访问权限。Kubernetes将人类用户标识为用户账户。但是,RBAC策略也可以管理软件资源的行为,Kubernetes将其标识为服务账户。服务账户为在pod中运行的进程提供了身份。服务账户不是用户账户。 用户账户由管理员和开发人员等使用,用于访问集群并进行一些开发工作或维护。 服务账户用于应用程序和进程在与ApiServer交谈时进行身份验证。并且这些服务账户可以通过Kubernetes RBAC受限制。 这使您可以对过程/应用程序进行身份验证和限制访问以及该过程/应用程序可以做些什么。
每个命名空间都有一个默认的服务账户。 并且如果创建时没有指定服务账户,则创建的每个pod都会分配默认的服务账户(并在其中安装令牌作为Secrets),尽管它的权限非常有限。 因此,如果想要为应用程序授予更多权限,或者想要自定义控制,您应该为您的应用程序或进程创建一个服务账户。
角色 vs. 集群角色
RBAC授权可以定义限制在命名空间内或整个集群内的权限/策略。 为此,您可以定义一组权限,称为角色,它在给定命名空间内定义。 如果想要在整个集群中定义角色,则称之为集群角色。 基本上,集群角色和角色分别定义用户在集群或命名空间内可以执行的操作。 Kubernetes允许您配置自定义角色或使用默认用户界面角色(例如集群管理员、管理员、编辑、查看)。
RoleBinding vs. ClusterRoleBinding
您可以将角色和集群角色分配给Kubernetes主体(例如用户、用户组或服务账户)。 角色可以通过RoleBindings分配给主体(例如用户、用户组或服务账户),集群角色可以通过ClusterRoleBindings分配给主体(例如用户、用户组或服务账户)。 在本文中,我将讨论使用RoleBindings和ClusterRoleBindings为服务账户分配角色和集群角色,处理Kubernetes RBAC策略。 有两种主要的权限处理类型, 1)在命名空间范围内处理RBAC策略, 2)在集群范围内处理RBAC策略。
1. 命名空间范围内的RBAC策略
首先,我测试了命名空间范围内的RBAC策略功能,通过Role和RoleBinding将服务账户权限分配给命名空间。 为此,我创建了命名空间、服务账户,使用Role定义了命名空间策略,并通过RoleBinding将这些策略分配给服务账户。
1.1. 创建命名空间 首先,我检查了Kubernetes集群中的RBAC功能是否启用。然后创建了一个名为rahasak的命名空间。
# verify k8s rbac installed
❯❯ kubectl api-versions | grep rbac
rbac.authorization.k8s.io/v1
---
# create namespace
kubectl create namespace rahasak
❯❯ kubectl get ns
NAME STATUS AGE
default Active 20h
kube-node-lease Active 20h
kube-public Active 20h
kube-system Active 20h
rahasak Active 20h
1.2. 创建服务账户 以下是创建服务账户的方式。我将此服务账户分配到先前创建的rahasak命名空间中。
apiVersion: v1
kind: ServiceAccount
metadata:
name: rahasak-serviceaccount
namespace: rahasak
# create service account
kubectl apply -f rahasak-service-account.yaml
# view service accounts
# service account created in rahasak namespace
❯❯ kubectl get serviceaccounts -n rahasak
NAME SECRETS AGE
default 1 20h
rahasak-serviceaccount 1 10s
服务账户具有一个令牌。我刚刚创建的一个命名为rahasak-serviceaccount-token-vntdr
。
此令牌存储为KubernetesSecrets,可以作为Secrets读取。这个令牌是您用来将第三方应用程序身份验证到Kubernetes ApiServer的令牌。
# view service account token
❯❯ kubectl describe serviceaccount rahasak-serviceaccount -n rahasak
Name: rahasak-serviceaccount
Namespace: rahasak
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: rahasak-serviceaccount-token-vntdr
Tokens: rahasak-serviceaccount-token-vntdr
Events: <none>
# token is stored as a secret, so it can be viewed with token name
❯❯ kubectl describe secret rahasak-serviceaccount-token-vntdr -n rahasak
Name: rahasak-serviceaccount-token-vntdr
Namespace: rahasak
Labels: <none>
Annotations: kubernetes.io/service-account.name: rahasak-serviceaccount
kubernetes.io/service-account.uid: 237ec5f9-0050-402a-a553-72f26c39a11c
Type: kubernetes.io/service-account-token
Data
====
token: xxxxxxxxxx-xxx_mxxx6j_xxxxx
ca.crt: 1111 bytes
namespace: 7 bytes
1.3. 创建角色
以下是创建具有不同权限的角色的方法。此角色定义可以在rahasak命名空间中执行的操作(get
, watch
, list
)只能作用于资源pod。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: rahasak
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
1.4. 创建RoleBinding 可以通过RoleBinding将此角色分配给服务账户。因此,服务账户只能在rahasak命名空间中列出、获取、观察pod。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: rahasak
roleRef: # points to the Role
apiGroup: rbac.authorization.k8s.io
kind: Role
name: pod-reader # name of Role
subjects: # points to the ServiceAccount
- kind: ServiceAccount
name: rahasak-serviceaccount # service account to bind to
namespace: rahasak # ns of service account
# create role
kubectl apply -f rahasak-role.yaml
# list roles in rahasak namespace
❯❯ kubectl get roles -n rahasak
NAME CREATED AT
pod-reader 2022-06-17T01:00:35Z
# describe role permissions
❯❯ kubectl describe role pod-reader -n rahasak
Name: pod-reader
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get watch list]
1.5. 测试权限
为了测试分配给服务账户的权限,我使用了一个内含kubectl命令的自定义pod。
这个pod是可用的bibinwilson/docker-kubectl
Docker镜像。
我使用这个Docker镜像创建了一个pod,并分配了rahasak-serviceaccount给它。
因此,该pod应该只允许执行角色中指定的权限(例如在rahasak命名空间中列出、获取、观察pod)。
我已部署了这个pod,通过kubectl exec连接到pod并检查它是否具有我们在角色中提到的权限。
apiVersion: v1
kind: Pod
metadata:
name: rahasak-kubectl
namespace: rahasak
spec:
containers:
- image: bibinwilson/docker-kubectl:latest
name: kubectl
serviceAccountName: rahasak-serviceaccount
# deploy pod with kubectl
kubectl apply -f rahasak-kubectl.yaml
# list pods
❯❯ kubectl get pods -n rahasak
NAME READY STATUS RESTARTS AGE
rahasak-kubectl 1/1 Running 0 4s
# connect to kubectl pod
kubectl exec -it --namespace=rahasak rahasak-kubectl -- /bin/bash
# check list pod permission in rahasak
# permission should be there
root@debug-kubectl:/# kubectl get pods -n rahasak
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 10 (28m ago) 20h
debug-kubectl 1/1 Running 0 97s
nginx 1/1 Running 0 21h
# check list pod permission in bassa
# give forbidden error
root@debug-kubectl:/# kubectl get pods -n bassa
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:rahasak:rahasak-serviceaccount" cannot list resource "pods" in API group "" in the namespace "bassa"
# check list services permission
# give forbidden error
kubectl get svc
Error from server (Forbidden): services is forbidden: User "system:serviceaccount:rahasak:rahasak-serviceaccount" cannot list resource "services" in API group "" in the namespace "rahasak"
2. 集群范围内的RBAC策略
其次,我测试了分配集群范围服务账户权限的集群范围RBAC策略,通过ClusterRole和ClusterRoleBinding定义集群策略,并通过ClusterRoleBinding将这些策略分配给服务账户。 为此,我创建了命名空间、服务账户,使用ClusterRole定义了集群策略,并通过ClusterRoleBinding将这些策略分配给服务账户。
2.1. 创建命名空间 我为这种情景创建了一个名为bassa的不同的命名空间(之前创建的命名空间,rahasak)。
# create namespace
kubectl create namespace bassa
❯❯ kubectl get ns
NAME STATUS AGE
bassa Active 5s
default Active 21h
kube-node-lease Active 21h
kube-public Active 21h
kube-system Active 21h
rahasak Active 21h
2.2. 创建服务账户 以下是创建服务账户的方式。我将此服务账户分配到bassa命名空间中。
apiVersion: v1
kind: ServiceAccount
metadata:
name: bassa-serviceaccount
namespace: bassa
# create service account
kubectl apply -f bassa-service-account.yaml
# view service accounts
# service account created in bassa namespace
❯❯ kubectl get serviceaccounts -n bassa
NAME SECRETS AGE
bassa-serviceaccount 1 6s
default 1 2m49s
2.3. 创建ClusterRole 以下是创建具有不同权限的ClusterRole的方法。此角色定义可以在整个集群中对资源pod执行的操作(获取、观察、列出)。由于ClusterRoles不具有命名空间,所以ClusterRole的命名空间被省略。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# "namespace" omitted since ClusterRoles are not namespaced
# namespace: bassa
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
# create cluster role
kubectl apply -f bassa-cluster-role.yaml
# list cluster roles
❯❯ kubectl get clusterroles | grep pod-reader
NAME CREATED AT
pod-reader 2022-06-17T02:01:43Z
# describe cluster role permissions
❯❯ kubectl describe clusterrole pod-reader
Name: pod-reader
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
pods [] [] [get watch list]
2.4. 创建ClusterRoleBinding 可以通过ClusterRoleBinding将此ClusterRole分配给服务账户。因此,服务账户可以在集群中的所有命名空间中列出、获取、观察pod。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: pod-reader-binding
namespace: bassa
roleRef: # points to the ClusterRole
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: pod-reader # name of ClusterRole
subjects: # points to the ServiceAccount
- kind: ServiceAccount
name: bassa-serviceaccount # service account to bind to
namespace: bassa # ns of service account
Test:
# create cluster role binding
kubectl apply -f bassa-cluster-role-binding.yaml
# list cluster role binding
kubectl get clusterrolebindings.rbac.authorization.k8s.io | grep pod-reader
NAME ROLE AGE
pod-reader-binding ClusterRole/pod-reader 35s
# describe clusetr role binding
❯❯ kubectl describe clusterrolebindings pod-reader-binding
Name: pod-reader-binding
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: pod-reader
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount bassa-serviceaccount bassa
2.5. 测试权限 与以前的情景类似,为了测试分配给服务账户的权限,我使用了一个内含kubectl命令的自定义pod。这个pod是可用的bibinwilson/docker-kubectl Docker镜像。我使用这个Docker镜像创建了一个pod,并将bassa-serviceaccount分配给它。因此,该pod应该只允许执行ClusterRole中指定的权限(例如在集群中的所有命名空间中列出、获取、观察pod)。我已部署了这个pod,通过kubectl exec连接到pod并检查它是否具有我们在ClusterRole中提到的权限。
apiVersion: v1
kind: Pod
metadata:
name: bassa-kubectl
namespace: bassa
spec:
containers:
- image: bibinwilson/docker-kubectl:latest
name: kubectl
serviceAccountName: bassa-serviceaccount
Test:
# deploy pod with kubectl
kubectl apply -f bassa-kubectl.yaml
# list pods
❯❯ kubectl get pods -n bassa
NAME READY STATUS RESTARTS AGE
bassa-kubectl 1/1 Running 0 14s
# connect to kubectl pod
kubectl exec -it --namespace=bassa bassa-kubectl -- /bin/bash
# check list pod permission in bassa namespace
# permission should be there
root@bassa-kubectl:/# kubectl get pods -n bassa
NAME READY STATUS RESTARTS AGE
bassa-kubectl 1/1 Running 0 57s
# check list pod permission in rahasak namespace
# permission should be there
root@bassa-kubectl:/# kubectl get pods -n rahasak
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 11 (7m47s ago) 21h
debug-kubectl 1/1 Running 0 40m
nginx 1/1 Running 0 21h
# check list services permission
# give forbidden error
kubectl get svc
Error from server (Forbidden): services is forbidden: User "system:serviceaccount:rahasak:rahasak-serviceaccount" cannot list resource "services" in API group "" in the namespace "rahasak"