Kubernetes认证鉴权

Posted 猴赛雷技术交流

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kubernetes认证鉴权相关的知识,希望对你有一定的参考价值。

作者:王长生

我们知道对于资源对象的操作都是通过 APIServer 进行的,那么集群是怎样知道我们的请求就是合法的请求呢?这个就需要了解 Kubernetes的认证鉴权流程

API 对象

在讲认证鉴权之前,我们还需要再去理解下 Kubernetes 集群中的对象,我们知道,在 Kubernetes 集群中,Kubernetes 对象是我们持久化的实体,就是最终存入 etcd 中的数据。我们直接编写的 YAML 文件,通过 kubectl 来提交的资源清单文件,然后创建的对应的资源对象,那么它究竟是如何将我们的 YAML 文件转换成集群中的一个 API 对象的呢?

这个就需要去了解下声明式 API的设计,Kubernetes API 是一个以 JSON 为主要序列化方式的 HTTP 服务,除此之外也支持 Protocol Buffers 序列化方式,主要用于集群内部组件间的通信。Kubernetes API 文档可以参考官网https://kubernetes.io/docs/re...进行阅读学习

为了可扩展性,Kubernetes 在不同的 API 路径(比如/api/v1 或者 /apis/batch)下面支持了多个 API 版本,不同的 API 版本意味着不同级别的稳定性和支持:

  • Alpha 级别,例如 v1alpha1 默认情况下是被禁用的,可以随时删除对功能的支持,所以要慎用
  • Beta 级别,例如 v2beta1 默认情况下是启用的,表示代码已经经过了很好的测试,但是对象的语义可能会在随后的版本中以不兼容的方式更改
  • 稳定级别,比如 v1 表示已经是稳定版本了,也会出现在后续的很多版本中。

在 Kubernetes 集群中,一个 API 对象在 Etcd 里的完整资源路径,是由:Group(API 组)、Version(API 版本)和 Resource(API 资源类型)三个部分组成的。通过这样的结构,整个 Kubernetes 里的所有 API 对象,实际上就可以用如下的树形结构表示出来:

从上图中我们也可以看出 Kubernetes 的 API 对象的组织方式,在顶层,我们可以看到有一个核心组(由于历史原因,是 /api/v1 下的所有内容而不是在 /apis/core/v1 下面)和命名组(路径 /apis/$NAME/$VERSION)和系统范围内的实体,比如 /metrics。我们也可以用下面的命令来查看集群中的 API 组织形式:

[root@k8s-master ~]# kubectl get --raw /
{
  "paths": [
    "/api",
    "/api/v1",
    "/apis",
    "/apis/",
    ...
    "/version"
  ]
}

比如我们来查看核心组下的资源对象,同样我们还是可以通过 kubectl 来查询数据,这里面我们可以看到核心组下面的资源对象和对应操作

