3-13-2-用户认证案例

熊 0 阅读 容器

1. 用户认证案例

示例创建一个用户只能管理名为devops的Namespace

1.1. 创建系统用户

  1. 用管理员创建一个测试用户devops

    [root@k8s-master ~]# useradd devops
    [root@k8s-master ~]# su - devops
  2. 用devops用户测试访问k8s集群

    [devops@k8s-master ~]$ kubectl get pods 
    The connection to the server localhost:8080 was refused - did you specify the right host or port?

默认肯定是访问不到的,如果想要访问,必须要创建devops用户的访问证书

1.2. 为devops用户创建访问证书

这里使用openssl生成证书文件,有可以通过cfssl工具生成。工具地址

  1. 生成秘钥文件,权限设置600。

    [devops@k8s-master ~]$ mkdir certs
    [devops@k8s-master ~]$ (umask 077; openssl genrsa -out ./certs/devops.key 2048)
  2. 创建证书签署请求,-subj选项中CN的值将被API Server识别为用户名,O的值将被识别为用户组。

    [devops@k8s-master ~]$ openssl req -new -key ./certs/devops.key -out ./certs/devops.csr -subj "/CN=devops/O=devops"
  3. 基于kubernetes-ca签署证书,这一步需要切换为管理员,因为普通用户没有权限。

    [root@k8s-master ~]# openssl x509 -req -days 365 -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -in /home/devops/certs/devops.csr -out /home/devops/certs/devops.crt 
    Signature ok
    subject=/CN=devops/O=devops
    Getting CA Private Key
    ​
    [root@k8s-master ~]# ls /home/devops/certs/
    devops.crt  devops.csr  devops.key

1.3. 为devops用户生成配置文件

  1. 设置api server的环境变量

    [root@k8s-master ~]# export KUBE_APISERVER="https://192.168.102.101:6443"
  2. 创建kubeconfig配置文件

    [root@k8s-master ~]# kubectl config set-cluster kubernetes --server=${KUBE_APISERVER} --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --kubeconfig=devops.kubeconfig
    Cluster "kubernetes" set.
    ​
    [root@k8s-master ~]# ls devops.kubeconfig 
    devops.kubeconfig
  3. 根据常见证书时所使用的用户,来创建身份凭证

    [root@k8s-master ~]# kubectl config set-credentials devops --client-certificate=/home/devops/certs/devops.crt --client-key=/home/devops/certs/devops.key --embed-certs=true --kubeconfig=./devops.kubeconfig 
    User "devops" set.
  4. 设置上下文

    [root@k8s-master ~]# kubectl config set-context 'devops@kubernetes' --user=devops --cluster=kubernetes --namespace=devops --kubeconfig=./devops.kubeconfig 
    Context "devops@kubernetes" created.

1.4. 创建role

  1. 编写资源清单文件devops-role.yaml

    ---
    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      namespace: devops
      name: devops-rbac
    rules:
    - apiGroups: [""]  # ""表示核心API群组
      resources: ["*"] # "*"表示所有资源
      verbs: ["*"]     # "*"表示所有权限
  2. 创建

    [root@k8s-master ~]# kubectl apply -f devops-role.yaml 
    role.rbac.authorization.k8s.io/devops-rbac created
    
    [root@k8s-master ~]# kubectl describe role devops-rbac -n devops
    Name:         devops-rbac
    Labels:       <none>
    Annotations:  <none>
    PolicyRule:
      Resources  Non-Resource URLs  Resource Names  Verbs
      ---------  -----------------  --------------  -----
      *          []                 []              [*]

