命令记不住

登陆

k8s 的访问控制和 RBAC 授权

17.Kubernetes访问控制

1.请求流程

,请求的发起分为两个部分:

  • 第一个部分是人机交互的过程。 是大家非常熟悉的用 kubectl 对 api-server 的一个请求过程;
  • 第二个部分是 Pod 中的业务逻辑与 api-server 之间的交互。

Api-server 收到请求后,就会开启访问控制流程。这里面分为三个步骤:

  • Authentication 认证阶段:判断请求用户是否为能够访问集群的合法用户。如果用户是个非法用户,那 api-server 会返回一个 401 的状态码,并终止该请求;
  • 如果用户合法的话,我们的 api-server 会进入到访问控制的第二阶段 Authorization:鉴权阶段。在该阶段中 api-server 会判断用户是否有权限进行请求中的操作。如果无权进行操作,api-server 会返回 403 的状态码,并同样终止该请求;
  • 如果用户有权进行该操作的话,访问控制会进入到第三个阶段:AdmissionControl。在该阶段中 api-server 的 Admission Control 会判断请求是否是一个安全合规的请求。如果最终验证通过的话,访问控制流程才会结束。

此时我们的请求将会转换为一个 Kubernetes objects 相应的变更请求,最终持久化到 ETCD 中。

2.认证方式

Kubernetes 没有自身的用户管理能力,我们无法像操作 Pod 一样,通过 API 的方式创建删除一个用户实例。同时我们也无法在 ETCD 中找到用户对应的存储对象。

  • Basic 认证

该认证方式下,管理员会将 Username 和 Password 组成的白名单放置在 api-server 读取的静态配置文件上面进行认证,该方式一般用于测试场景,在安全方面是不推荐且不可拓展的一种方式。

  • X509 证书认证

该方式是 api-server 中相对应用较多的使用方式,首先访问者会使用由集群 CA 签发的,或是添加在 api-server Client CA 中授信 CA 签发的客户端证书去访问 api-server。api-server 服务端在接收到请求后,会进行 TLS 的握手流程。除了验证证书的合法性,api-server 还会校验客户端证书的请求源地址等信息。开启双向认证,X509 认证是一个比较安全的方式,也是 Kubernetes 组件之间默认使用的认证方式,同时也是 kubectl 客户端对应的 kube-config 中经常使用到的访问凭证。

  • Bearer Tokens(JSON Web Tokens)
    • Service Account
  • OpenID Connect
  • Webhooks

该方式的 Tokens 是通用的 JWT 的形式,其中包含了签发者、用户的身份、过期时间等多种元信息。它的认证方式也是常见的私钥加签,公钥验签的一个基本流程。基于 Token 的认证使用场景也很广泛,比如 Kubernetes Pod 应用中经常使用到的 Service Account,其中就会自动绑定一个签名后的 JWT Token 用于请求 api-server。

另外 api-server 还支持基于 OpenID 协议的 Token 认证,可以通过对 api-server 的配置连接一个指定的外部 IDP,同时可以通过 Keycloak,Dex 这样的开源服务来管理 IDP,请求者可以按照自己熟悉的方式在原身份认证服务上进行登录认证,并最终返回一个相应的 JWT token,为了后面的 api-server 的鉴权流程。

除此之外,还可以使用 Webhooks 的方式,将请求的 Token 发送到指定外部服务进行 Token 的验签。

3.安全框架

k8s安全框架主要由3个阶段进行控制,每一个阶段都支持插件方式,通过APi Server配置来启用插件

  • Authentication(鉴全)
  • Authorization(授权)
  • Admission Control(准入控制)

Apiserver提供三种客户端身份认证

  • HTTPS证书认证:基于CA证书签名的数据证书认证(kubuconfig)
  • HTTP Token认证:通过一个Token来识别用户(serviceaccount)
  • HTTP Base认证:用户名+密码认证方式,已弃用

4.准入控制

Admission Control准入控制

实现让用户自己定义准入规则插件,k8s自身也是模块化设计。

Adminssion Control实际上是一个准入控制器插件列表,发送到API Server的请求都需要经过这个列表的每个准入控制器插件的检查,检查不通过,则拒绝请求

启用一个准入控制器:

kube-apiserver --enable-admission-pluguns=NamespaceLifecycle,LimitRanger

关闭一个准入控制器