[root@k8s-master ~]# kubectl get --raw /api/v1 | python -m json.tool
{
    "groupVersion": "v1",
    "kind": "APIResourceList",
    "resources": [
        {
            "kind": "Binding",
            "name": "bindings",
            "namespaced": true,
            "singularName": "",
            "verbs": [
                "create"
            ]
        },
        {
            "kind": "ComponentStatus",
            "name": "componentstatuses",
            "namespaced": false,
            "shortNames": [
                "cs"
            ],
            "singularName": "",
            "verbs": [
                "get",
                "list"
            ]
        },
        {
            "kind": "ConfigMap",
            "name": "configmaps",
            "namespaced": true,
            "shortNames": [
                "cm"
            ],
            "singularName": "",
            "storageVersionHash": "qFsyl6wFWjQ=",
            "verbs": [
                "create",
                "delete",
                "deletecollection",
                "get",
                "list",
                "patch",
                "update",
                "watch"
            ]
        },
        ...
        {
            "kind": "Service",
            "name": "services/status",
            "namespaced": true,
            "singularName": "",
            "verbs": [
                "get",
                "patch",
                "update"
            ]
        }

但是这个操作和我们平时操作 HTTP 服务的方式不太一样,这里我们可以通过 kubectl proxy 命令来开启一个代理http服务对 apiserver 进行访问:

[root@k8s-master ~]# kubectl proxy
Starting to serve on 127.0.0.1:8001

然后重新开启一个新的终端,我们可以通过如下代理服务方式来访问apiserver的接口,比如我们访问查询某个命名空间下pod资源对象的接口

[root@k8s-master ~]# curl http://127.0.0.1:8001/api/v1/namespaces/default/pods
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces/default/pods",
    "resourceVersion": "9109616"
  },
  "items": [
    {
      "metadata": {
        "name": "nginx-deploy-75c7f965d8-hnmvn",
        "generateName": "nginx-deploy-75c7f965d8-",
        "namespace": "default",
        "selfLink": "/api/v1/namespaces/default/pods/nginx-deploy-75c7f965d8-hnmvn",
        "uid": "574ac979-41b8-460f-afaf-d29155911ba3",
        "resourceVersion": "6786396",
        "creationTimestamp": "2021-05-10T03:30:07Z",
        "labels": {
          "app": "nginx",
          "pod-template-hash": "75c7f965d8"
        },
        "ownerReferences": [
          {
            "apiVersion": "apps/v1",
            "kind": "ReplicaSet",
            "name": "nginx-deploy-75c7f965d8",
            "uid": "25bdae05-87e9-41e0-bcde-6bfeda87047c",
            "controller": true,
            "blockOwnerDeletion": true
          }
        ],
        ...

通常,Kubernetes API 支持通过标准 HTTP  POST、PUT、DELETE 和 GET 在指定 PATH 路径上创建、更新、删除和检索操作,并使用 JSON 作为默认的数据交互格式。

Kubernetes认证

上面我们使用了kubectl或者kubectl proxy的方式,都能够顺利获取到apiserver的资源对象的数据,这是因为它们已经顺利通过了Kubernetes的认证鉴权组件
Kubernetes API的请求从发起到操作存储层的流程如图

下面我们分析下kubectl、kubectl proxy、pod访问apiserver的认证方式

kubectl访问apiserver

kubectl使用的认证方式是clientCA认证,X509认证是Kubernetes组件间默认使用的认证方式,同时也是kubectl客户端对应的kube-config中经常使用到的访问凭证。它是一个比较安全的方式,访问者会使用由集群CA签发的,或是添加在apiserver配置中的授信CA签发的客户端证书去访问apiserver。apiserver在接收到请求后,会进行TLS的握手流程。
除了验证证书的合法性,apiserver还会校验客户端证书的请求源地址等信息,开启双向认证。
比如我们查看下我们kubectl的证书信息

[root@k8s-master ~]# cat ~/.kube/config
apiVersion: v1
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
users:
- name: kubernetes-admin
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURFekNDQWZ1Z0F3SUJBZ0lJVmxIbDlTalNvdFF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRBME1EY3hNVFF6TXpsYUZ3MHlNakEwTURjeE1UUXpOREZhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXFzVnlQc2RQRGlEYW9FNWcKZWxOQjV4ZHJoZCs1eEd5RUJFbGpUY2tMb3JPQlN6SjE3Z2JpY0VSaXRQLzh1YVpmVk9ISnZ0Y2tyZUpGa3NHNgp2Ujc5YUk4d3k0elUreEk0ZzdzK2ZrTFRsK1QrR2xaSWlQaXN3a2RQZE9ad0REUDBKdDQ5NjljVzFndVJ6UTVQCmhpSjRTcE96Z0dmeFJGQWpFTUFCNktJcXBWYjlrbmV4d0xHVDRRNTZNS1JvV294UytEaFBQZFk4bUlVR3pHZ0oKbkw1bEl1Mjl2a0FmWG1vZEdZMVFUNkszSXU3NmFhWXl0TTVRUTZZVnFwekxXU0lYOFN2L0E0dlFqVDlTSDY5eQptQ1RmQ0lXWjVTRGZ4VTlvQ0p5RGpKTmpBdUErNWJONUpxMDFEYjhjK0hjTHVHUENBRVJUVnBZU3docWx1T0lFCk40SU9Md0lEQVFBQm8wZ3dSakFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0h3WURWUjBqQkJnd0ZvQVV6RmZHVHJhMjRVa3hzM2NReWJzSnprT2R2UXN3RFFZSktvWklodmNOQVFFTApCUUFEZ2dFQkFDRHUwQ3g5Qk1NdjdUMnh6T3gzTDNNczk5NTdKMDY3WDVhbTZnZW4yaXltekViMkNldG51REdoCnFMWW5MZnBOZ1FOQ1pTbkg5dzZIYjdWenRMTzlheXZjejcvRVlRVkpyOVN0MzdtZDc0d3dKY1AvZWY1b2ZEbkgKVTVJaXZKK1RuM3REeGhlVVU5VlBFSkdCbFZmd3N0UmxJZ3NWclR0TkVnNGYzaW04azZzNlRTTGV5Sis4Y21zdgpwTmYyRDNpWWw3aEhBTGJwS2tFWVEya2xSY0IyRDFSL1Fhd2o4WWoyUGJ4cEZOU0t4QmQ4S09mcGVaMWQ5ZmpiCmZMbUxGU29rZjk1b0lrTk9TSGpUanVDNmNaNGVHczU0bjhaMmhnMWZia1R0Y2pJK1ROZi9nY29FNExvM3JhaDgKbW1sa1Qxdit4T3hKUWpkbkdwT2FSNytINFkwblY5dz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBcXNWeVBzZFBEaURhb0U1Z2VsTkI1eGRyaGQrNXhHeUVCRWxqVGNrTG9yT0JTekoxCjdnYmljRVJpdFAvOHVhWmZWT0hKdnRja3JlSkZrc0c2dlI3OWFJOHd5NHpVK3hJNGc3cytma0xUbCtUK0dsWkkKaVBpc3drZFBkT1p3RERQMEp0NDk2OWNXMWd1UnpRNVBoaUo0U3BPemdHZnhSRkFqRU1BQjZLSXFwVmI5a25leAp3TEdUNFE1Nk1LUm9Xb3hTK0RoUFBkWThtSVVHekdnSm5MNWxJdTI5dmtBZlhtb2RHWTFRVDZLM0l1NzZhYVl5CnRNNVFRNllWcXB6TFdTSVg4U3YvQTR2UWpUOVNINjl5bUNUZkNJV1o1U0RmeFU5b0NKeURqSk5qQXVBKzViTjUKSnEwMURiOGMrSGNMdUdQQ0FFUlRWcFlTd2hxbHVPSUVONElPTHdJREFRQUJBb0lCQUdLQnVzRVQzenBiSVVIUApkRCtidnl3NmlqK1RLbWx2MzBkSnZncWtxaDJVUmtUR090aXZCL2VTdXcyRmpKYmFyYXNkQTI4ZVUzNHFROC9BCkNLUUhPRTRVS3lWL2Uydkl1dWppSGM1ZlpnYjhoTWRVZGtyc2gxc2FIMjlqYmNiY1FUNGFmTVdLTVJZUFhtOVcKamZEbCtWV3JsYVBBVWFBQ1NmZmppalpUTlI1aCtuSUxxazdLQ3dUelRTRk1FNmNpS3g3NkhJZ08wODlhSzJGTgpqNWpLTjRhdWtSSTQyMnNiYmFvRGNsMXVpNVFtaHFVU0xCVVQvemVhTHM0MXJrN2w4MWNtQXhYQll0YXRwb1A0Ci84dDQzSkMyRVdYQU5BZDQ1cW1jbzVBUmZoMUZJMWo4ejB3dFZpakhDSmFIMmo4TjhGTHh3YzhZL0ttNGphMncKcVVyK0dhRUNnWUVBei95dVJMUDBBbWwvRXhLN0oxVUpERnJGbG5GTHVsRmVDM2dwWFRCL0NxUXFOL1BkbDVDdgpKbVpCV3VhTXArWEJna0NMZE5UV1BNMGFIUEd3aExKUWZXa1ZYc1lCM2VENllwM0pXVGR1dmJvbVVuRzY1TC9yCnF2WTVSUy83WWNmRnZtbVNNYVAxeCsxUDFEQWVUWHBvdllBczlIS2U3RFh4UUUxL3BEOHEwTzBDZ1lFQTBqRngKSlpQU1J4RE5tNVNaTzNsYUZwVDJKdGJQdDUvdUtXRjAraDZvWlNKaDlPVjhhaVM5NlRPRStYREYwaHk5ZVBMbAp6a1NFQ0hEOEE3ZVF0OWc1VGc2c3lCWkpWMXJzYUN0YjRCWGRpcU1jSGE4SWhLQW9ySnpxYldGTXZmdG1WMjc5CjMrVldGaW13dnBuTzNWaHhnQ3lLWjRhRjdaNkV2T1ZDb3IzNDVBc0NnWUVBeUlkME1qTmFtUlREKzB5OCsxQW0KZUMzd2dYdGNxeGdXVjNLVVZ4QVIvTjJKQXdkeDU5Y011RFl3M3dhWUtLMEJwS2E4am5sQzBiNWlaZk8wNEV2WQpCUUpUSTF3L29vQnVpTFJlMUZENHlaNTNvbGVhL1QvNVpZMGViSkcxaW5JRk92QW9qd25wUjhpTGhpYWFvTkxiCnQ1R2tSazlZNEorbHFmek9penFIK29VQ2dZQUp0aWNZS1dCSjBFanZxMG41S1g0MEZPWGFuWW96WGJ4UFJTVjIKZVB3bTBCUGVrTXZTeTZmS29vcStTNnVZTGFQRGR0V1BWak1UZ01Ua0Z4TWtxMlRhYW1zcFEzNVgvdWQxV0t1QwpDd0NWYXp2ZFV6ejlnN2pkWU5La0F4N2NtRVQrUFM2VnJhN3dqelNQV2VQbzdqRXdUdDZHTWZ6MklhRFlhVzlPCnZhQkdTUUtCZ0dEaGdvK3BucWFrZmhVRE15bWxwQ3ZiNWZXS000RzJWbDFHZEdaSlFSWEpPR0hqbjlyNWZuQzEKdGx4d3BBN2NucjNPalRLYVRYeVM1SzA0QlVzQ0l2UFZmZVZlMW9ydm9rR3ZkNGJxUlFab3AvVlFzWnI2RGpnTApqUjV4UzBOdXJnR2QzVVEwRHFhL0xOQW9mMEFOdG9nTHM1Vm1VL1pueDA2L3dndHN6empnCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

默认我们使用kubectl命令行,使用的默认上下文是kubernetes-admin@kubernetes,这个上下文使用的kubernetes用户是kubernetes-admin
这个用户对应的证书中是包含认证信息的

echo -n "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURFekNDQWZ1Z0F3SUJBZ0lJVmxIbDlTalNvdFF3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRBME1EY3hNVFF6TXpsYUZ3MHlNakEwTURjeE1UUXpOREZhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXFzVnlQc2RQRGlEYW9FNWcKZWxOQjV4ZHJoZCs1eEd5RUJFbGpUY2tMb3JPQlN6SjE3Z2JpY0VSaXRQLzh1YVpmVk9ISnZ0Y2tyZUpGa3NHNgp2Ujc5YUk4d3k0elUreEk0ZzdzK2ZrTFRsK1QrR2xaSWlQaXN3a2RQZE9ad0REUDBKdDQ5NjljVzFndVJ6UTVQCmhpSjRTcE96Z0dmeFJGQWpFTUFCNktJcXBWYjlrbmV4d0xHVDRRNTZNS1JvV294UytEaFBQZFk4bUlVR3pHZ0oKbkw1bEl1Mjl2a0FmWG1vZEdZMVFUNkszSXU3NmFhWXl0TTVRUTZZVnFwekxXU0lYOFN2L0E0dlFqVDlTSDY5eQptQ1RmQ0lXWjVTRGZ4VTlvQ0p5RGpKTmpBdUErNWJONUpxMDFEYjhjK0hjTHVHUENBRVJUVnBZU3docWx1T0lFCk40SU9Md0lEQVFBQm8wZ3dSakFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0h3WURWUjBqQkJnd0ZvQVV6RmZHVHJhMjRVa3hzM2NReWJzSnprT2R2UXN3RFFZSktvWklodmNOQVFFTApCUUFEZ2dFQkFDRHUwQ3g5Qk1NdjdUMnh6T3gzTDNNczk5NTdKMDY3WDVhbTZnZW4yaXltekViMkNldG51REdoCnFMWW5MZnBOZ1FOQ1pTbkg5dzZIYjdWenRMTzlheXZjejcvRVlRVkpyOVN0MzdtZDc0d3dKY1AvZWY1b2ZEbkgKVTVJaXZKK1RuM3REeGhlVVU5VlBFSkdCbFZmd3N0UmxJZ3NWclR0TkVnNGYzaW04azZzNlRTTGV5Sis4Y21zdgpwTmYyRDNpWWw3aEhBTGJwS2tFWVEya2xSY0IyRDFSL1Fhd2o4WWoyUGJ4cEZOU0t4QmQ4S09mcGVaMWQ5ZmpiCmZMbUxGU29rZjk1b0lrTk9TSGpUanVDNmNaNGVHczU0bjhaMmhnMWZia1R0Y2pJK1ROZi9nY29FNExvM3JhaDgKbW1sa1Qxdit4T3hKUWpkbkdwT2FSNytINFkwblY5dz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="|base64 -d|openssl x509 -text
certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 6220005401490006740 (0x5651e5f528d2a2d4)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes
        Validity
            Not Before: Apr  7 11:43:39 2021 GMT
            Not After : Apr  7 11:43:41 2022 GMT
        Subject: O=system:masters, CN=kubernetes-admin
  ...      

其中Subject: O=system:masters, CN=kubernetes-admin分别代表O用户组和CN用户,kubernetes基于RBAC对该用户和组配置了对应的权限

kubectl proxy访问apiserver

kubectl proxy使用的是RequestHeader认证,在该种访问模式下, 我们是以http的方式发起请求到代理服务的, 此时, 代理服务会将该请求发送给 kube-apiserver, 在此之前, 代理会将发送给 kube-apiserver 的请求头里加入证书信息
apiserver需要配置:

  • --requestheader-username-headers=X-Remote-User
  • --requestheader-group-headers=X-Remote-Group
  • --requestheader-extra-headers-prefix=X-Remote-Extra-
  • --requestheader-client-ca-file:防止头部欺骗
  • --requestheader-allowed-names:设置允许的CN列表
  • --proxy-client-cert-file:客户端证书
  • --proxy-client-key-file:客户端私钥
   [root@k8s-master ~]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
   ...
     - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
    - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
    - --requestheader-allowed-names=front-proxy-client
    - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
    - --requestheader-extra-headers-prefix=X-Remote-Extra-
    - --requestheader-group-headers=X-Remote-Group
    - --requestheader-username-headers=X-Remote-User
   ...

我们查看对应的proxy-client-cert-file证书,获取用户信息

[root@k8s-master ~]# cat /etc/kubernetes/pki/front-proxy-client.crt|openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1421614817980964257 (0x13ba9725192fdda1)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=front-proxy-ca
        Validity
            Not Before: Apr  7 11:43:40 2021 GMT
            Not After : Apr  7 11:43:40 2022 GMT
        Subject: CN=front-proxy-client

可以看到对应的CN是front-proxy-client,我们在apiserver中已经配置了- --requestheader-allowed-names=front-proxy-client是可以认证通过的

Pod访问apiserver

Pod访问apiserver使用的是ServiceAccountAuth认证,serviceaccount是k8s中唯一能够通过API方式管理的apiserver访问凭证,通常用于pod中的业务进程与apiserver的交互,ServiceAccount解决Pod在集群里面的身份认证问题,认证使用的授权信息存在secret里面(由SecretAccount Controller自行创建)
当一个namespace创建完成后,会同时在该namespace下生成名为default的serviceaccount和对应Secret:

[root@k8s-master ~]# kubectl get sa default -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2021-04-07T11:44:12Z"
  name: default
  namespace: default
  resourceVersion: "379"
  selfLink: /api/v1/namespaces/default/serviceaccounts/default
  uid: 3493e0f4-a87c-4c0e-a373-3c117d205d8d
secrets:
- name: default-token-s46zd
[root@k8s-master ~]# kubectl get secret default-token-s46zd -o yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeE1EUXdOekV4TkRNek9Wb1hEVE14TURRd05URXhORE16T1Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSlFWCjNmRmVraUdmL3ZDK1JPNFR4SC9QbkRhMmJINi9lRFAzNUc1SXppUnladmpUWWtNeGVyOHIrTWdndCtCN05oc28Ka0ZCVVNCVUhrbVhHZFFBUHRjNTJocVdGRlhtZk10TzBhNzZBTWNCdFZUa2hPZDRxc3NPcy9jUndVcGxYKytteApLcW9FdDc0eFBhRnJxRzIyeDVEN011Y3lYQmtxQk4vWGRKcThKNU5xTWhHd2EvbjVtbWUxYmRrdGh3UWd1SnZzCkc2THRBZGZhRWdXbWxnUVFUMWZHNkhVV3g0L085aTJSNEhIU1VXMDFmTnUwaGFVekNJcE04VERLMk9DbDJYN04KcWE3QitGZDlZR1krUVdhNWVMZk9nMFJUcTJOb210M1E5WWVGWHJKZDJMOHlpc3VsbjM0ZDNxZjFQakxtMkdJQwpQS01XenBVaWJxbkpNb0RvdjYwQ0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZNeFh4azYydHVGSk1iTjNFTW03Q2M1RG5iMExNQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFBdW5WUXYvTnhnN2JCYXBiVWRVT2s4UWhkclZkbXFGVUlCWnlQN0FUMlh5eVNlMG8xVwp4dEU3c1NyWlQvZDJUTzJseFRLM0NQRVU2dW9uMDQ1amhyd1N1dGNVa3llMUZVcnF6aWNTa1luZjhnVFdOMmtlCnpUdWJ5OUowcVZFRVErc2cvU2Q1bERVUm9LSHAyVXRLZzdrbVRzT3d3U2ppVnlVZEdmMGcrZ2djUU9iMjFvNVgKYUtoOUtIQUdBVDRvQnlOdTY0STJEaWV0QkRkWWdsL3B5cTgwcCtwVTlLSDJObEZrMERhc01uU2I0eEE1M2U3RApJQVJua0JGOFNuSXR2a3pacFFTVWhXNVpJT2IvdjdOcWZxalhuTE8rdUx4czRPSllXL3V5TzBpMEkrYUF5RWRYClUyUkMzZjIyUHV1VmNnWmZ6ck5vUzU5dnQwVVlVM1FRcURqMgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
  namespace: ZGVmYXVsdA==
  token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklraDZZMnB4VlhCbk5ubFBVa3AxVVZwblYwbGthMmhOZG14TVpHeHdOa1pGVFdvMVFXUkhjbUpPWldNaWZRLmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUprWldaaGRXeDBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5elpXTnlaWFF1Ym1GdFpTSTZJbVJsWm1GMWJIUXRkRzlyWlc0dGN6UTJlbVFpTENKcmRXSmxjbTVsZEdWekxtbHZMM05sY25acFkyVmhZMk52ZFc1MEwzTmxjblpwWTJVdFlXTmpiM1Z1ZEM1dVlXMWxJam9pWkdWbVlYVnNkQ0lzSW10MVltVnlibVYwWlhNdWFXOHZjMlZ5ZG1salpXRmpZMjkxYm5RdmMyVnlkbWxqWlMxaFkyTnZkVzUwTG5WcFpDSTZJak0wT1RObE1HWTBMV0U0TjJNdE5HTXdaUzFoTXpjekxUTmpNVEUzWkRJd05XUTRaQ0lzSW5OMVlpSTZJbk41YzNSbGJUcHpaWEoyYVdObFlXTmpiM1Z1ZERwa1pXWmhkV3gwT21SbFptRjFiSFFpZlEuWHc3Rm4zWURoTlViYWNMOVdMVW1ISFQzbzkyZ2d2c0t0dzdPY21PTUhyd2ZDTnlPUFRIWTFKTUtCRkpCZkIzcmhjdURncHI2dHBpQm1BN0pnUzkwRTVhNG4zU1VoU0pscEE4eElZWU90aklJSFhaV25rYVg3T1c0WkRwU2RIVzNienNyOHBBc09SS2diTENzZ18yRlBmRGhybHRQMjFKNnZoOHZMUGlfVVJlTmtiSVM4WlgzcERFNTV2eHZlRkE1Zkk1S2NqLVJKdnRpOFQ3TUc5WjQxZU56OXlyWVd5SkRpenh5RUlLR0tEVnVIUjNyLXpvWm9icHhvQU1BcUc2aFN6NkhXUUkzVG45anVXcmVWTGJWYk9qUktzTmF4ZVNqOU5BSTBsZXRzQTJPVFVGcUF3M1drU3E0MnRZOE5fcm5NbkZuN1R3U3VqQk5hVmlPSl9xQi13
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: default
...

对应的Secret里:data字段有两块数据:ca.crt用于对服务端的校验,token用于Pod的身份认证,它们都是用base64编码过的
Pod创建的时候,Admission Controller会根据指定的ServiceAccount把对应secret的ca.crt和token文件挂载到固定目录/var/run/secrets/kubernetes.io/serviceaccount下

    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-s46zd
      readOnly: true

Pod要访问apiserver的时候,默认利用Secret其中的token文件来认证Pod的身份,利用ca.crt校验服务端,Pod身份被认证合法后,其权限需要通过RBAC来配置

Kubernetes鉴权(RBAC)

上面我们介绍了 Kubernetes 所有资源对象都是模型化的 API 对象,允许执行 CRUD(Create、Read、Update、Delete) 操作(也就是我们常说的增、删、改、查操作),比如下面的这些资源:

  • Pods
  • ConfigMaps
  • Deployments
  • Nodes
  • Secrets
  • Namespaces
  • ......
    对于上面这些资源对象的可能存在的操作有:
  • create
  • get
  • delete
  • list
  • update
  • edit
  • watch
  • exec
  • patch

在更上层,这些资源和 API Group 进行关联,比如 Pods 属于 Core API Group,而 Deployements 属于 apps API Group,现在我们要在 Kubernetes 中通过 RBAC 来对资源进行权限管理,除了上面的这些资源和操作以外,我们还需要了解另外几个概念:

  • Rule:规则,规则是一组属于不同 API Group 资源上的一组操作的集合
  • Role 和 ClusterRole:角色和集群角色,这两个对象都包含上面的 Rules 元素,二者的区别在于,在 Role 中,定义的规则只适用于单个命名空间,也就是和 namespace 关联的,而 ClusterRole 是集群范围内的,因此定义的规则不受命名空间的约束。另外 Role 和 ClusterRole 在Kubernetes 中都被定义为集群内部的 API 资源,和我们前面学习过的 Pod、Deployment 这些对象类似,都是我们集群的资源对象,所以同样的可以使用 YAML 文件来描述,用 kubectl 工具来管理
  • Subject:主题,对应集群中尝试操作的对象,集群中定义了3种类型的主题资源:

    • User Account:用户,这是有外部独立服务进行管理的,管理员进行私钥的分配,用户可以使用 KeyStone 或者 Goolge 帐号,甚至一个用户名和密码的文件列表也可以。对于用户的管理集群内部没有一个关联的资源对象,所以用户不能通过集群内部的 API 来进行管理
    • Group:组,这是用来关联多个账户的,集群中有一些默认创建的组,比如 cluster-admin
    • Service Account:服务帐号,通过 Kubernetes API 来管理的一些用户帐号,和 namespace 进行关联的,适用于集群内部运行的应用程序,需要通过 API 来完成权限认证,所以在集群内部进行权限操作,我们都需要使用到 ServiceAccount
  • RoleBinding 和 ClusterRoleBinding:角色绑定和集群角色绑定,简单来说就是把声明的 Subject 和我们的 Role 进行绑定的过程(给某个用户绑定上操作的权限),二者的区别也是作用范围的区别:RoleBinding 只会影响到当前 namespace 下面的资源操作权限,而 ClusterRoleBinding 会影响到所有的 namespace。

接下来我们来通过几个简单的示例,来演示下在 Kubernetes 集群中如何使用 RBAC。

只能访问某个 namespace 的普通用户

我们想要创建一个 User Account,只能访问default这个命名空间,对应的用户信息如下所示:

username: wangcs
group: imonkey

创建用户凭证

我们前面已经提到过,Kubernetes 没有 User Account 的 API 对象,不过要创建一个用户帐号的话也是挺简单的,利用管理员分配给你的一个私钥就可以创建了,这个我们可以参考官方文档中的方法,这里我们来使用 OpenSSL 证书来创建一个 User
给用户 wangcs 创建一个私钥,命名成 wangcs.key:

[root@k8s-master k8s-rbac]# openssl genrsa -out wangcs.key 2048
Generating RSA private key, 2048 bit long modulus
....+++
...................+++
e is 65537 (0x10001)

使用我们刚刚创建的私钥创建一个证书签名请求文件:wangcs.csr,要注意需要确保在-subj参数中指定用户名和组(CN表示用户名,O表示组):

[root@k8s-master k8s-rbac]# openssl req -new -key wangcs.key -out wangcs.csr -subj "/CN=wangcs/O=imonkey"

然后找到我们的 Kubernetes 集群的 CA 证书,我们使用的是 kubeadm 安装的集群,CA 相关证书位于 /etc/kubernetes/pki/ 目录下面,我们会利用该目录下面的 ca.crt 和 ca.key两个文件来批准上面的证书请求。生成最终的证书文件,我们这里设置证书的有效期为 100 天:

[root@k8s-master k8s-rbac]# openssl x509 -req -in wangcs.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out wangcs.crt -days 100
Signature ok
subject=/CN=wangcs/O=imonkey
Getting CA Private Key

现在查看我们当前文件夹下面是否生成了一个证书文件:

[root@k8s-master k8s-rbac]# ls
wangcs.crt  wangcs.csr  wangcs.key

现在我们可以使用刚刚创建的证书文件和私钥文件在集群中创建新的凭证和上下文(Context):

[root@k8s-master]# kubectl config set-credentials wangcs --client-certificate=/root/k8s-rbac/wangcs.crt --client-key=/root/k8s-rbac/wangcs.key
User "wangcs" set.

我们可以看到一个用户 wangcs 创建了,然后为这个用户设置新的 Context,我们这里指定特定的一个 namespace:

[root@k8s-master ~]# kubectl config set-context wangcs-context --cluster=kubernetes --namespace=default --user=wangcs
Context "wangcs-context" created.

到这里,我们的用户 wangcs 就已经创建成功了,现在我们使用当前的这个配置文件来操作 kubectl 命令的时候,应该会出现错误,因为我们还没有为该用户定义任何操作的权限呢:

[root@k8s-master ~]# kubectl get pods --context=wangcs-context
Error from server (Forbidden): pods is forbidden: User "wangcs" cannot list resource "pods" in API group "" in the namespace "default"

创建角色

用户创建完成后,接下来就需要给该用户添加操作权限,我们来定义一个 YAML 文件,创建一个允许用户操作 Deployment、Pod、ReplicaSets 的角色,如下定义:(wangcs-role.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: wangcs-role
  namespace: default
rules:
- apiGroups: ["", "apps"]
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用[\'*\']

其中 Pod 属于core这个 API Group,在 YAML 中用空字符就可以,而 Deployment 和 ReplicaSet 现在都属于 apps 这个 API Group(如果不知道则可以用 kubectl explain 命令查看),所以 rules 下面的 apiGroups 就综合了这几个资源的 API Group:["", "apps"],其中 verbs 就是我们上面提到的可以对这些资源对象执行的操作,我们这里需要所有的操作方法,所以我们也可以使用[\'*\']来代替,然后直接创建这个 Role:

[root@k8s-master k8s-rbac]# kubectl apply -f wangcs-role.yaml 
role.rbac.authorization.k8s.io/wangcs-role created

创建角色权限绑定

Role 创建完成了,但是很明显现在我们这个 Role 和我们的用户 wangcs 还没有任何关系,对吧?这里就需要创建一个 RoleBinding 对象,在 default 这个命名空间下面将上面的 wangcs-role 角色和用户 wangcs 进行绑定:(wangcs-rolebinding.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: wangcs-rolebinding
  namespace: default
subjects:
- kind: User
  name: wangcs
  apiGroup: ""
roleRef:
  kind: Role
  name: wangcs-role
  apiGroup: rbac.authorization.k8s.io  # 留空字符串也可以,则使用当前的apiGroup

上面的 YAML 文件中我们看到了 subjects 字段,这里就是我们上面提到的用来尝试操作集群的对象,这里对应上面的 User 帐号 wangcs,使用kubectl 创建上面的资源对象:

[root@k8s-master k8s-rbac]# kubectl apply -f wangcs-rolebinding.yaml 
rolebinding.rbac.authorization.k8s.io/wangcs-rolebinding created

测试

现在我们应该可以上面的 wangcs-context 上下文来操作集群了:

[root@k8s-master ~]# kubectl get pods --context=wangcs-context
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-75c7f965d8-hnmvn   1/1     Running   0          11d
nginx-deploy-75c7f965d8-xtdv9   1/1     Running   0          11d

我们可以成功访问default命名空间的pod对象,如果我们在后面加上一个-n kube-system试看看呢?

[root@k8s-master ~]# kubectl get pods --context=wangcs-context -n kube-system
Error from server (Forbidden): pods is forbidden: User "wangcs" cannot list resource "pods" in API group "" in the namespace "kube-system"

如果去获取其他的资源对象呢:

[root@k8s-master ~]# kubectl get configmaps  --context=wangcs-context
Error from server (Forbidden): configmaps is forbidden: User "wangcs" cannot list resource "configmaps" in API group "" in the namespace "default"

我们可以看到没有权限获取,因为我们并没有为当前操作用户指定configmap的访问权限,是符合我们的预期的。这样我们就创建了一个只有单个命名空间访问权限的普通 User 。

只能访问某个 namespace 的 ServiceAccount

上面我们创建了一个只能访问某个命名空间下面的普通用户,我们前面也提到过 subjects 下面还有一种类型的主题资源:ServiceAccount,现在我们来创建一个集群内部的用户只能操作 default 这个命名空间下面的 pods 和 deployments,首先来创建一个 ServiceAccount 对象:

[root@k8s-master ~]# kubectl create sa wangcs-sa
serviceaccount/wangcs-sa created

当然我们也可以定义成 YAML 文件的形式来创建:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: wangcs-sa
  namespace: default

然后新建一个 Role 对象:(wangcs-sa-role.yaml)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: wangcs-sa-role
  namespace: default
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch"]

可以看到我们这里定义的角色只有查询pod和deployment权限,待会我们可以重点测试一下,创建该 Role 对象:

[root@k8s-master k8s-rbac]# kubectl apply -f wangcs-sa-role.yaml
role.rbac.authorization.k8s.io/wangcs-sa-role created

然后创建一个 RoleBinding 对象,将上面的 ServiceAccount wangcs-sa 和role wangcs-sa-role 进行绑定:(wangcs-sa-rolebinding.yaml)

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: wangcs-sa-rolebinding
  namespace: default
subjects:
- kind: ServiceAccount
  name: wangcs-sa
  namespace: default
roleRef:
  kind: Role
  name: wangcs-sa-role
  apiGroup: rbac.authorization.k8s.io

添加这个资源对象:

[root@k8s-master k8s-rbac]# kubectl apply -f wangcs-sa-rolebinding.yaml 
rolebinding.rbac.authorization.k8s.io/wangcs-sa-rolebinding created

测试

首先获取到ServiceAccount wangcs-sa对应的secret的token

[root@k8s-master ~]# kubectl get secret wangcs-sa-token-b6blc -o yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeE1EUXdOekV4TkRNek9Wb1hEVE14TURRd05URXhORE16T1Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSlFWCjNmRmVraUdmL3ZDK1JPNFR4SC9QbkRhMmJINi9lRFAzNUc1SXppUnladmpUWWtNeGVyOHIrTWdndCtCN05oc28Ka0ZCVVNCVUhrbVhHZFFBUHRjNTJocVdGRlhtZk10TzBhNzZBTWNCdFZUa2hPZDRxc3NPcy9jUndVcGxYKytteApLcW9FdDc0eFBhRnJxRzIyeDVEN011Y3lYQmtxQk4vWGRKcThKNU5xTWhHd2EvbjVtbWUxYmRrdGh3UWd1SnZzCkc2THRBZGZhRWdXbWxnUVFUMWZHNkhVV3g0L085aTJSNEhIU1VXMDFmTnUwaGFVekNJcE04VERLMk9DbDJYN04KcWE3QitGZDlZR1krUVdhNWVMZk9nMFJUcTJOb210M1E5WWVGWHJKZDJMOHlpc3VsbjM0ZDNxZjFQakxtMkdJQwpQS01XenBVaWJxbkpNb0RvdjYwQ0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZNeFh4azYydHVGSk1iTjNFTW03Q2M1RG5iMExNQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFBdW5WUXYvTnhnN2JCYXBiVWRVT2s4UWhkclZkbXFGVUlCWnlQN0FUMlh5eVNlMG8xVwp4dEU3c1NyWlQvZDJUTzJseFRLM0NQRVU2dW9uMDQ1amhyd1N1dGNVa3llMUZVcnF6aWNTa1luZjhnVFdOMmtlCnpUdWJ5OUowcVZFRVErc2cvU2Q1bERVUm9LSHAyVXRLZzdrbVRzT3d3U2ppVnlVZEdmMGcrZ2djUU9iMjFvNVgKYUtoOUtIQUdBVDRvQnlOdTY0STJEaWV0QkRkWWdsL3B5cTgwcCtwVTlLSDJObEZrMERhc01uU2I0eEE1M2U3RApJQVJua0JGOFNuSXR2a3pacFFTVWhXNVpJT2IvdjdOcWZxalhuTE8rdUx4czRPSllXL3V5TzBpMEkrYUF5RWRYClUyUkMzZjIyUHV1VmNnWmZ6ck5vUzU5dnQwVVlVM1FRcURqMgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
  namespace: ZGVmYXVsdA==
  token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklraDZZMnB4VlhCbk5ubFBVa3AxVVZwblYwbGthMmhOZG14TVpHeHdOa1pGVFdvMVFXUkhjbUpPWldNaWZRLmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUprWldaaGRXeDBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5elpXTnlaWFF1Ym1GdFpTSTZJbmRoYm1kamN5MXpZUzEwYjJ0bGJpMWlObUpzWXlJc0ltdDFZbVZ5Ym1WMFpYTXVhVzh2YzJWeWRtbGpaV0ZqWTI5MWJuUXZjMlZ5ZG1salpTMWhZMk52ZFc1MExtNWhiV1VpT2lKM1lXNW5ZM010YzJFaUxDSnJkV0psY201bGRHVnpMbWx2TDNObGNuWnBZMlZoWTJOdmRXNTBMM05sY25acFkyVXRZV05qYjNWdWRDNTFhV1FpT2lJNU9EZ3pPV1kxT0MweE5EZG1MVFEzWm1NdE9HVXlaQzFoTjJRMk1HRmtOakUyWVRNaUxDSnpkV0lpT2lKemVYTjBaVzA2YzJWeWRtbGpaV0ZqWTI5MWJuUTZaR1ZtWVhWc2REcDNZVzVuWTNNdGMyRWlmUS5BRl85T1hWd1pkeGVnckRSYWtXYjFrYWM3YmVlclBNTE03T2IwU3JiN2pPcFl4VzdMQllxNkpqNUE5NWxRQm9Yd3haQ09WLUtsYUZxSDc2RnZBRnFYX2taWE5XdWFkeElIZzhkWmVwWl9HbnJwYXBSeFFZZVlsbGRFR3BRdHZZSXdqLUsxRE9xMEprYnM3TW55dGUtcDE0WWxDWGZrdGp2NnVlaDEtcHZnRWRhbjdlS2xjNldwaFFvNnNRUm8xNmppc1VINkRvYU5FdXIxcGpXWVRHSlpuZ2tmQVU2QkNnV1lkRDd1MmwwZnV5dXh0Z2RyM0V1cHBmSVc1Wk5DQVBBbVU3SWRFd3JBVWJtWW5jZ3JyeTNaQWsxR1ctbnlpa0tWTmNNa29NTFAxejIwdHlQWUFaUkVHOTdSWkRhd1JQM1NvSXlIZTRxM245V1hhN0QxdjhSM1E=
kind: Secret
...

对token进行base64解密

echo -n "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklraDZZMnB4VlhCbk5ubFBVa3AxVVZwblYwbGthMmhOZG14TVpHeHdOa1pGVFdvMVFXUkhjbUpPWldNaWZRLmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUprWldaaGRXeDBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5elpXTnlaWFF1Ym1GdFpTSTZJbmRoYm1kamN5MXpZUzEwYjJ0bGJpMWlObUpzWXlJc0ltdDFZbVZ5Ym1WMFpYTXVhVzh2YzJWeWRtbGpaV0ZqWTI5MWJuUXZjMlZ5ZG1salpTMWhZMk52ZFc1MExtNWhiV1VpT2lKM1lXNW5ZM010YzJFaUxDSnJkV0psY201bGRHVnpMbWx2TDNObGNuWnBZMlZoWTJOdmRXNTBMM05sY25acFkyVXRZV05qYjNWdWRDNTFhV1FpT2lJNU9EZ3pPV1kxT0MweE5EZG1MVFEzWm1NdE9HVXlaQzFoTjJRMk1HRmtOakUyWVRNaUxDSnpkV0lpT2lKemVYTjBaVzA2YzJWeWRtbGpaV0ZqWTI5MWJuUTZaR1ZtWVhWc2REcDNZVzVuWTNNdGMyRWlmUS5BRl85T1hWd1pkeGVnckRSYWtXYjFrYWM3YmVlclBNTE03T2IwU3JiN2pPcFl4VzdMQllxNkpqNUE5NWxRQm9Yd3haQ09WLUtsYUZxSDc2RnZBRnFYX2taWE5XdWFkeElIZzhkWmVwWl9HbnJwYXBSeFFZZVlsbGRFR3BRdHZZSXdqLUsxRE9xMEprYnM3TW55dGUtcDE0WWxDWGZrdGp2NnVlaDEtcHZnRWRhbjdlS2xjNldwaFFvNnNRUm8xNmppc1VINkRvYU5FdXIxcGpXWVRHSlpuZ2tmQVU2QkNnV1lkRDd1MmwwZnV5dXh0Z2RyM0V1cHBmSVc1Wk5DQVBBbVU3SWRFd3JBVWJtWW5jZ3JyeTNaQWsxR1ctbnlpa0tWTmNNa29NTFAxejIwdHlQWUFaUkVHOTdSWkRhd1JQM1NvSXlIZTRxM245V1hhN0QxdjhSM1E="|base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6Ikh6Y2pxVXBnNnlPUkp1UVpnV0lka2hNdmxMZGxwNkZFTWo1QWRHcmJOZWMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Indhbmdjcy1zYS10b2tlbi1iNmJsYyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ3YW5nY3Mtc2EiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5ODgzOWY1OC0xNDdmLTQ3ZmMtOGUyZC1hN2Q2MGFkNjE2YTMiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDp3YW5nY3Mtc2EifQ.AF_9OXVwZdxegrDRakWb1kac7beerPMLM7Ob0Srb7jOpYxW7LBYq6Jj5A95lQBoXwxZCOV-KlaFqH76FvAFqX_kZXNWuadxIHg8dZepZ_GnrpapRxQYeYlldEGpQtvYIwj-K1DOq0Jkbs7Mnyte-p14YlCXfktjv6ueh1-pvgEdan7eKlc6WphQo6sQRo16jisUH6DoaNEur1pjWYTGJZngkfAU6BCgWYdD7u2l0fuyuxtgdr3EuppfIW5ZNCAPAmU7IdEwrAUbmYncgrry3ZAk1GW-nyikKVNcMkoMLP1z20tyPYAZREG97RZDawRP3SoIyHe4q3n9WXa7D1v8R3Q

接下来,使用这个token 对apiserver发起请求 https://{apiserver ip}:6443/api/v1/namespaces/default/pods

curl -k -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ikh6Y2pxVXBnNnlPUkp1UVpnV0lka2hNdmxMZGxwNkZFTWo1QWRHcmJOZWMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Indhbmdjcy1zYS10b2tlbi1iNmJsYyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ3YW5nY3Mtc2EiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5ODgzOWY1OC0xNDdmLTQ3ZmMtOGUyZC1hN2Q2MGFkNjE2YTMiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDp3YW5nY3Mtc2EifQ.AF_9OXVwZdxegrDRakWb1kac7beerPMLM7Ob0Srb7jOpYxW7LBYq6Jj5A95lQBoXwxZCOV-KlaFqH76FvAFqX_kZXNWuadxIHg8dZepZ_GnrpapRxQYeYlldEGpQtvYIwj-K1DOq0Jkbs7Mnyte-p14YlCXfktjv6ueh1-pvgEdan7eKlc6WphQo6sQRo16jisUH6DoaNEur1pjWYTGJZngkfAU6BCgWYdD7u2l0fuyuxtgdr3EuppfIW5ZNCAPAmU7IdEwrAUbmYncgrry3ZAk1GW-nyikKVNcMkoMLP1z20tyPYAZREG97RZDawRP3SoIyHe4q3n9WXa7D1v8R3Q" "https://172.17.114.33:6443/api/v1/namespaces/default/pods"
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces/default/pods",
    "resourceVersion": "9141416"
  },
  "items": [
    {
      "metadata": {
        "name": "nginx-deploy-75c7f965d8-hnmvn",
        "generateName": "nginx-deploy-75c7f965d8-",
        "namespace": "default",
        "selfLink": "/api/v1/namespaces/default/pods/nginx-deploy-75c7f965d8-hnmvn",
        "uid": "574ac979-41b8-460f-afaf-d29155911ba3",
        "resourceVersion": "6786396",
        "creationTimestamp": "2021-05-10T03:30:07Z",
        "labels": {
          "app": "nginx",
          "pod-template-hash": "75c7f965d8"
        },
   ...   

我们看是可以访问到default 命名空间的pod list,符合预期
接下来,使用这个token 对apiserver发起请求 https://{apiserver ip}:6443/api/v1/namespaces/kube-system/pods,访问kube-system命名空间下的pod list

[root@k8s-master ~]# curl -k -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ikh6Y2pxVXBnNnlPUkp1UVpnV0lka2hNdmxMZGxwNkZFTWo1QWRHcmJOZWMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Indhbmdjcy1zYS10b2tlbi1iNmJsYyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ3YW5nY3Mtc2EiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5ODgzOWY1OC0xNDdmLTQ3ZmMtOGUyZC1hN2Q2MGFkNjE2YTMiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDp3YW5nY3Mtc2EifQ.AF_9OXVwZdxegrDRakWb1kac7beerPMLM7Ob0Srb7jOpYxW7LBYq6Jj5A95lQBoXwxZCOV-KlaFqH76FvAFqX_kZXNWuadxIHg8dZepZ_GnrpapRxQYeYlldEGpQtvYIwj-K1DOq0Jkbs7Mnyte-p14YlCXfktjv6ueh1-pvgEdan7eKlc6WphQo6sQRo16jisUH6DoaNEur1pjWYTGJZngkfAU6BCgWYdD7u2l0fuyuxtgdr3EuppfIW5ZNCAPAmU7IdEwrAUbmYncgrry3ZAk1GW-nyikKVNcMkoMLP1z20tyPYAZREG97RZDawRP3SoIyHe4q3n9WXa7D1v8R3Q" "https://172.17.114.33:6443/api/v1/namespaces/kube-system/pods"
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
    
  },
  "status": "Failure",
  "message": "pods is forbidden: User \\"system:serviceaccount:default:wangcs-sa\\" cannot list resource \\"pods\\" in API group \\"\\" in the namespace \\"kube-system\\"",
  "reason": "Forbidden",
  "details": {
    "kind": "pods"
  },
  "code": 403
}

返回403没有权限,符合预期

可以全局访问的 ServiceAccount

刚刚我们创建的 wangcs-sa 这个 ServiceAccount 和一个 Role 角色进行绑定的,如果我们现在创建一个新的 ServiceAccount,需要他操作的权限作用于所有的 namespace,这个时候我们就需要使用到 ClusterRole 和 ClusterRoleBinding 这两种资源对象了。同样,首先新建一个 ServiceAcount 对象:(wangcs-sa2.yaml)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: wangcs-sa2
  namespace: default

创建:

[root@k8s-master k8s-rbac]# kubectl apply -f wangcs-sa2.yaml 
serviceaccount/wangcs-sa2 created

然后创建一个 ClusterRoleBinding 对象(wangcs-clusterolebinding.yaml):

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: wangcs-sa2-clusterrolebinding
subjects:
- kind: ServiceAccount
  name: wangcs-sa2
  namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

从上面我们可以看到我们没有为这个资源对象声明 namespace,因为这是一个 ClusterRoleBinding 资源对象,是作用于整个集群的,我们也没有单独新建一个 ClusterRole 对象,而是使用的 cluster-admin 这个对象,这是 Kubernetes 集群内置的 ClusterRole 对象,我们可以使用 kubectl get clusterrole 和 kubectl get clusterrolebinding 查看系统内置的一些集群角色和集群角色绑定,这里我们使用的 cluster-admin 这个集群角色是拥有最高权限的集群角色,所以一般需要谨慎使用该集群角色。

创建:

kubectl apply -f wangcs-clusterolebinding.yaml 
Warning: rbac.authorization.k8s.io/v1beta1 ClusterRoleBinding is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRoleBinding
clusterrolebinding.rbac.authorization.k8s.io/wangcs-sa2-clusterrolebinding created

测试:

接下来,使用这个wangcs-sa2 对应的secret的token 对apiserver发起请求 https://{apiserver ip}:6443/api/v1/pods
!

[root@k8s-master k8s-rbac]# curl -k -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ikh6Y2pxVXBnNnlPUkp1UVpnV0lka2hNdmxMZGxwNkZFTWo1QWRHcmJOZWMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Indhbmdjcy1zYTItdG9rZW4tdHQ1d2oiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoid2FuZ2NzLXNhMiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjU3ZDU4M2JiLWMwNWUtNDU2NC04ZDQwLTIxOWJlMGM2NzBmMiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0Ondhbmdjcy1zYTIifQ.YIYq33Ww8X8NNwjk_P-4IcV95e7j__aIv-2EX8AicsB_o2kwbfUvoe1Rgx8mN7MErRul46PgKshGL62C4D9pvZFi7H0BeFnY2CsUbYMIIHlEF_IhhKZLkXIbhgcQa8EzAa4KRkgcfO4ULPezO2EnLp-NPt4RABxaAa0aMbkYKgwL-ILCGKbNBQmrWASNcfgfjCavOZXW_hhyLIy_uO3PsCMP4k_T_Tv3lKOYzd8JnKLp1b1ytLrYBtinGYHgJHQB48XnNi8a-gL8rtp5GuDzOf_cQj43Fdub2yRtcNYgkLt6nAxlqNHV1ENjPxUYpJzqzsE5BWhcZQT6bZuyBlWobA" "https://172.17.114.33:6443/api/v1/pods"|more
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/pods",
    "resourceVersion": "9143830"
  },
  "items": [
    {
      "metadata": {
        "name": "nginx-deploy-75c7f965d8-hnmvn",
        "generateName": "nginx-deploy-75c7f965d8-",
        "namespace": "default",
        "selfLink": "/api/v1/namespaces/default/pods/nginx-deploy-75c7f965d8-hnmvn",
        "uid": "574ac979-41b8-460f-afaf-d29155911ba3",
        "resourceVersion": "6786396",
        "creationTimestamp": "2021-05-10T03:30:07Z",
        "labels": {
          "app": "nginx",
          "pod-template-hash": "75c7f965d8"
        },
  ...      

所有命名空间下的pod list都能够查询出来,符合预期

以上是关于Kubernetes认证鉴权的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes 安全权限管理深度剖析

Kubernetes入门至精通 | Kubernetes集群安全 - 鉴权

Kubernetes入门至精通 Kubernetes集群安全 - 鉴权

Kubernetes——安全认证

26-Kubernetes-安全认证

Kubernetes十九安全认证