1.5. 进行RoleBinding验证权限

  1. 编写RoleBinding资源清单文件devops-rolebinding.yaml。

    ---
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: devops-rolebinding
      namespace: devops
    subjects:
    - kind: User
      name: devops
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role
      name: devops-rbac
      apiGroup: rbac.authorization.k8s.io
  2. 进行绑定

    [root@k8s-master ~]# kubectl apply -f devops-rolebinding.yaml 
    rolebinding.rbac.authorization.k8s.io/devops-rolebinding created
    
    [root@k8s-master ~]# kubectl get rolebinding/devops-rolebinding -n devops
    NAME                 ROLE               AGE
    devops-rolebinding   Role/devops-rbac   16s
  3. 把kubeconfig文件复制到 devops 用户的家目录的.kube下

    [root@k8s-master ~]# mkdir -p /home/devops/.kube
    [root@k8s-master ~]# cp devops.kubeconfig /home/devops/.kube/config
    [root@k8s-master ~]# ls /home/devops/.kube/
    config
    
    [root@k8s-master ~]# chown -R devops.devops /home/devops/.kube/

  4. 切换上下文,是kubectl读取到config的信息

    [devops@k8s-master ~]$ kubectl config use-context devops@kubernetes
    Switched to context "devops@kubernetes".

开始验证权限

[devops@k8s-master ~]$ kubectl get pods 
No resources found in devops namespace.
[devops@k8s-master ~]$ kubectl get service
No resources found in devops namespace.

通过上面结果可以看出,可以get pod,get service等。

测试创建Pod

[devops@k8s-master ~]$ kubectl run test-pod --image='vvoo/demoapp:v1.0' -n devops
pod/test-pod created
[devops@k8s-master ~]$ kubectl get pods -n devops
NAME       READY   STATUS    RESTARTS   AGE
test-pod   1/1     Running   0          7s
[devops@k8s-master ~]$ kubectl get pods 
NAME       READY   STATUS    RESTARTS   AGE
test-pod   1/1     Running   0          10s

从上面测试结果可以看出,devops用户可以进行pods的创建,且get时不指名称空间,也默认是devops名称空间。

测试其他名称空间创建资源

[devops@k8s-master ~]$ kubectl run test-pod --image='vvoo/demoapp:v1.0' -n default
Error from server (Forbidden): pods is forbidden: User "devops" cannot create resource "pods" in API group "" in the namespace "default"
[devops@k8s-master ~]$ kubectl get pods -n default
Error from server (Forbidden): pods is forbidden: User "devops" cannot list resource "pods" in API group "" in the namespace "default"

可以看出,devops并没有别的名称空间的任何权限,包括默认的default名称空间。

2. ServiceAccount 认证案例

这里通过部署Kubernetes Dashboard示例。

Kubernetes Dashboard项目为Kubernetes集群提供了一个基于Web 的通用UI,支持集群管理、应用管理及应用排障等功能。Dashboard项目包含前端和后端两个组件,如下图所示。前端运行于客户端浏览器中,由TypeScript编写,它使用标准的HTTP方法将请求发送到后端并从后端获取业务数据;后端是使用Go语言编写的HTTP服务器,它负责接收前端的请求、将数据请求发送到适配的远程后端(例如Kubernetes API Server等)或实现业务逻辑等。

kubernetes-access-control-serviceaccount-identify-1

Dashboard 1.7(不含)之前的版本在部署时直接赋予管理权限,这种方式可能存在安全风险,因此1.7及之后的版本默认在部署时仅定义运行Dashboard所需要的最小权限,并且只有在Master主机上通过 kubectl proxy命令创建代理后,才能在本机进行访问。

2.1. 部署Dashboard

官网文档

出于安全因素的考虑,Dashboard在其项目仓库中推荐的默认部署清单(recommended.yaml)中仅定义了运行自身所需要的最小权限, 并且强制要求远程访问必须要基于HTTPS通信,否则应该通过kubectl proxy以代理方式进行。因而,若需要绕过kubectl proxy代理直接访问Dashboard,必须要为其HTTP服务进程提供用于建立HTTPS连接的服务器端证书。

推荐的部署清单默认便会在内存中生成自签证书,并以之生成名为kubernetes-dashboard-certs的Secret对象,Dashboard Pod将从该 Secret中加载证书(tls.crt)和私钥(tls.key)。若需要使用自定义的证书,则应该在执行如下部署命令之前先把准备好的证书与私钥文件分别以tls.crt和tls.key为键名,创建成kubernetes-dashboard名称空间下名为kubernetes-dashboard-certs的Secret对象,需要用到时,在Dashboard部署之前参考Secret对象的管理方式完成创建即可。下面示例中未自定义Secret,直接使用Dashboard项目Master分支中的配置清单完成应用部署。

# kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yaml

部署完成的Dashboard支持多种不同的访问方式,例如kubectl proxy、kubectl port-forward、节点端口、Ingress或API Server等,这里使用节点端口。默认创建的Service对象(kubernetesdashboard)类型为ClusterIP,它仅能在Pod客户端中访问,若需要在集群外使用浏览器访问Dashboard,可将该Service对象类型修改为NodePort后,通过节点端口进行访问。

# kubectl patch svc kubernetes-dashboard -p '{"spec":{"type":"NodePort"}}' -n kubernetes-dashboard
service/kubernetes-dashboard patched

未指定NodePort属性值将会由Service控制器随机分配,获取端口号

# kubectl get svc/kubernetes-dashboard -n kubernetes-dashboard -o jsonpath='{.spec.ports[0].nodePort}'
31959

浏览器访问,它支持直接通过目标Service Account的令牌加载身份凭证,或以该令牌为身份凭证生成专用的kubeconfig文件,并通过指定的文件路径向Dashboard提交认证信息。

kubernetes-access-control-serviceaccount-identify-2

Dashboard的资源访问权限继承自登录时的Service Account用户,我们可以向相关的Service Account分配特定的角色或集群角色完成Dashboard用户权限模型的构建。例如,为登录的用户授权集群级别管理权限时,可直接使用ClusterRoleBinding为Service Account分配内置的集群角色cluster-admin,而授权名称空间级别的管理权限时,可在目标名称空间上向Service Account分配内置的集群角色admin。 当然,也可以直接自定义RBAC的角色或集群角色,以完成特殊需求的权限委派。

2.2. 认证与授权

Kubernetes Dashboard自身并不进行任何形式的身份验证和鉴权,它仅是把用户提交的身份凭据转发至后端的API Server完成验证,资源操作请求及权限检查同样会提交至后端的API Server进行。 从某种意义上讲,Dashboard更像是用户访问Kubernetes的代理程序,发送给API Server的身份认证及资源操作请求都是由Dashboard应用程序完成,因而用户提交的身份凭据需要关联至某个Service Account。

集群全局的资源管理操作依赖于集群管理员权限,因而需要为专用于访问Dashboard的Service Account分配内置的cluster-admin集群角色。随后,将相应Service Account的令牌信息提交给Dashboard并认证到API Server,便可使得Dashboard继承了该账户的所有管理权限。

例如,下面在kubernetes-dashboard名称空间创建一个名为dashboard-admin的Service Account完成该目标。

// 创建一个ServiceAccount
# kubectl create serviceaccount admin-user -n kubernetes-dashboard 
serviceaccount/admin-user created

// 将ServiceAccount和ClusterRole资源cluster-admin绑定
# kubectl create clusterrolebinding admin-user --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:admin-user
clusterrolebinding.rbac.authorization.k8s.io/admin-user created

随后,获取到服务账号kubernetes-dashboard:admin-user关联的Secret对象中的令牌信息,提交给Dashboard即可完成认证。

// 获取admin-user服务账号的Secret对象名称保存在变量中
# ADMIN_SECRET=$(kubectl -n kubernetes-dashboard get secret | awk '/^admin-user/{print $1}')

// 从上面获取到的Secret中获取经过Base64编码后的令牌信息
# ADMIN_TOKEN=$(kubectl get secrets $ADMIN_SECRET -n kubernetes-dashboard -o jsonpath='{.data.token}' |base64 -d)