kube-apiserver --disable-admission-plugins=PodNodeSelector,AlwaysDeny

查看默认启用

kubectl exec kube-apiserver-k8s-master -n kube-system  --kube-apiserver -h |  grep enable-admission-plugins

.

5.RBAC授权

RBAC(Role-Based Access Control 基于角色的访问控制):负责完成授权工作

RBAC根据API请求属性,决定允许还是拒绝。

比较常见的授权维度:

  • user
  • group
  • 资源,pod,deployment
  • 资源的操作,get,list,create,update
  • 命名空间
  • API组
基于角色的权限访问控制RBAC

RBAC是k8s默认授权策略,并且是动态配置策略

  • 主体

    • User
    • Group
    • ServiceAccount:服务帐号
  • 角色

    • Role:授权特定命名空间的访问权限
    • ClusterRole:授权所有命名空间的访问权限
  • 角色绑定

    • RoleBinding:将角色绑定到主体
    • ClusterRoleBinding:将集群角色绑定到主体

6.RBAC基于用户实验

需求:授权访问default命名空间Pod读取权限

实施步骤:

  • 用k8s CA签发客户端证书
  • 生成kubeconfig授权文件
  • 创建RBAC权限策略
  • 指定kubeconfig文件测试权限
kubectl get pods --kubeconfig=./config/user.kubeconfig
1.签发客户端证书