# echo $ADMIN_TOKEN
eyJhbGciOiJSUzI1NiIsImtpZCI6InczQ1d1ckhpUUxYRF91WlY1RVI3YW5XWExSS0RYWWxxQU1fdUlzSEZtZTgifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLXh2NjZrIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIxN2RhMTgzZC1mNjE0LTQwMDItYmQ4Mi0wMjk4ZGUyYmNlM2QiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZXJuZXRlcy1kYXNoYm9hcmQ6YWRtaW4tdXNlciJ9.NZDcjtTOcK0XFI7rNNAl9QZFtYu7a_3L8LBNFz2nw5f9UftDqbduwVgnT2ifGXsGaAu1P641Few-ggS64aLJKININlyoltdp8k3mIn0FsZ8BWJ-ekNCXUdRJyXg1GRvUeEZ74brwh--dtQT7-evUn42NmcoE2DAd9jRBmSVVa2myAkTKIwllp9BLE_UzRPt49VOrWef_4G-BOGP0t3YkAnvvivrkxBRqUzcrSth4nHA2D0T9f4RdXanSgh-mbGbmZve9BqljE-uwmDzG-nGGKkoEr6JOeXAeJdSo4TVPrFDFjaGyV42UUNQAF5Bjgad3vEvSeS00qy34dAccbhAOKg

将上面获取到的令牌信息复制到Dashboard的登录界面即可完成认证。

kubernetes-access-control-serviceaccount-identify-3

显然,每次访问Dashboard之前都要先通过如上命令获取相应的令牌是件相当烦琐的事情,更简便的办法是依该身份凭据创建出一个专用的kubeconfig文件并存储到客户端,随后登录时在浏览器中通过本地路径加载该kubeconfig文件即可完成认证,更加安全和便捷。

创建专用kubeconfig配置文件示例

为上面创建的kubernetes-dashboard:admin-user创建相关的配置文件。

  1. 添加集群配置,包括集群名称、API Server URL和信任的CA的证书;clusters配置段中的各列表项名称需要唯一。

    # kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server="https://192.168.102.101:6443" --kubeconfig=$HOME/.kube/admin-user.config
    Cluster "kubernetes" set.

  2. 添加身份凭证。

    # kubectl config set-credentials admin-user --token=$ADMIN_TOKEN --kubeconfig=$HOME/.kube/admin-user.config
    User "admin-user" set.

  3. 以用户admin-user的身份凭证与kubernetes集群建立映射关系。

    # kubectl config set-context admin-user@kubernetes --user=admin-user --cluster=kubernetes --kubeconfig=$HOME/.kube/admin-user.config
    Context "admin-user@kubernetes" created.
  4. 设置当前上下文为admin-user@kubernetes。

    # kubectl config use-context admin-user@kubernetes --kubeconfig=$HOME/.kube/admin-user.config
    Switched to context "admin-user@kubernetes".

到这里为止,一个用于Dashboard登陆认证、拥有管理员权限的kubeconfig配置文件设置完成,将这个文件复制到客户端机器上,然后登陆Dashboard时选择文件登陆即可。如下图

kubernetes-access-control-serviceaccount-identify-4

另外,若需要设定的用户仅具有某个名称空间的管理权限,或者仅拥有集群或名称空间级别的资源读取权限,都能够通过RBAC权限管理模型来实现。这类用户的设定过程与前述步骤中的关键不同之处仅在于角色分配步骤。

示例:创建一个全局读取权限Dashboard用户

在名称空间kubernetes-dashboard中创建服务账户monitor,并通过ClusterRoleBinding为其分配默认的集群角色view,便可创建一个仅具有全局读取权限的Dashboard用户, 所需步骤如下。

# kubectl create serviceaccount monitor -n kubernetes-dashboard 
serviceaccount/monitor created

# kubectl create clusterrolebinding monitor --clusterrole=view --serviceaccount=kubernetes-dashboard:monitor
clusterrolebinding.rbac.authorization.k8s.io/monitor created

示例:创建一个只对dev名称空间有权限Dashboard用户

在名称空间dev中创建一个服务账户dev-ns-admin,并通过RoleBinding为其分配默认的集群角色admin,就能创建一个仅具有dev名称空间管理权限的Dashboard用户,所需要的步骤如下。

# kubectl create serviceaccount ns-admin -n dev
serviceaccount/ns-admin created

# kubectl create clusterrolebinding ns-admin --clusterrole=admin --serviceaccount=dev:ns-admin
clusterrolebinding.rbac.authorization.k8s.io/ns-admin created

无论分配了何种集群角色或拥有ServiceAccount账户的特定角色,它们的认证信息提取及使用kubeconfig配置文件的方式都是相同的。