使用cfssl工具生成客户端CA证书(链接:https://pan.baidu.com/s/12LXQBPFWAM9giYGeI679UA 提取码:CBMM)

#ls
cert.sh  kubeconfig.sh  rbac.yaml
#bash cert.sh 
#ll
total 32
-rw-r--r-- 1 root root  997 Nov 28 18:18 aliang.csr
-rw-r--r-- 1 root root  219 Nov 28 18:18 aliang-csr.json
-rw------- 1 root root 1679 Nov 28 18:18 aliang-key.pem
-rw-r--r-- 1 root root 1277 Nov 28 18:18 aliang.pem
-rw-r--r-- 1 root root  292 Nov 28 18:18 ca-config.json
-rw-r--r-- 1 root root  741 Sep  1  2019 cert.sh
-rw-r--r-- 1 root root  622 Sep  1  2019 kubeconfig.sh
-rw-r--r-- 1 root root  477 Aug 25  2019 rbac.yaml
2.生成授权文件

生成kubeconfig授权文件,embed-certs=true使用base64编码写入文件中

# 设置集群
kubectl config set-cluster kubernetes \ # 集群的名字kubernetes
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=https://192.168.31.61:6443 \
--kubeconfig=aliang.kubeconfig
# 设置客户端认证
kubectl config set-credentials aliang \ #客户端名字aliang
--client-key=aliang-key.pem \
--client-certificate=aliang.pem \
--embed-certs=true \
--kubeconfig=aliang.kubeconfig
# 设置默认上下文 (可以配置一个证书使用多个集群)
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=aliang \
--kubeconfig=aliang.kubeconfig
# 设置当前使用配置
kubectl config use-context kubernetes --kubeconfig=aliang.kubeconfig

查看生成的kubeconfig

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBtCg==
    server: https://192.168.122.71:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: aliang
  name: kubernetes
current-context: kubernetes
kind: Config
preferences: {}
users:
- name: aliang
  user:
    client-certificate-data: LS0tLBVEUtLS0tLQo=
    client-key-data: LS0tLS1CRUdJTiBSU
3.创建RBAC权限策略

创建角色(权限集合):

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # api组,例如apps组,空值表示是核心API组,像namespace、pod、service、pv、pvc都在里面
  resources: ["pods","pods/log"] #资源名称(复数),例如pods、deployments、services
  verbs: ["get", "watch", "list"] # 资源操作方法

查看api组的方式- apiGroups: [“”]

# kubectl api-resources  |  grep apps
controllerrevisions                            apps/v1                                true         ControllerRevision
daemonsets                        ds           apps/v1                                true         DaemonSet
deployments                       deploy       apps/v1                                true         Deployment
replicasets                       rs           apps/v1                                true         ReplicaSet
statefulsets                      sts          apps/v1                                true         StatefulSet
# kubectl api-resources  |  grep networking
ingressclasses                                 networking.k8s.io/v1                   false        IngressClass
ingresses                         ing          networking.k8s.io/v1                   true         Ingress
networkpolicies                   netpol       networking.k8s.io/v1                   true         NetworkPolicy

将用户与角色绑定:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User # 主体
  name: aliang # 主体名称
  apiGroup: rbac.authorization.k8s.io
roleRef: # 绑定的角色
  kind: Role
  name: pod-reader # 角色名称
  apiGroup: rbac.authorization.k8s.io

查看当前权限

#kubectl get node --kubeconfig=./aliang.kubeconfig
Error from server (Forbidden): nodes is forbidden: User "aliang" cannot list resource "nodes" in API group "" at the cluster scope

#kubectl get pods --kubeconfig=./aliang.kubeconfig
NAME                          READY   STATUS    RESTARTS   AGE
configmap-demo-pod1           1/1     Running   0          4h2m
fluentd-elasticsearch-7vgqn   1/1     Running   0          7h12m
fluentd-elasticsearch-g6dqw   1/1     Running   0          7h11m
web6-0                        1/1     Running   0          7h12m
web6-1                        1/1     Running   0          7h11m
web6-2                        1/1     Running   0          7h11m

4.增加授权访问

修改rbac.yaml文件

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: ["","apps"] # api组,例如apps组,空值表示是核心API组,像namespace、pod、service、pv、pvc都在里面
  resources: ["pods","pods/log","services","deployment"] #资源名称(复数),例如pods、deployments、services
  verbs: ["get", "watch", "list"] # 资源操作方法

验证权限

#kubectl get pods,svc,deploy --kubeconfig=./aliang.kubeconfig
NAME                              READY   STATUS              RESTARTS   AGE
pod/configmap-demo-pod1           1/1     Running             0          4h11m
pod/fluentd-elasticsearch-7vgqn   1/1     Running             0          7h21m
pod/fluentd-elasticsearch-g6dqw   1/1     Running             0          7h21m
pod/rbc-788cd8c47f-2q6vf          0/1     ContainerCreating   0          3s
pod/web6-0                        1/1     Running             0          7h21m
pod/web6-1                        1/1     Running             0          7h20m
pod/web6-2                        1/1     Running             0          7h20m

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        21d
service/web          ClusterIP   None             <none>        80/TCP         8h
service/web-01       NodePort    10.108.173.136   <none>        80:30897/TCP   14d
service/web-02       NodePort    10.108.216.246   <none>        80:32006/TCP   14d

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/rbc   0/1     1            0           3s

.

7.RBAC基于角色实验

为一个服务分配只能创建deployment,daemonset,statefulset的权限

命令行创建
# 创建集群角色
kubectl create clusterrole deployment-clusterrole \
--verb=create --resource=deployments,daemonsets,statefulsets
# 创建服务账号
kubectl create serviceaccount cicd-token -n app-team1
# 将服务账号绑定角色
kubectl create rolebinding cicd-token \
--serviceaccount=app-team1:cicd-token \
--clusterrole=deployment-clusterrole -n app-team1
# 测试服务账号权限
kubectl --as=system:serviceaccount:app-team1:cicd-token get pods -n app-team1
yaml创建
apiVersion: v1
kind: ServiceAccount
metadata:
name: cicd-token
namespace: app-team1
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deployment-clusterrole
rules:
- apiGroups: ["apps"]
resources: ["deployments","daemonsets","statefulsets"] 
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding # 角色绑定
metadata:
name: cicd-token
namespace: app-team1
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: deployment-clusterrole
subjects:
- kind: ServiceAccount
name: cicd-token # 服务帐号
namespace: app-team1

.

8.查看授权信息

[root@cka-master ] cka-master 
#kubectl get role
NAME                                    CREATED AT
leader-locking-nfs-client-provisioner   2021-11-27T16:17:11Z
pod-reader                              2021-11-28T10:58:22Z

[root@cka-master ] cka-master 
#kubectl describe role pod-reader
Name:         pod-reader
Labels:       <none>
Annotations:  <none>
PolicyRule:
Resources         Non-Resource URLs  Resource Names  Verbs
---------         -----------------  --------------  -----
deployments       []                 []              [get watch list]
pods/log          []                 []              [get watch list]
pods              []                 []              [get watch list]
services          []                 []              [get watch list]
deployments.apps  []                 []              [get watch list]
pods.apps/log     []                 []              [get watch list]
pods.apps         []                 []              [get watch list]
services.apps     []                 []              [get watch list]

.

推荐阅读