k8s之RBAC

本节实战

实战名称
💘 实战查看k8s里api对象-2023.1.18(测试成功)
💘 实战1只能访问某个 namespace 的普通用户-2023.2.3(测试成功)openssl
💘 实战2只能访问某个 namespace 的普通用户-2023.2.6(测试成功)cfgssl
💘 实战<=1.20 k8s版本sa测试-2023.1.18(测试成功)
💘 实战>=1.21版本 && <=1.23版本sa测试-2023.1.18(测试成功)
💘 实战>=1.24版本sa测试-2023.2.5(测试成功)
💘 实战为 ServiceAccount 分配权限-2023.2.5(测试成功)
💘 实战cka-rbac考试题-创建sa并赋予权限-2023.2.6(测试成功)
💘 实战可以全局访问的 ServiceAccount-2023.2.5(测试成功)

前言

前面我们已经学习一些常用的资源对象的使用我们知道对于资源对象的操作都是通过 APIServer 进行的那么集群是怎样知道我们的请求就是合法的请求呢这个就需要了解 Kubernetes 中另外一个非常重要的知识点了RBAC基于角色的权限控制

管理员可以通过 Kubernetes API 动态配置策略来启用 RBAC 需要在 kube-apiserver 中添加参数--authorization-mode=RBAC如果使用的 kubeadm 安装的集群那么是默认开启了 RBAC 的可以通过查看 Master节点上 apiserver 的静态 Pod 定义文件

☸ ➜ cat /etc/kubernetes/manifests/kube-apiserver.yaml
……
	- --authorization-mode=Node,RBAC
……

如果是二进制的方式搭建的集群添加这个参数过后记得要重启 kube-apiserver 服务。

1、API对象

在学习 RBAC 之前我们还需要再去理解下 Kubernetes 集群中的对象。我们知道在 Kubernetes 集群中Kubernetes 对象是我们持久化的实体就是最终存入 etcd 中的数据集群中通过这些实体来表示整个集群的状态。前面我们都直接编写的 YAML 文件通过 kubectl 来提交的资源清单文件然后创建的对应的资源对象那么它究竟是如何将我们的 YAML 文件转换成集群中的一个 API 对象的呢

这个就需要去了解下声明式 API的设计Kubernetes API 是一个以 JSON 为主要序列化方式的 HTTP 服务(可以理解为一个webserver)除此之外也支持 Protocol Buffers 序列化方式主要用于集群内部组件间的通信。为了可扩展性Kubernetes 在不同的 API 路径比如/api/v1 或者 /apis/batch下面支持了多个 API 版本不同的 API 版本意味着不同级别的稳定性和支持

  • Alpha 级别例如 v1alpha1 默认情况下是被禁用的可以随时删除对功能的支持所以要慎用;

  • Beta 级别例如 v2beta1 默认情况下是启用的表示代码已经经过了很好的测试但是对象的语义可能会在随后的版本中以不兼容的方式更改;

  • 稳定级别比如 v1 表示已经是稳定版本了也会出现在后续的很多版本中;

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

image-20230118071807336

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

比如我们来查看批处理这个操作在我们当前这个版本中存在两个版本的操作/apis/batch/v1/apis/batch/v1beta1分别暴露了可以查询和操作的不同实体集合。

通常Kubernetes API 支持通过标准 HTTP POSTPUTDELETEGET 在指定 PATH 路径上创建、更新、删除和检索操作并使用 JSON 作为默认的数据交互格式。比如现在我们要创建一个 Deployment 对象那么我们的 YAML 文件的声明就需要怎么写

apiVersion: apps/v1
kind: Deployment

其中 Deployment 就是这个 API 对象的资源类型Resourceapps 就是它的组Groupv1 就是它的版本Version。API Group、Version 和 资源就唯一定义了一个 HTTP 路径然后在 kube-apiserver 端对这个 url 进行了监听然后把对应的请求传递给了对应的控制器进行处理而已当然在 Kuberentes 中的实现过程是非常复杂的。

💘 实战查看k8s里api对象-2023.1.18(测试成功)

image-20230118071807336

  • 实验环境
实验环境
1、win10,vmwrokstation虚机
2、k8s集群3台centos7.6 1810虚机1个master节点,2个node节点
   k8s versionv1.25.4
   containerd://1.6.10
  • 实验软件无

  • 我们也可以用下面的命令来查看集群中的 API 组织形式

[root@master1 ~]#kubectl get --raw /
{
  "paths": [
    "/.well-known/openid-configuration",
    "/api",
    "/api/v1",
    "/apis",
    "/apis/",
    "/apis/admissionregistration.k8s.io",
    "/apis/admissionregistration.k8s.io/v1",
    "/apis/apiextensions.k8s.io",
    "/apis/apiextensions.k8s.io/v1",
    "/apis/apiregistration.k8s.io",
    "/apis/apiregistration.k8s.io/v1",
    "/apis/apps",
    "/apis/apps/v1",
    "/apis/authentication.k8s.io",
    "/apis/authentication.k8s.io/v1",
    "/apis/authorization.k8s.io",
    "/apis/authorization.k8s.io/v1",
    "/apis/autoscaling",
    "/apis/autoscaling/v1",
    "/apis/autoscaling/v2beta1",
    "/apis/autoscaling/v2beta2",
    "/apis/batch",
    "/apis/batch/v1",
    "/apis/batch/v1beta1",
    "/apis/certificates.k8s.io",
    "/apis/certificates.k8s.io/v1",
    "/apis/coordination.k8s.io",
    "/apis/coordination.k8s.io/v1",
    "/apis/discovery.k8s.io",
    "/apis/discovery.k8s.io/v1",
    "/apis/discovery.k8s.io/v1beta1",
    "/apis/events.k8s.io",
    "/apis/events.k8s.io/v1",
    "/apis/events.k8s.io/v1beta1",
    "/apis/flowcontrol.apiserver.k8s.io",
    "/apis/flowcontrol.apiserver.k8s.io/v1beta1",
    "/apis/metrics.k8s.io",
    "/apis/metrics.k8s.io/v1beta1",
    "/apis/networking.k8s.io",
    "/apis/networking.k8s.io/v1",
    "/apis/node.k8s.io",
    "/apis/node.k8s.io/v1",
    "/apis/node.k8s.io/v1beta1",
    "/apis/policy",
    "/apis/policy/v1",
    "/apis/policy/v1beta1",
    "/apis/rbac.authorization.k8s.io",
    "/apis/rbac.authorization.k8s.io/v1",
    "/apis/scheduling.k8s.io",
    "/apis/scheduling.k8s.io/v1",
    "/apis/storage.k8s.io",
    "/apis/storage.k8s.io/v1",
    "/apis/storage.k8s.io/v1beta1",
    "/healthz",
    "/healthz/autoregister-completion",
    "/healthz/etcd",
    "/healthz/log",
    "/healthz/ping",
    "/healthz/poststarthook/aggregator-reload-proxy-client-cert",
    "/healthz/poststarthook/apiservice-openapi-controller",
    "/healthz/poststarthook/apiservice-registration-controller",
    "/healthz/poststarthook/apiservice-status-available-controller",
    "/healthz/poststarthook/bootstrap-controller",
    "/healthz/poststarthook/crd-informer-synced",
    "/healthz/poststarthook/generic-apiserver-start-informers",
    "/healthz/poststarthook/kube-apiserver-autoregistration",
    "/healthz/poststarthook/priority-and-fairness-config-consumer",
    "/healthz/poststarthook/priority-and-fairness-config-producer",
    "/healthz/poststarthook/priority-and-fairness-filter",
    "/healthz/poststarthook/rbac/bootstrap-roles",
    "/healthz/poststarthook/scheduling/bootstrap-system-priority-classes",
    "/healthz/poststarthook/start-apiextensions-controllers",
    "/healthz/poststarthook/start-apiextensions-informers",
    "/healthz/poststarthook/start-cluster-authentication-info-controller",
    "/healthz/poststarthook/start-kube-aggregator-informers",
    "/healthz/poststarthook/start-kube-apiserver-admission-initializer",
    "/livez",
    "/livez/autoregister-completion",
    "/livez/etcd",
    "/livez/log",
    "/livez/ping",
    "/livez/poststarthook/aggregator-reload-proxy-client-cert",
    "/livez/poststarthook/apiservice-openapi-controller",
    "/livez/poststarthook/apiservice-registration-controller",
    "/livez/poststarthook/apiservice-status-available-controller",
    "/livez/poststarthook/bootstrap-controller",
    "/livez/poststarthook/crd-informer-synced",
    "/livez/poststarthook/generic-apiserver-start-informers",
    "/livez/poststarthook/kube-apiserver-autoregistration",
    "/livez/poststarthook/priority-and-fairness-config-consumer",
    "/livez/poststarthook/priority-and-fairness-config-producer",
    "/livez/poststarthook/priority-and-fairness-filter",
    "/livez/poststarthook/rbac/bootstrap-roles",
    "/livez/poststarthook/scheduling/bootstrap-system-priority-classes",
    "/livez/poststarthook/start-apiextensions-controllers",
    "/livez/poststarthook/start-apiextensions-informers",
    "/livez/poststarthook/start-cluster-authentication-info-controller",
    "/livez/poststarthook/start-kube-aggregator-informers",
    "/livez/poststarthook/start-kube-apiserver-admission-initializer",
    "/logs",
    "/metrics",
    "/openapi/v2",
    "/openid/v1/jwks",
    "/readyz",
    "/readyz/autoregister-completion",
    "/readyz/etcd",
    "/readyz/informer-sync",
    "/readyz/log",
    "/readyz/ping",
    "/readyz/poststarthook/aggregator-reload-proxy-client-cert",
    "/readyz/poststarthook/apiservice-openapi-controller",
    "/readyz/poststarthook/apiservice-registration-controller",
    "/readyz/poststarthook/apiservice-status-available-controller",
    "/readyz/poststarthook/bootstrap-controller",
    "/readyz/poststarthook/crd-informer-synced",
    "/readyz/poststarthook/generic-apiserver-start-informers",
    "/readyz/poststarthook/kube-apiserver-autoregistration",
    "/readyz/poststarthook/priority-and-fairness-config-consumer",
    "/readyz/poststarthook/priority-and-fairness-config-producer",
    "/readyz/poststarthook/priority-and-fairness-filter",
    "/readyz/poststarthook/rbac/bootstrap-roles",
    "/readyz/poststarthook/scheduling/bootstrap-system-priority-classes",
    "/readyz/poststarthook/start-apiextensions-controllers",
    "/readyz/poststarthook/start-apiextensions-informers",
    "/readyz/poststarthook/start-cluster-authentication-info-controller",
    "/readyz/poststarthook/start-kube-aggregator-informers",
    "/readyz/poststarthook/start-kube-apiserver-admission-initializer",
    "/readyz/shutdown",
    "/version"
  ]
}
[root@master1 ~]#
  • 同样我们还是可以通过 kubectl 来查询对应对象下面的数据
[root@master1 ~]#kubectl get --raw /apis/batch/v1 | python -m json.tool
{
    "apiVersion": "v1",
    "groupVersion": "batch/v1",
    "kind": "APIResourceList",
    "resources": [
        {
            "categories": [
                "all"
            ],
            "kind": "CronJob",
            "name": "cronjobs",
            "namespaced": true,
            "shortNames": [
                "cj"
            ],
            "singularName": "",
            "storageVersionHash": "sd5LIXh4Fjs=",
            "verbs": [
                "create",
                "delete",
                "deletecollection",
                "get",
                "list",
                "patch",
                "update",
                "watch"
            ]
        },
        {
            "kind": "CronJob",
            "name": "cronjobs/status",
            "namespaced": true,
            "singularName": "",
            "verbs": [
                "get",
                "patch",
                "update"
            ]
        },
        {
            "categories": [
                "all"
            ],
            "kind": "Job",
            "name": "jobs",
            "namespaced": true,
            "singularName": "",
            "storageVersionHash": "mudhfqk/qZY=",
            "verbs": [
                "create",
                "delete",
                "deletecollection",
                "get",
                "list",
                "patch",
                "update",
                "watch"
            ]
        },
        {
            "kind": "Job",
            "name": "jobs/status",
            "namespaced": true,
            "singularName": "",
            "verbs": [
                "get",
                "patch",
                "update"
            ]
        }
    ]
}


[root@master1 ~]#kubectl get --raw /apis/batch/v1beta1 | python -m json.tool
{
    "apiVersion": "v1",
    "groupVersion": "batch/v1beta1",
    "kind": "APIResourceList",
    "resources": [
        {
            "categories": [
                "all"
            ],
            "kind": "CronJob",
            "name": "cronjobs",
            "namespaced": true,
            "shortNames": [
                "cj"
            ],
            "singularName": "",
            "storageVersionHash": "sd5LIXh4Fjs=",
            "verbs": [
                "create",
                "delete",
                "deletecollection",
                "get",
                "list",
                "patch",
                "update",
                "watch"
            ]
        },
        {
            "kind": "CronJob",
            "name": "cronjobs/status",
            "namespaced": true,
            "singularName": "",
            "verbs": [
                "get",
                "patch",
                "update"
            ]
        }
    ]
}
[root@master1 ~]#
  • 但是这个操作和我们平时操作 HTTP 服务的方式不太一样这里我们可以通过 kubectl proxy 命令来开启对 apiserver 的访问

现在我们知道了 API Server 可以通过 URI 的形式访问到资源我们可以通过 kubectl proxy 来代理一个本地的API Server 端口这样就可以绕过认证了直接可以以 http 的形式进行

[root@master1 ~]#kubectl proxy
Starting to serve on 127.0.0.1:8001
  • 然后重新开启一个新的终端我们可以通过如下方式来访问批处理的 API 服务
[root@master1 ~]#curl http://127.0.0.1:8001/apis/batch/v1
{
  "kind": "APIResourceList",
  "apiVersion": "v1",
  "groupVersion": "batch/v1",
  "resources": [
    {
      "name": "cronjobs",
      "singularName": "",
      "namespaced": true,
      "kind": "CronJob",
      "verbs": [
        "create",
        "delete",
        "deletecollection",
        "get",
        "list",
        "patch",
        "update",
        "watch"
      ],
      "shortNames": [
        "cj"
      ],
      "categories": [
        "all"
      ],
      "storageVersionHash": "sd5LIXh4Fjs="
    },
    {
      "name": "cronjobs/status",
      "singularName": "",
      "namespaced": true,
      "kind": "CronJob",
      "verbs": [
        "get",
        "patch",
        "update"
      ]
    },
    {
      "name": "jobs",
      "singularName": "",
      "namespaced": true,
      "kind": "Job",
      "verbs": [
        "create",
        "delete",
        "deletecollection",
        "get",
        "list",
        "patch",
        "update",
        "watch"
      ],
      "categories": [
        "all"
      ],
      "storageVersionHash": "mudhfqk/qZY="
    },
    {
      "name": "jobs/status",
      "singularName": "",
      "namespaced": true,
      "kind": "Job",
      "verbs": [
        "get",
        "patch",
        "update"
      ]
    }
  ]
}[root@master1 ~]#
  • 同样也可以去访问另外一个版本的对象数据
[root@master1 ~]#curl http://127.0.0.1:8001/apis/batch/v1beta1
{
  "kind": "APIResourceList",
  "apiVersion": "v1",
  "groupVersion": "batch/v1beta1",
  "resources": [
    {
      "name": "cronjobs",
      "singularName": "",
      "namespaced": true,
      "kind": "CronJob",
      "verbs": [
        "create",
        "delete",
        "deletecollection",
        "get",
        "list",
        "patch",
        "update",
        "watch"
      ],
      "shortNames": [
        "cj"
      ],
      "categories": [
        "all"
      ],
      "storageVersionHash": "sd5LIXh4Fjs="
    },
    {
      "name": "cronjobs/status",
      "singularName": "",
      "namespaced": true,
      "kind": "CronJob",
      "verbs": [
        "get",
        "patch",
        "update"
      ]
    }
  ]
}[root@master1 ~]#
  • 我们就可以直接访问 API Server 了

image-20230201212742134

  • 如果想看系统支持哪些 GVK 那么可以通过 kubectl 的命令查看
[root@master1 ~]#kubectl api-resources
NAME                               SHORTNAMES      APIVERSION                             NAMESPACED   KIND
bindings                                           v1                                     true         Binding
componentstatuses                  cs              v1                                     false        ComponentStatus
configmaps                         cm              v1                                     true         ConfigMap
endpoints                          ep              v1                                     true         Endpoints
events                             ev              v1                                     true         Event
limitranges                        limits          v1                                     true         LimitRange
namespaces                         ns              v1                                     false        Namespace
nodes                              no              v1                                     false        Node
persistentvolumeclaims             pvc             v1                                     true         PersistentVolumeClaim
persistentvolumes                  pv              v1                                     false        PersistentVolume
pods                               po              v1                                     true         Pod
podtemplates                                       v1                                     true         PodTemplate
replicationcontrollers             rc              v1                                     true         ReplicationController
resourcequotas                     quota           v1                                     true         ResourceQuota
secrets                                            v1                                     true         Secret
serviceaccounts                    sa              v1                                     true         ServiceAccount
services                           svc             v1                                     true         Service
mutatingwebhookconfigurations                      admissionregistration.k8s.io/v1        false        MutatingWebhookConfiguration
validatingwebhookconfigurations                    admissionregistration.k8s.io/v1        false        ValidatingWebhookConfiguration
customresourcedefinitions          crd,crds        apiextensions.k8s.io/v1                false        CustomResourceDefinition
apiservices                                        apiregistration.k8s.io/v1              false        APIService
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
tokenreviews                                       authentication.k8s.io/v1               false        TokenReview
localsubjectaccessreviews                          authorization.k8s.io/v1                true         LocalSubjectAccessReview
selfsubjectaccessreviews                           authorization.k8s.io/v1                false        SelfSubjectAccessReview
selfsubjectrulesreviews                            authorization.k8s.io/v1                false        SelfSubjectRulesReview
subjectaccessreviews                               authorization.k8s.io/v1                false        SubjectAccessReview
horizontalpodautoscalers           hpa             autoscaling/v2                         true         HorizontalPodAutoscaler
verticalpodautoscalercheckpoints   vpacheckpoint   autoscaling.k8s.io/v1                  true         VerticalPodAutoscalerCheckpoint
verticalpodautoscalers             vpa             autoscaling.k8s.io/v1                  true         VerticalPodAutoscaler
cronjobs                           cj              batch/v1                               true         CronJob
jobs                                               batch/v1                               true         Job
certificatesigningrequests         csr             certificates.k8s.io/v1                 false        CertificateSigningRequest
leases                                             coordination.k8s.io/v1                 true         Lease
endpointslices                                     discovery.k8s.io/v1                    true         EndpointSlice
events                             ev              events.k8s.io/v1                       true         Event
flowschemas                                        flowcontrol.apiserver.k8s.io/v1beta2   false        FlowSchema
prioritylevelconfigurations                        flowcontrol.apiserver.k8s.io/v1beta2   false        PriorityLevelConfiguration
nodes                                              metrics.k8s.io/v1beta1                 false        NodeMetrics
pods                                               metrics.k8s.io/v1beta1                 true         PodMetrics
ingressclasses                                     networking.k8s.io/v1                   false        IngressClass
ingresses                          ing             networking.k8s.io/v1                   true         Ingress
networkpolicies                    netpol          networking.k8s.io/v1                   true         NetworkPolicy
runtimeclasses                                     node.k8s.io/v1                         false        RuntimeClass
poddisruptionbudgets               pdb             policy/v1                              true         PodDisruptionBudget
clusterrolebindings                                rbac.authorization.k8s.io/v1           false        ClusterRoleBinding
clusterroles                                       rbac.authorization.k8s.io/v1           false        ClusterRole
rolebindings                                       rbac.authorization.k8s.io/v1           true         RoleBinding
roles                                              rbac.authorization.k8s.io/v1           true         Role
priorityclasses                    pc              scheduling.k8s.io/v1                   false        PriorityClass
csidrivers                                         storage.k8s.io/v1                      false        CSIDriver
csinodes                                           storage.k8s.io/v1                      false        CSINode
csistoragecapacities                               storage.k8s.io/v1                      true         CSIStorageCapacity
storageclasses                     sc              storage.k8s.io/v1                      false        StorageClass
volumeattachments                                  storage.k8s.io/v1                      false        VolumeAttachment
[root@master1 ~]#

这里我们可以发现一些特别的地方对于 Pod 和 Service它的 API GROUP 居然是空的这其实就是 Kubernetes核心core资源的含义也就是所谓的 Kubernetes 中的基础资源他们不需要 Group只有 Version 和Kind 其实主要是历史原因导致的在 Kubernetes 的开始之初还不支持自定义类型的时候就没考虑过 Group。

测试结束。😘

🍀 备注

api-server就是一个webserver。

image-20230118065658892

image-20230118070243256

image-20230118070323754

image-20230118070732948

1.GVK

我们知道要表达一个资源对象需要指定 group/kind 和 version 这个在 Kubernetes 的 API Server 中简称为GVKGVK 是定位一种类型的方式例如 daemonsets 就是 Kubernetes 中的一种资源当我们跟 Kubernetes 说我想要创建一个 daemonsets 的时候kubectl 是如何知道该怎么向 API Server 发送请求呢是所有的不同资源都发向同一个 Endpoint还是每种资源都是不同的

我们回顾下定义的 daemonsets 的资源清单文件

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: kube-system
spec:
# ......

这里声明的 apiVersion 是 apps/v1 其实就是隐含了 Group 是 apps Version 是 v1 Kind 就是定义的DaemonSet而 kubectl 接收到这个清单之后就可以根据这个声明去调用 API Server 对应的 URL 去获取信息例如这里就是 /api/apps/v1/daemonset 。所以我们说 Kubernetes 组织资源的方式是以 REST 的 URI 的形式来的而组织的路径就是

image-20230201210651724

我们这里不是说是 G(roup)V(ersion)K(ind) 吗怎么现在又变成了 G(roup)V(ersion)R(esource) 这就是API Server 中的第二个概念 GVR。

2.GVR

理解了 GVK 之后再理解 GVR 就很容易了这就是面向对象编程里面的类和对象的概念是一样的

image-20230201212108767

Kind 其实就是一个类用于描述对象的而 Resource 就是具体的 Kind可以理解成类已经实例化成对象了。Resource 只是 API 中的一个 Kind 的使用方式通常情况下 Kind 和 Resource 之间有一个一对一的映射。例如pods 资源对应于 Pod 种类但是有时同一类型可能由多个资源返回。例如 Scale Kind 是由所有 scale 子资源返回的如 deployments/scale 或 replicasets/scale这就是允许 KubernetesHorizontalPodAutoscaler(HPA) 与不同资源交互的原因。

当我们要定义一个 GVR 的时候那么怎么知道这个 GVR 是属于哪个 GVK 的呢也就是前面说的kubectl 是如何从YAML 资源清单文件中知道该请求的是哪个 GVR 路径的这就是 REST Mapping 的功能 REST Mapping 可以指定一个 GVR 例如 daemonset 的这个例子然后它返回对应的 GVK 以及支持的操作等。

在代码中其实就对应于这个接口

image-20230201212351570

这样就把 GVK 和 GVR 联系起来了。

noResources

image-20230202204824171

image-20230202204835457

如何确定某个资源对象属于哪个apiGroup呢

方法1kubectl explains命令

[root@master1 rbac]#kubectl explain pod
KIND:     Pod
VERSION:  v1
……

方法2kubectl api-resource命令

[root@master1 rbac]#kubectl api-resources |head -1;kubectl api-resources |grep pods
NAME                              SHORTNAMES   APIVERSION                             NAMESPACED   KIND
pods                              po           v1                                     true         Pod
pods                                           metrics.k8s.io/v1beta1                 true         PodMetrics
podsecuritypolicies               psp          policy/v1beta1                         false        PodSecurityPolicy
[root@master1 rbac]#

image-20230202205116622

2、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 属于 appsAPI 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。

⚠️ 注意

rolebinding是绑定某个命名空间的
clusterrolebinding是针对all命名空间的
正常情况下我们创建一个role 就对应一个rolebinding。我们创建一个clusterrole 就对应一个clusterrolebinding;

image-20230202211426451

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

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

💘 实战1只能访问某个 namespace 的普通用户-2023.2.3(测试成功)openssl

image-20230203075216847

  • 实验环境
实验环境
1、win10,vmwrokstation虚机
2、k8s集群3台centos7.6 1810虚机1个master节点,2个node节点
   k8s versionv1.25.4
   containerd://1.6.10
  • 实验软件无
  • 实验步骤
1.创建用户凭证
2.创建角色
3.创建角色权限绑定
4.测试

1、创建用户凭证

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

username: cnych
group: youdianzhishi

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

  • 给用户 cnych 创建一个私钥命名成 cnych.key
[root@master1 ~]#mkdir rbac
[root@master1 ~]#cd rbac/
[root@master1 rbac]#openssl genrsa -out cnych.key 2048
Generating RSA private key, 2048 bit long modulus
..+++
..........................................................................+++
e is 65537 (0x10001)
[root@master1 rbac]#ls
cnych.key
  • 使用我们刚刚创建的私钥创建一个证书签名请求文件cnych.csr要注意需要确保在-subj参数中指定用户名和组(CN表示用户名O表示组)
[root@master1 rbac]#openssl req -new -key cnych.key -out cnych.csr -subj "/CN=cnych/O=youdianzhishi"
[root@master1 rbac]#ls
cnych.csr  cnych.key
  • 然后找到我们的 Kubernetes 集群的 CA 证书我们使用的是 kubeadm 安装的集群CA 相关证书位于 /etc/kubernetes/pki/ 目录下面如果你是二进制方式搭建的你应该在最开始搭建集群的时候就已经指定好了 CA 的目录我们会利用该目录下面的 ca.crt ca.key两个文件来批准上面的证书请求。生成最终的证书文件我们这里设置证书的有效期为 500 天
[root@master1 rbac]#openssl x509 -req -in cnych.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out cnych.crt -days 500
Signature ok
subject=/CN=cnych/O=youdianzhishi
Getting CA Private Key

#现在查看我们当前文件夹下面是否生成了一个证书文件
[root@master1 rbac]#ls
cnych.crt  cnych.csr  cnych.key
  • 现在我们可以使用刚刚创建的证书文件和私钥文件在集群中创建新的凭证和上下文(Context)我们先来创建新的凭证
[root@master1 rbac]#kubectl config --help #这里我们可以先看下config的帮助信息
……
Available Commands:
  current-context Display the current-context #care
  delete-cluster  Delete the specified cluster from the kubeconfig
  delete-context  Delete the specified context from the kubeconfig
  delete-user     Delete the specified user from the kubeconfig
  get-clusters    Display clusters defined in the kubeconfig  #care
  get-contexts    Describe one or many contexts
  get-users       Display users defined in the kubeconfig
  rename-context  Rename a context from the kubeconfig file
  set             Set an individual value in a kubeconfig file
  set-cluster     Set a cluster entry in kubeconfig
  set-context     Set a context entry in kubeconfig
  set-credentials Set a user entry in kubeconfig  #care
  unset           Unset an individual value in a kubeconfig file
  use-context     Set the current-context in a kubeconfig file
  view            Display merged kubeconfig settings or a specified kubeconfig file
……
  • 我们先来创建新的凭证
[root@master1 rbac]#kubectl config set-credentials cnych --client-certificate=cnych.crt --client-key=cnych.key
User "cnych" set.
  • 我们可以看到一个用户 cnych 创建了然后为这个用户设置新的 Context我们这里指定特定的一个 namespace
#因为我们当前只有一个k8s集群我么可以用命令先看一下
[root@master1 rbac]#kubectl config get-clusters
NAME
kubernetes

#为这个用户设置新的 Context
[root@master1 rbac]#kubectl config set-context cnych-context --cluster=kubernetes --namespace=kube-system --user=cnych
Context "cnych-context" created.
  • 到这里我们的用户 cnych 就已经创建成功了现在我们使用当前的这个配置文件来操作 kubectl 命令的时候应该会出现错误因为我们还没有为该用户定义任何操作的权限呢
[root@master1 rbac]#kubectl get pod --context=cnych-context
Error from server (Forbidden): pods is forbidden: User "cnych" cannot list resource "pods" in API group "" in the namespace "kube-system"

因此需要按如下思路去操作

image-20230203074335320

2、创建角色

  • 用户创建完成后接下来就需要给该用户添加操作权限我们来定义一个 YAML 文件创建一个允许用户操作 Deployment、Pod、ReplicaSets 的角色如下定义
#cnych-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cnych-role
  namespace: kube-system
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@master1 rbac]#kubectl apply -f cnych-role.yaml
role.rbac.authorization.k8s.io/cnych-role created

注意这里我们没有使用上面的 cnych-context 这个上下文因为暂时还没有权限。

3、创建角色权限绑定

  • Role 创建完成了但是很明显现在我们这个 Role 和我们的用户 cnych 还没有任何关系对吧这里就需要创建一个 RoleBinding 对象在 kube-system 这个命名空间下面将上面的 cnych-role 角色和用户 cnych 进行绑定
#cnych-rolebinding.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cnych-rolebinding
  namespace: kube-system
subjects:
- kind: User #外部的用户
  name: cnych
  apiGroup: "" #没有就填个空字符串
roleRef: #管理员权限声明的角色
  kind: Role
  name: cnych-role
  apiGroup: rbac.authorization.k8s.io  # 留空字符串也可以则使用当前的apiGroup
  
#把cnych用户和cnych-role角色绑定在一起而Role角色具有相应权限就相当于cnych用户有了这个权限。
  • 上面的 YAML 文件中我们看到了 subjects 字段这里就是我们上面提到的用来尝试操作集群的对象这里对应上面的 User 帐号 cnych使用kubectl 创建上面的资源对象
[root@master1 rbac]#kubectl apply -f cnych-rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/cnych-rolebinding created

4、测试

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

[root@master1 rbac]#kubectl get pod --context=cnych-context
NAME                              READY   STATUS    RESTARTS      AGE
coredns-7568f67dbd-9dls5          1/1     Running   0             16d
coredns-7568f67dbd-kqhjq          1/1     Running   0             27d
etcd-master1                      1/1     Running   1             28d
kube-apiserver-master1            1/1     Running   2 (28d ago)   28d
kube-controller-manager-master1   1/1     Running   2             28d
kube-flannel-ds-5lm5t             1/1     Running   0             25d
kube-flannel-ds-rmtfk             1/1     Running   0             25d
kube-flannel-ds-xbp6g             1/1     Running   0             25d
kube-proxy-4sw76                  1/1     Running   0             28d
kube-proxy-mkghd                  1/1     Running   0             28d
kube-proxy-s2748                  1/1     Running   0             28d
kube-scheduler-master1            1/1     Running   2             28d
metrics-server-76b8bfbb47-8v2lr   1/1     Running   0             6d15h

[root@master1 rbac]#kubectl get pod,deploy,rs --context=cnych-context
NAME                                  READY   STATUS    RESTARTS      AGE
pod/coredns-7568f67dbd-9dls5          1/1     Running   0             16d
pod/coredns-7568f67dbd-kqhjq          1/1     Running   0             27d
pod/etcd-master1                      1/1     Running   1             28d
pod/kube-apiserver-master1            1/1     Running   2 (28d ago)   28d
pod/kube-controller-manager-master1   1/1     Running   2             28d
pod/kube-flannel-ds-5lm5t             1/1     Running   0             25d
pod/kube-flannel-ds-rmtfk             1/1     Running   0             25d
pod/kube-flannel-ds-xbp6g             1/1     Running   0             25d
pod/kube-proxy-4sw76                  1/1     Running   0             28d
pod/kube-proxy-mkghd                  1/1     Running   0             28d
pod/kube-proxy-s2748                  1/1     Running   0             28d
pod/kube-scheduler-master1            1/1     Running   2             28d
pod/metrics-server-76b8bfbb47-8v2lr   1/1     Running   0             6d15h

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/coredns          2/2     2            2           28d
deployment.apps/metrics-server   1/1     1            1           6d15h

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/coredns-7568f67dbd          2         2         2       28d
replicaset.apps/metrics-server-76b8bfbb47   1         1         1       6d15h
replicaset.apps/metrics-server-859bf7c488   0         0         0       6d15h
[root@master1 rbac]#
  • 我们可以看到我们使用 kubectl 的使用并没有指定 namespace这是因为我们我们上面创建这个 Context 的时候就绑定在了 kube-system 这个命名空间下面如果我们在后面加上一个-n default试看看呢
[root@master1 rbac]#kubectl get po --context=cnych-context --namespace=deafult
Error from server (Forbidden): pods is forbidden: User "cnych" cannot list resource "pods" in API group "" in the namespace "deafult"
[root@master1 rbac]#kubectl get po --context=cnych-context -n default
Error from server (Forbidden): pods is forbidden: User "cnych" cannot list resource "pods" in API group "" in the namespace "default"
[root@master1 rbac]#
  • 如果去获取其他的资源对象呢
[root@master1 rbac]#kubectl get svc --context=cnych-context
Error from server (Forbidden): services is forbidden: User "cnych" cannot list resource "services" in API group "" in the namespace "kube-system"
[root@master1 ~]#kubectl get daemonsets --context=cnych-context
Error from server (Forbidden): daemonsets.apps is forbidden: User "cnych" cannot list resource "daemonsets" in API group "apps" in the namespace "kube-system"

我们可以看到没有权限获取因为我们并没有为当前操作用户指定其他对象资源的访问权限是符合我们的预期的。

  • 此时我们给role加上允许访问daemonsets的权限
[root@master1 rbac]#vim cnych-role.yaml
#cnych-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cnych-role
  namespace: kube-system
rules:
- apiGroups: ["", "apps"]
  resources: ["deployments", "replicasets", "pods", "daemonsets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']
  
#部署
[root@master1 rbac]#kubectl apply -f cnych-role.yaml
role.rbac.authorization.k8s.io/cnych-role configured

#验证
[root@master1 rbac]#kubectl get daemonsets --context=cnych-context
NAME         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-proxy   3         3         3       3            3           kubernetes.io/os=linux   61d

这样我们就创建了一个只有单个命名空间访问权限的普通 User 。

实验结束。😘

💘 实战2只能访问某个 namespace 的普通用户-2023.2.6(测试成功)cfgssl

image-20230206212010809

  • 实验环境
实验环境
1、win10,vmwrokstation虚机
2、k8s集群3台centos7.6 1810虚机1个master节点,2个node节点
   k8s versionv1.22.2
   containerd://1.5.5
  • 实验环境
链接https://pan.baidu.com/s/1LGijalb5sc3x_B4M1qMKMg?pwd=0qs4 
提取码0qs4 

20211005-rbac实验软件

image-20230206210630616

  • 背景

案例为指定用户授权访问不同命名空间权限例如新入职一个小弟希望让他先熟悉K8s集群为了安全性先不能给他太大权限因此先给他授权访问default命名空间Pod读取权限。

实施大致步骤

  1. 用K8S CA签发客户端证书
  2. 生成kubeconfig授权文件
  3. 创建RBAC权限策略
  4. 指定kubeconfig文件测试权限
    kubectl get pods --kubeconfig=./aliang.kubeconfig

1、用K8S CA签发客户端证书

注意前期需要先安装cfgssl命令才行请自行百度或查看我之前的文章。

[root@k8s-master ~]#ll -h
total 4.0K
-rw-r--r-- 1 root root 1.4K Jul  6 14:02 rbac.zip
drwxr-xr-x 6 root root   78 Jul  6 13:59 yaml #上传rbac.zip文件到家目录下并解压
[root@k8s-master ~]#unzip rbac.zip
[root@k8s-master ~]#cd rbac/
[root@k8s-master rbac]#ls
cert.sh  kubeconfig.sh  rbac.yaml


[root@k8s-master rbac]#sh cert.sh #直接执行
2021/07/05 05:50:00 [INFO] generate received request
2021/07/05 05:50:00 [INFO] received CSR
2021/07/05 05:50:00 [INFO] generating key: rsa-2048
2021/07/05 05:50:00 [INFO] encoded CSR
2021/07/05 05:50:00 [INFO] signed certificate with serial number 159473389712332926121043715574924065961218702913
2021/07/05 05:50:00 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
[root@k8s-master rbac]#

注意用K8S CA签发客户端证书

image-20230206211046745

2. 生成kubeconfig授权文件

[root@k8s-master rbac]#pwd
/root/rbac
[root@k8s-master rbac]#ls
aliang.csr  aliang-csr.json  aliang-key.pem  aliang.pem  ca-config.json  cert.sh  kubeconfig.sh  rbac  rbac.yaml  rbac.zip

[root@k8s-master rbac]#sh kubeconfig.sh #直接执行
Cluster "kubernetes" set.
User "aliang" set.
Context "kubernetes" created.
Switched to context "kubernetes".

[root@k8s-master rbac]#ls #注意生成为kubeconfig文件如下aliang.kubeconfig
aliang.csr  aliang-csr.json  aliang-key.pem  aliang.kubeconfig  aliang.pem  ca-config.json  cert.sh  kubeconfig.sh  rbac  rbac.yaml  rbac.zip
[root@k8s-master rbac]#

修改aliang.kubeconfig文件

image-20230206211207243

此时我们可以测试下

[root@k8s-master rbac]#kubectl get pod --kubeconfig=aliang.kubeconfig
Error from server (Forbidden): pods is forbidden: User "aliang" cannot list resource "pods" in API group "" in the namespace "default"
#此时可以看到访问被禁止了。到这里我们相当于完成了第一步"鉴权"即k8s是认你这个客户端证书的。现在就将要开始第二步授权操作了。

3. 创建RBAC权限策略

查看rbac.yaml内容

[root@k8s-master rbac]#cat rbac.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

---

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
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
[root@k8s-master rbac]#

apply下rbac.yaml并查看

#apply下rbac.yaml
[root@k8s-master rbac]#kubectl apply -f rbac.yaml
role.rbac.authorization.k8s.io/pod-reader created
rolebinding.rbac.authorization.k8s.io/read-pods created

#查看
[root@k8s-master rbac]#kubectl get role|grep pod-reader
pod-reader   2021-07-04T22:20:54Z

[root@k8s-master rbac]#kubectl describe role pod-reader
Name:         pod-reader
Labels:       <none>
Annotations:  <none>
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  pods       []                 []              [get watch list]
[root@k8s-master rbac]#

4.指定kubeconfig文件测试权限

以上all策略均已经配置完成了现在进行测试

[root@k8s-master rbac]#kubectl get pod --kubeconfig=aliang.kubeconfig #现在终于可以查看了
NAME      READY   STATUS             RESTARTS   AGE
my-pod    1/1     Running            0          38h
my-pod1   1/2     CrashLoopBackOff   23         38h

#以下无分配权限次用户将不能进行其他操作
[root@k8s-master rbac]#kubectl get deployments --kubeconfig=aliang.kubeconfig #一下均查看失败
Error from server (Forbidden): deployments.apps is forbidden: User "aliang" cannot list resource "deployments" in API group "apps" in the namespace "default"

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

[root@k8s-master rbac]#kubectl get service --kubeconfig=aliang.kubeconfig
Error from server (Forbidden): services is forbidden: User "aliang" cannot list resource "services" in API group "" in the namespace "default"

#同样kubectl describe也是可以使用的
[root@k8s-master rbac]#kubectl describe pod my-pod1 --kubeconfig=aliang.kubeconfig
Name:         my-pod1
Namespace:    default
Priority:     0
Node:         k8s-node2/172.29.9.33
Start Time:   Sat, 03 Jul 2021 15:43:45 +0800
Labels:       <none>
Annotations:  cni.projectcalico.org/podIP: 10.244.169.149/32

5.现在这个小伙子技术差不多了该如何给他放大权限呢

继续编辑rbac.yaml

[root@k8s-master rbac]#vim rbac.yaml #注意以下有没有空格都是ok的
……
- apiGroups: ["", "apps"] #添加
  resources: ["pods", "deployments", "services"] #添加这里都是复数
  verbs: ["get", "watch", "list"]
……

image-20230206211426190

再次apply下并测试

#apply
[root@k8s-master rbac]#kubectl apply -f rbac.yaml
role.rbac.authorization.k8s.io/pod-reader configured
rolebinding.rbac.authorization.k8s.io/read-pods unchanged

#查看=>符合预期可以正常查看deployment/svc资源
[root@k8s-master rbac]#kubectl get deployments --kubeconfig=aliang.kubeconfig
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    1/1     1            1           5s
[root@k8s-master rbac]#kubectl get service --kubeconfig=aliang.kubeconfig
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   33d

技巧如果我们实在不知道该如何配置策略我们可以根据权限不足提示进行配置策略。

注意
deployments/statefulsets/repilcasets在apps组里面
namespace、pod、service、pv、pvc都在核心组里面

[root@k8s-master rbac]#kubectl get deployments --kubeconfig=aliang.kubeconfig #一下均查看失败
Error from server (Forbidden): deployments.apps is forbidden: User "aliang" cannot list resource "deployments" in API group "apps" in the namespace "default"

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

[root@k8s-master rbac]#kubectl get service --kubeconfig=aliang.kubeconfig
Error from server (Forbidden): services is forbidden: User "aliang" cannot list resource "services" in API group "" in the namespace "default"
  • 再测试我们给这个小弟添加delete权限
1、默认删除失败
[root@k8s-master rbac]#kubectl get deployments.apps --kubeconfig=aliang.kubeconfig
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    1/1     1            1           18m

[root@k8s-master rbac]#kubectl delete  deployments.apps web  --kubeconfig=aliang.kubeconfig
Error from server (Forbidden): deployments.apps "web" is forbidden: User "aliang" cannot delete resource "deployments" in API group "apps" in the namespace "default"
[root@k8s-master rbac]#

2、添加delete权限
[root@k8s-master rbac]#vim rbac.yaml
- apiGroups: ["","apps"]
  resources: ["pods","deployments","services"]
  verbs: ["get","watch","list","delete"] #添加dlete权限注意这里添加了删除操作后代表对上面所有资源都具有删除权限。

3、apply并查看
[root@k8s-master rbac]#kubectl apply -f rbac.yaml
role.rbac.authorization.k8s.io/pod-reader configured
rolebinding.rbac.authorization.k8s.io/read-pods unchanged

[root@k8s-master rbac]#kubectl delete  deployments.apps web  --kubeconfig=aliang.kubeconfig #添加delete后删除成功
deployment.apps "web" deleted
[root@k8s-master rbac]#kubectl get   deployments.apps  --kubeconfig=aliang.kubeconfig 
No resources found in default namespace.
[root@k8s-master rbac]#

6.此时这个小伙子就可以欢乐去使用k8s集群了

我们 可以把这个aliang.kubeconfig配置文件发给小弟他可以通过如下命令进行访问k8s集群

[root@k8s-master rbac]#pwd
/root/rbac
[root@k8s-master rbac]#ls
aliang.csr  aliang-csr.json  aliang-key.pem  aliang.kubeconfig  aliang.pem  ca-config.json  cert.sh  kubeconfig.sh  rbac  rbac.yaml  rbac.zip

[root@k8s-master rbac]#
kubectl get pod --kubeconfig=aliang.kubeconfig
kubectl get deployment --kubeconfig=aliang.kubeconfig
kubectl get service --kubeconfig=aliang.kubeconfig

注意

他可以在任何机器上去访问这个k8s集群但要能通是前提

使用之前可以先安装好kubectl命令。

aliang.kubeconfig访问k8s里面所有的资源都在这里面了。

它如果不想每次后面都加上–kubeconfig=aliang.kubeconfig的话我们可以去修改默认kubeconfig文件的但如何修改呢(我也不知道暂且搁置。。。。)

如果登录到了master默认使用的就是/root/.kube/config配置文件了。

实验结束。😘

2.只能访问某个 namespace 的 ServiceAccount

1ServiceAccount

image-20230204175205074

ServiceAccount 为 Pod 中运行的进程提供了一个身份Pod 内的进程可以使用其关联服务账号的身份向集群的APIServer 进行身份认证。

当创建 Pod 的时候规范下面有一个 spec.serviceAccount 的属性用来指定该 Pod 使用哪个 ServiceAccount如果没有指定的话则默认使用 default 这个 sa。然后通过投射卷在 Pod 的目录
/run/secrets/kubernetes.io/serviceaccount/ 下有一个 token 令牌文件。我们通过 RBAC 对该 sa 授予了什么权限那么容器里的应用拿着这个 token 后就具备了对应的权限。

ServiceAccount主要是用于解决 Pod 在集群中的身份认证问题的。认证使用的授权信息其实就是利用前面我们讲到的一个类型为kubernetes.io/service-account-token进行管理的。

⚠️ 注意sa是命名空间级别的每创建一个命名空间后其下都会有一个default的sa。default sa是没有绑定任何权限的。

[root@master1 ~]#kubectl get sa
NAME      SECRETS   AGE
default   0         61d
[root@master1 ~]#kubectl create ns test
namespace/test created
[root@master1 ~]#kubectl get sa -ntest
NAME      SECRETS   AGE
default   0         5s

🍀 画图说明

image-20230204174056393

⚠️ 注意2种方式访问k8s集群serviceaccount只能在pod里使用

1.集群外访问kubectl

2.集群内访问sa

image-20230206212823567

image-20230206212828165

但是需要注意的是不同的 K8s 版本对该 token 文件的使用是不一样的所以我们可以分几个版本来分别讨论下。

1<=1.20版本

💘 实战<=1.20 k8s版本sa测试-2023.1.18(测试成功)

image-20230204190627533

  • 实验环境
实验环境
kind环境k8s v1.20.15
  • 实验软件无
  • 使用 kind 快速创建一个小于等于 v1.20 版本的集群
[root@docker ~]#kind create cluster --name kind120 --image kindest/node:v1.20.15
[root@docker ~]#kubectl get node
NAME                    STATUS   ROLES                  AGE    VERSION
kind120-control-plane   Ready    control-plane,master   8m2s   v1.20.15
  • 我们先创建一个字为 sa-demo 的 ServiceAccount 对象
[root@docker ~]#kubectl create sa sa-demo
serviceaccount/sa-demo created
[root@docker ~]#kubectl get sa
NAME      SECRETS   AGE
default   1         8m57s
sa-demo   1         9s
[root@docker ~]#kubectl get secret
NAME                  TYPE                                  DATA   AGE
default-token-wc7tx   kubernetes.io/service-account-token   3      9m17s
sa-demo-token-4kwph   kubernetes.io/service-account-token   3      29s

我们可以看到创建 sa 后自动生成了一个 secret格式为 -token-xxxx 比如我们创建了一个名字为 sa-demo 的 sa 之后系统自动创建了一个名字为 sa-demo-token-4kwph 的 secret这个 secret 里就包含了一个token。

[root@docker ~]#kubectl describe secret sa-demo-token-4kwph
Name:         sa-demo-token-4kwph
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: sa-demo
              kubernetes.io/service-account.uid: 0318b17e-6bf6-4831-ba34-792ad305018e

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1066 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6InpxQ3dCV1JGREVtaVo2TlBqTmN4dVF3VVo4eVdXeXA5RGhSaWZKdHMzb0EifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InNhLWRlbW8tdG9rZW4tNGt3cGgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic2EtZGVtbyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjAzMThiMTdlLTZiZjYtNDgzMS1iYTM0LTc5MmFkMzA1MDE4ZSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnNhLWRlbW8ifQ.ThtpMWagNdebRt0GPPvOoJLpnwSpkZM_RtmcSyiexGbzXdp93JkFDBinAmHSVKno3id2qWwfEvkLCKDq4pTDlcG_GsM3vliTFwbWprtC_HdMbtWSm5bvA1TFapJ_JIKXeHD9ovkluuYquccQBvOxKmE-s4jkuldK4WAyJ1oAY9-Dcwb92E4rTCw7J2mWsGoCKXKhl55cbFovQD1Ug6f966MgAjci8EUw9qkOTYQEL7eK74GCQVfBUAqEcBFutotOi8BiZopPfqGy0nnYGw3KgrkFFCAaNQUJ_FXLeP2YH4zHqMLZ7ggLpS_bvx79gQ1Lf-JxQ2keBwosUbcH79ckqw

可以看到自动生成的这个 secret 对象里面包含一个 token我们也可以通过下面的命令来获取

[root@docker ~]#kubectl get  secret sa-demo-token-4kwph  -o jsonpath='{.data.token}' | base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6InpxQ3dCV1JGREVtaVo2TlBqTmN4dVF3VVo4eVdXeXA5RGhSaWZKdHMzb0EifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InNhLWRlbW8tdG9rZW4tNGt3cGgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic2EtZGVtbyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjAzMThiMTdlLTZiZjYtNDgzMS1iYTM0LTc5MmFkMzA1MDE4ZSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnNhLWRlbW8ifQ.ThtpMWagNdebRt0GPPvOoJLpnwSpkZM_RtmcSyiexGbzXdp93JkFDBinAmHSVKno3id2qWwfEvkLCKDq4pTDlcG_GsM3vliTFwbWprtC_HdMbtWSm5bvA1TFapJ_JIKXeHD9ovkluuYquccQBvOxKmE-s4jkuldK4WAyJ1oAY9-Dcwb92E4rTCw7J2mWsGoCKXKhl55cbFovQD1Ug6f966MgAjci8EUw9qkOTYQEL7eK74GCQVfBUAqEcBFutotOi8BiZopPfqGy0nnYGw3KgrkFFCAaNQUJ_FXLeP2YH4zHqMLZ7ggLpS_bvx79gQ1Lf-JxQ2keBwosUbcH79ckqw[root@docker ~]#

这个 token 是 JWT 结构的我们可以把这个 token 复制到 jwt.io 网站进行解码。

https://jwt.io/

image-20230204185401990

右侧部分显示了 token 被解码之后的内容其中 PAYLOAD 部分是 token 里包含的 sa-demo 的信息可以看到里面没有过期时间也说明了该 token 是永不过期的

  • 现在我们使用上面我们创建的 sa 来运行一个 Pod
# demo-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo
spec:
  serviceAccount: sa-demo
  containers:
    - name: demo
      image: nginx:1.7.9
      ports:
        - containerPort: 80

直接创建该 Pod 即可

[root@docker ~]#kubectl apply -f demo-pod.yaml
pod/demo created
[root@docker ~]#kubectl get po
NAME   READY   STATUS    RESTARTS   AGE
demo   1/1     Running   0          75s

[root@docker ~]#kubectl get po demo -oyaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"demo","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.7.9","name":"demo","ports":[{"containerPort":80}]}],"serviceAccount":"sa-demo"}}
  creationTimestamp: "2023-02-04T10:56:35Z"
  name: demo
  namespace: default
  resourceVersion: "1859"
  uid: 994996db-d7cd-4a63-8558-b0697ac33585
spec:
  containers:
  - image: nginx:1.7.9
    imagePullPolicy: IfNotPresent
    name: demo
    ports:
    - containerPort: 80
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: sa-demo-token-4kwph
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  nodeName: kind120-control-plane
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: sa-demo
  serviceAccountName: sa-demo
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: sa-demo-token-4kwph
    secret:
      defaultMode: 420
      secretName: sa-demo-token-4kwph
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2023-02-04T10:56:35Z"
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2023-02-04T10:57:10Z"
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2023-02-04T10:57:10Z"
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2023-02-04T10:56:35Z"
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: containerd://d05bdfc60b7b0edd569a7a3aa495e2b1c2510e9238a3bdec22730384f41df9e6
    image: docker.io/library/nginx:1.7.9
    imageID: sha256:35d28df486f6150fa3174367499d1eb01f22f5a410afe4b9581ac0e0e58b3eaf
    lastState: {}
    name: demo
    ready: true
    restartCount: 0
    started: true
    state:
      running:
        startedAt: "2023-02-04T10:57:09Z"
  hostIP: 172.18.0.3
  phase: Running
  podIP: 10.244.0.5
  podIPs:
  - ip: 10.244.0.5
  qosClass: BestEffort
  startTime: "2023-02-04T10:56:35Z"
[root@docker ~]#

Pod 创建后我们可以看到会自动将指定 sa 对应的 secret 挂载到容器的/var/run/secrets/kubernetes.io/serviceaccount 目录下去所以现在该目录下面肯定包含对应的 token 文件我们可以查看该值来验证下

[root@docker ~]#kubectl exec -it demo -- cat /run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6InpxQ3dCV1JGREVtaVo2TlBqTmN4dVF3VVo4eVdXeXA5RGhSaWZKdHMzb0EifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InNhLWRlbW8tdG9rZW4tNGt3cGgiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic2EtZGVtbyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjAzMThiMTdlLTZiZjYtNDgzMS1iYTM0LTc5MmFkMzA1MDE4ZSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnNhLWRlbW8ifQ.ThtpMWagNdebRt0GPPvOoJLpnwSpkZM_RtmcSyiexGbzXdp93JkFDBinAmHSVKno3id2qWwfEvkLCKDq4pTDlcG_GsM3vliTFwbWprtC_HdMbtWSm5bvA1TFapJ_JIKXeHD9ovkluuYquccQBvOxKmE-s4jkuldK4WAyJ1oAY9-Dcwb92E4rTCw7J2mWsGoCKXKhl55cbFovQD1Ug6f966MgAjci8EUw9qkOTYQEL7eK74GCQVfBUAqEcBFutotOi8BiZopPfqGy0nnYGw3KgrkFFCAaNQUJ_FXLeP2YH4zHqMLZ7ggLpS_bvx79gQ1Lf-JxQ2keBwosUbcH79ckqw[root@docker ~]#

可以看到 Pod 里通过投射卷所挂载的 token 跟 sa-demo 对应的 secret 包含的 token 是一模一样的这个 token是永不过期的所以即使删除了 Pod 之后重新创建Pod 里的 token 仍然是不变的因为 secret 对象里面的 token数据并没有变化。

如果需要在 Pod 中去访问 K8s 集群的资源对象现在就可以为使用的 sa 绑定上相应的权限然后在 Pod 应用中使用该对应的 token 去和 APIServer 进行通信就可以了这个时候的 token 就能识别到对应的权限了。

⚠️ 注意

这些系统pod里的镜像是没有的我们可以创建一个nginx pod来测试

[root@master1 ~]#kubectl get po -A
NAMESPACE              NAME                                         READY   STATUS             RESTARTS          AGE
default                nginx-7498977d8c-r6sqx                       1/1     Running            0                 19d
default                pod1                                         1/1     Running            0                 19d
default                secret1-pod                                  0/1     CrashLoopBackOff   51 (4m7s ago)     18d
default                secret2-pod                                  1/1     Running            40 (4m7s ago)     19d
default                secret3-pod                                  1/1     Running            39 (3m36s ago)    19d
default                testcm1-pod                                  0/1     CrashLoopBackOff   263 (3m36s ago)   20d
default                testcm2-pod                                  0/1     CrashLoopBackOff   210 (4m6s ago)    20d
default                testcm3-pod                                  0/1     CrashLoopBackOff   207 (3m5s ago)    20d
default                testcm4-pod                                  0/1     CrashLoopBackOff   207 (5m23s ago)   20d
default                testcm5-pod                                  1/1     Running            0                 20d
kube-flannel           kube-flannel-ds-955fg                        1/1     Running            1 (59d ago)       61d
kube-flannel           kube-flannel-ds-ddfqs                        1/1     Running            0                 61d
kube-flannel           kube-flannel-ds-x2gd6                        1/1     Running            1 (51d ago)       61d
kube-system            coredns-7b884d5cb7-6jzn6                     1/1     Running            1 (51d ago)       61d
kube-system            coredns-7b884d5cb7-gcszd                     1/1     Running            1 (51d ago)       61d
kube-system            etcd-master1                                 1/1     Running            1 (51d ago)       61d
kube-system            kube-apiserver-master1                       1/1     Running            1 (51d ago)       61d
kube-system            kube-controller-manager-master1              1/1     Running            2 (47d ago)       61d
kube-system            kube-proxy-l6np4                             1/1     Running            0                 61d
kube-system            kube-proxy-vb49s                             1/1     Running            1 (51d ago)       61d
kube-system            kube-proxy-xmg7m                             1/1     Running            1 (59d ago)       61d
kube-system            kube-scheduler-master1                       1/1     Running            2 (47d ago)       61d
kube-system            metrics-server-7c5487d558-nwj59              1/1     Running            0                 41d
kube-system            vpa-admission-controller-8599bb878d-q25wx    1/1     Running            0                 40d
kube-system            vpa-recommender-6bf6dd6795-wchjc             1/1     Running            0                 40d
kube-system            vpa-updater-697666f758-6vl75                 1/1     Running            0                 40d
kubernetes-dashboard   dashboard-metrics-scraper-64bcc67c9c-27pqg   1/1     Running            0                 61d
kubernetes-dashboard   kubernetes-dashboard-5c8bd6b59-qlgjk         1/1     Running            9 (60d ago)       61d

#coredns等的镜像很精简就是一个二进制文件这里我们看下自己创建的pod就好。
[root@master1 ~]#kubectl exec -it coredns-7b884d5cb7-6jzn6  -nkube-system -- ls /run/secrets/kubernetes.io/serviceaccount/
error: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec "0aa9b2c89f8e5ac588074955ad37e3d54d64116a9edee4ee977fe77f00a4b512": OCI runtime exec failed: exec failed: unable to start container process: exec: "ls": executable file not found in $PATH: unknown
[root@master1 ~]#kubectl exec -it kubernetes-dashboard-5c8bd6b59-qlgjk  -nkubernetes-dashboard -- ls /run/secrets/kubernetes.io/serviceaccount/
error: Internal error occurred: error executing command in container: failed to exec in container: failed to start exec "2883ecb081fd96339dc1123b05331e044b4dc7ed762685b670f8ea37d7e87272": OCI runtime exec failed: exec failed: unable to start container process: exec: "ls": executable file not found in $PATH: unknown

[root@master1 ~]#kubectl exec -it nginx-7498977d8c-r6sqx -- ls /run/secrets/kubernetes.io/serviceaccount/
ca.crt  namespace  token

测试结束。😘

2>=1.21版本 && <=1.23版本

💘 实战>=1.21版本 && <=1.23版本sa测试-2023.1.18(测试成功)

image-20230205141912034

  • 实验环境
实验环境
kind环境k8s v1.22.15
  • 实验软件无

接下来我们基于>=1.21版本 && <=1.23版本的 K8s 集群进行测试。

  • 这里我们使用 kind 快速创建一个 v1.22.15 版本的集群
[root@docker ~]#kind create cluster --name kind122 --image kindest/node:v1.22.15
[root@docker ~]#kubectl get node
NAME                    STATUS   ROLES                  AGE   VERSION
kind122-control-plane   Ready    control-plane,master   11m   v1.22.15
  • 同样首先创建一个名为 sa-demo 的 ServiceAccount 对象
[root@docker ~]#kubectl create sa sa-demo
serviceaccount/sa-demo created
[root@docker ~]#kubectl get sa
NAME      SECRETS   AGE
default   1         9m17s
sa-demo   0         10s
[root@docker ~]#kubectl get secret
NAME                  TYPE                                  DATA   AGE
default-token-bzm5c   kubernetes.io/service-account-token   3      13m
sa-demo-token-5tc2g   kubernetes.io/service-account-token   3      12s

同样可以看到创建 sa 后系统也自动创建了一个对应的 secret 对象和以前版本没什么区别我们也可以通过下面的命令来获得该 secret 对象里面包含的 token 值

[root@docker ~]#kubectl get  secret sa-demo-token-n9z89  -o jsonpath='{.data.token}' | base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6IlBwOGtYcVlpRVdOLUc0NHByNE5obTlyc0tQTVlLa1R5a3F2TEQ2WnhkSWsifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InNhLWRlbW8tdG9rZW4tbjl6ODkiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic2EtZGVtbyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImY5ZTYyNzE1LTMwOWItNDE0YS04YTkzLTc5MTJhNzY1Nzk1MyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnNhLWRlbW8ifQ.WSpB6KkX55sC_K8MdCTH0uV71O5Cry7MYKE3dfvCMzZYseAgLpk_FXFr-IdlMzfN23Saur4Y-8v1jlyJ_h8ipbxXb2mgVCg46ORb65u8FZxWky6c7bDbARMcdiNxvtQystWos5vOSSYu9Gd61RU15zXE7SJByPAMeGDJIn94PXszmnKa037cKhKVIhfgXTRh4Rw_Xu66a9ALYU0b8dTAGfM8sBLwI-wEUolosTRNkC5M87i3cSHRsdv3WqsqW-2QytVW3COWL7erirb5XR5yTtLx0BWSXPFswR2UVpWpoW5AnQYh9M2xAd0O_FF6f_9r7I8RP0fUO6_kzxp2kCvJLw[root@docker ~]#

同样将该 token 值拷贝到 jwt.io 网站进行解码。

image-20230204195305391

从解码后的值可以看到该 token 值里面同样不包含任何过期时间也说明了我们创建 sa 之后所对应的 token 是永不过期的。

  • 同样我们再次使用上面的 sa 来创建一个 Pod如下所示
# demo-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo
spec:
  serviceAccount: sa-demo
  containers:
    - name: demo
      image: nginx:1.7.9
      ports:
        - containerPort: 80

直接创建该 Pod

[root@docker ~]#kubectl apply -f demo-pod.yaml
pod/demo created
[root@docker ~]#kubectl get po
NAME   READY   STATUS    RESTARTS   AGE
demo   1/1     Running   0          50s

[root@docker ~]#kubectl get po demo -oyaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"demo","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.7.9","name":"demo","ports":[{"containerPort":80}]}],"serviceAccount":"sa-demo"}}
  creationTimestamp: "2023-02-05T06:05:33Z"
  name: demo
  namespace: default
  resourceVersion: "811"
  uid: ecb8a127-1e56-4b0a-8760-ad952b83800f
spec:
  containers:
  - image: nginx:1.7.9
    imagePullPolicy: IfNotPresent
    name: demo
    ports:
    - containerPort: 80
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:#这里
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-cds9k
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  nodeName: kind122-control-plane
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: sa-demo
  serviceAccountName: sa-demo
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:#这里
  - name: kube-api-access-cds9k
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2023-02-05T06:05:33Z"
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2023-02-05T06:06:13Z"
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2023-02-05T06:06:13Z"
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2023-02-05T06:05:33Z"
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: containerd://b684a2c6ea8a02c86659045064cfead08019bfc30e7e27d1d998df6fa7481c5a
    image: docker.io/library/nginx:1.7.9
    imageID: sha256:35d28df486f6150fa3174367499d1eb01f22f5a410afe4b9581ac0e0e58b3eaf
    lastState: {}
    name: demo
    ready: true
    restartCount: 0
    started: true
    state:
      running:
        startedAt: "2023-02-05T06:06:12Z"
  hostIP: 172.18.0.3
  phase: Running
  podIP: 10.244.0.5
  podIPs:
  - ip: 10.244.0.5
  qosClass: BestEffort
  startTime: "2023-02-05T06:05:33Z"
[root@docker ~]#

当 Pod 创建后查看对应的资源对象可以看到和之前的版本已经有一个很大的区别了并不是将上面自动创建的 secret挂载到容器的 /var/run/secrets/kubernetes.io/serviceaccount 目录。我们可以查看下 Pod 中的 token 值来和 secret 包含的 token 值进行对比

[root@docker ~]# kubectl exec -it demo -- cat /run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6ImdsZHBQY2ZjRkZQUFNtbTkzLXhQSjFnN19JdUZBYWRrV2NLYUowanFMamcifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzA3MTEzMTMzLCJpYXQiOjE2NzU1NzcxMzMsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJkZW1vIiwidWlkIjoiZWNiOGExMjctMWU1Ni00YjBhLTg3NjAtYWQ5NTJiODM4MDBmIn0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJzYS1kZW1vIiwidWlkIjoiZDViNWE2MTktMjkyMC00Y2NiLWFlMTItZTM5YTY1YTYyNmI3In0sIndhcm5hZnRlciI6MTY3NTU4MDc0MH0sIm5iZiI6MTY3NTU3NzEzMywic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6c2EtZGVtbyJ9.WZQ6NLMmmdAx-VdTabT2ENno-C-FfQzzrOLsLEmCL3fL2wc-OrOvgoucgpRUF1gJD1ju95pt6wlpvJzD0I_6b0e3b8__3lbTSaXJigMXkvR_opuaw7EkE-vjtnBZMMn8RHTSfqDsRDfeth3BCBZq5873cTjl5X-s4fsYbBaWQaVfkzDxlt3dF_kdmIChHGRID3PrunwgtfgsrB2bg3UB16RiUXF4HSROugBxpoFymfvIPEuuNOaCv2IdRbWFr9qp0iMQxWvnOemlbFzoQM6NWfqZ6hP7gX_sADHPtOa73PyoPtnFZihhC3bPgS54TIeVOvtGA0_FI2cTfJAvDOPQ5w[root@docker ~]#

可以很明显看到现在 Pod 中的 token 值和自动创建 secret 的 token 值不一样了同样在 jwt.io 解码该 token值。

image-20230205141202648

可以看到该 token 值解码后的 PAYLOAD 数据中包含了很多不同的数据其中的 exp 字段表示该 token 的过期时间可以看到过期时间是 1 年

这里我们可以总结下在 v1.21 到 v1.23 版本的 K8s 集群当创建 ServiceAccount 对象后系统仍然会自动创建一个 secret 对象该 secret 对象里面包含的 token 仍然是永不过期的但是 Pod 里面并不会使用该 secret 的token 值了。

从上面查看创建后的 Pod 资源清单可以看出现在创建 Pod 后Kubernetes 控制平面会自动添加一个投射卷到 Pod此卷包括了访问 Kubernetes API 的 token该清单片段定义了由三个数据源组成的投射卷这三个数据源是

  • serviceAccountToken 数据源包含 kubelet 从 kube-apiserver 获取的令牌kubelet 使用TokenRequest API 获取有时间限制的令牌。为 TokenRequest 服务的这个令牌会在 Pod 被删除或定义的生命周期默认为 1 小时结束之后过期。该令牌绑定到特定的 Pod 并将其 **audience受众**设置为与 kubeapiserver 的 audience 相匹配。 这种机制取代了之前基于 Secret 添加卷的机制之前 Secret 代表了针对Pod 的 ServiceAccount 但不会过期。

  • configMap 数据源 ConfigMap 包含一组证书颁发机构数据Pod 可以使用这些证书来确保自己连接到集群的kube-apiserver而不是连接到中间件或意外配置错误的对等点上

  • downwardAPI 数据源用于查找包含 Pod 的名字空间的名称并使该名称信息可用于在 Pod 内运行的应用程序代码。

所以我们应该要指定现在版本的 K8s 集群创建的 Pod 里面包含的 token 不是使用 ServiceAccount 自动关联的secret 对象里面的 token 了而是 kubelet 会向 TokenRequest API 发送一个请求申请一个新的 token 放在 Pod 的 /run/secrets/kubernetes.io/serviceaccount/token 里。这个 token 会在 1 个小时后由kubelet 重新去申领一个新的 token所以 1 小时之后再次查看这个 token 的话会发现 token 的内容是变化的如果删除此 Pod 重新创建的话则会重新申领 token被删除 Pod 里的 token 会立即过期。

而且我们还可以手动使用 kubectl create token <sa> 命令来请求 ServiceAccount 的 token可以指定有效期等

[root@docker ~]#kubectl create token -h
Request a service account token.

Examples:
  # Request a token to authenticate to the kube-apiserver as the service account "myapp" in the current namespace
  kubectl create token myapp

  # Request a token for a service account in a custom namespace
  kubectl create token myapp --namespace myns

  # Request a token with a custom expiration
  kubectl create token myapp --duration 10m

  # Request a token with a custom audience
  kubectl create token myapp --audience https://example.com

  # Request a token bound to an instance of a Secret object
  kubectl create token myapp --bound-object-kind Secret --bound-object-name mysecret

  # Request a token bound to an instance of a Secret object with a specific uid
  kubectl create token myapp --bound-object-kind Secret --bound-object-name mysecret --bound-object-uid
0d4691ed-659b-4935-a832-355f77ee47cc

Options:
    --allow-missing-template-keys=true:
        If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to
        golang and jsonpath output formats.

    --audience=[]:
        Audience of the requested token. If unset, defaults to requesting a token for use with the Kubernetes API
        server. May be repeated to request a token valid for multiple audiences.

    --bound-object-kind='':
        Kind of an object to bind the token to. Supported kinds are Pod, Secret. If set, --bound-object-name must be
        provided.

    --bound-object-name='':
        Name of an object to bind the token to. The token will expire when the object is deleted. Requires
        --bound-object-kind.

    --bound-object-uid='':
        UID of an object to bind the token to. Requires --bound-object-kind and --bound-object-name. If unset, the UID
        of the existing object is used.

    --duration=0s:
        Requested lifetime of the issued token. The server may return a token with a longer or shorter lifetime.

    -o, --output='':
        Output format. One of: (json, yaml, name, go-template, go-template-file, template, templatefile, jsonpath,
        jsonpath-as-json, jsonpath-file).

    --show-managed-fields=false:
        If true, keep the managedFields when printing objects in JSON or YAML format.

    --template='':
        Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format
        is golang templates [http://golang.org/pkg/text/template/#pkg-overview].

Usage:
  kubectl create token SERVICE_ACCOUNT_NAME [options]

Use "kubectl options" for a list of global command-line options (applies to all commands).
[root@docker ~]#

测试结束。😘

3>=1.24版本

💘 实战>=1.24版本sa测试-2023.2.5(测试成功)

image-20230205144327903

  • 实验环境
实验环境
kind环境k8s v1.25.3
  • 实验软件无

  • 现在我们再来看下 v1.24 版本以上的 K8s 集群中的 ServiceAccount token 是如何工作的。这里我们使用 kind 快速创建一个 v1.25.3 版本的集群

[root@docker ~]#kind create cluster --name kind125 --image kindest/node:v1.25.3
[root@docker ~]#kubectl get node
NAME                    STATUS   ROLES                  AGE   VERSION
kind122-control-plane   Ready    control-plane,master   11m   v1.22.15
  • 同样首先创建一个名为 sa-demo 的 ServiceAccount 对象
[root@docker ~]#kubectl create sa sa-demo
serviceaccount/sa-demo created
[root@docker ~]#kubectl get sa
NAME      SECRETS   AGE
default   0         68s
sa-demo   0         5s
[root@docker ~]#kubectl get secret
No resources found in default namespace.

我们可以看到该 ServiceAccount 创建后并没有创建对应的 Secret 对象。

  • 同样接下来创建一个如下所示的 Pod
# demo-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo
spec:
  serviceAccount: sa-demo
  containers:
    - name: demo
      image: nginx:1.7.9
      ports:
        - containerPort: 80

创建上面的 Pod 后查看详情

[root@docker ~]#kubectl apply -f demo-pod.yaml
pod/demo created
[root@docker ~]#kubectl get po
NAME   READY   STATUS    RESTARTS   AGE
demo   1/1     Running   0          43s

[root@docker ~]#kubectl get po demo -oyaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"demo","namespace":"default"},"spec":{"containers":[{"image":"nginx:1.7.9","name":"demo","ports":[{"containerPort":80}]}],"serviceAccount":"sa-demo"}}
  creationTimestamp: "2023-02-05T06:40:36Z"
  name: demo
  namespace: default
  resourceVersion: "665"
  uid: d2db49c4-52bd-426b-9571-c40df6a39d3e
spec:
  containers:
  - image: nginx:1.7.9
    imagePullPolicy: IfNotPresent
    name: demo
    ports:
    - containerPort: 80
      protocol: TCP
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:#这里
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-5mklv
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  nodeName: kind125-control-plane
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: sa-demo
  serviceAccountName: sa-demo
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:#这里
  - name: kube-api-access-5mklv
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: "2023-02-05T06:40:36Z"
    status: "True"
    type: Initialized
  - lastProbeTime: null
    lastTransitionTime: "2023-02-05T06:41:10Z"
    status: "True"
    type: Ready
  - lastProbeTime: null
    lastTransitionTime: "2023-02-05T06:41:10Z"
    status: "True"
    type: ContainersReady
  - lastProbeTime: null
    lastTransitionTime: "2023-02-05T06:40:36Z"
    status: "True"
    type: PodScheduled
  containerStatuses:
  - containerID: containerd://4156c2683a99e178d6ed749014afbb7036c9f47c9ada5982076795807958b10c
    image: docker.io/library/nginx:1.7.9
    imageID: sha256:35d28df486f6150fa3174367499d1eb01f22f5a410afe4b9581ac0e0e58b3eaf
    lastState: {}
    name: demo
    ready: true
    restartCount: 0
    started: true
    state:
      running:
        startedAt: "2023-02-05T06:41:10Z"
  hostIP: 172.18.0.2
  phase: Running
  podIP: 10.244.0.5
  podIPs:
  - ip: 10.244.0.5
  qosClass: BestEffort
  startTime: "2023-02-05T06:40:36Z"
[root@docker ~]#

可以看到创建 Pod 后同样会自动添加一个投射卷到 Pod此卷包括了访问 Kubernetes API 的令牌和>=1.21版本 && <=1.23版本 表现是一致的。

  • 同样我们可以下查看 Pod 中的 token 值来进行验证
[root@docker ~]#kubectl exec -it demo -- cat /run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6Im9makVWMHN5dUZnYVFCckJZM1RnUmJJaTFZc1htOG5LcnR5NWNMYVgxd0EifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzA3MTE1MjM2LCJpYXQiOjE2NzU1NzkyMzYsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJkZW1vIiwidWlkIjoiZDJkYjQ5YzQtNTJiZC00MjZiLTk1NzEtYzQwZGY2YTM5ZDNlIn0sInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJzYS1kZW1vIiwidWlkIjoiM2EyOWI2ZTYtZTFmZS00NmJiLWExNmYtM2EzMjg4M2FkODVhIn0sIndhcm5hZnRlciI6MTY3NTU4Mjg0M30sIm5iZiI6MTY3NTU3OTIzNiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6c2EtZGVtbyJ9.9k5IEccHUiewSRU_6uEdBY1cykk-frXm_A1X_R1TDkOIShmttc5-XmrST0a45-HX2I2eFkVyvXnuyRCJJh8IT_30kcsuZF3rMZiYBPsi9ybnDtwWK_yZFXiHO9p-3AJ4kxFURmnzcTCbpI6yng58qRJCL1VdVSQ2a6nNrEAa6Mqr0N58o89msEJqdgVnPccDnGhjT7IzEXkV42devSvxtz2hLb53Pb91AsDJqK26bseq88la26ENfl24Q17WkaOU5MmqaqUnk2KPTRUWL5kFhxltr4LJCvTCJLLA2NylNBzVGXsuTxEvS90P2__HS2y0fpNp4SfgV27YABOszCyOTA[root@docker ~]#
  • 我们可以把上面输出的 token 值拷贝到 jwt.io 里进行解码。

image-20230205144327903

从上面的数据可以看到这里的 token 的有效期也为 1 年这个 token 在 Pod 里也是每 1 小时会更新一次如果Pod 被删除重建那么会重新申领一个新的 token被删除 Pod 里的 token 立即过期。

需要注意的没有特定的机制使通过 TokenRequest 签发的令牌无效如果你不再信任为某个 Pod 绑定的ServiceAccount 令牌你可以删除该 Pod删除 Pod 将使其绑定的令牌过期。

测试结束。😘

总结

我们可以简单总结下不同版本的 K8s 集群下面的 ServiceAccount Token 是如何工作的。

  • 1.20含 1.20之前的版本在创建 sa 时会自动创建一个 secret然后这个会把这个 secret 通过投射卷挂载到 pod 里该 secret 里面包含的 token 是永久有效的。

  • 1.21~1.23 版本在创建 sa 时也会自动创建 secret但是在 pod 里并不会使用 secret 里的 token而是由kubelet 到 TokenRequest API 去申请一个 token该 token 默认有效期为一年但是 pod 每一个小时会更新一次 token。

  • 1.24 版本及以上在创建 sa 时不再自动创建 secret 了只保留由 kubelet 到 TokenRequest API 去申请token。

当然我们仍然可以手动创建 Secret 来保存 ServiceAccount 令牌例如在你需要一个永不过期的令牌的时候。一旦手动创建一个 Secret 并将其关联到 ServiceAccountKubernetes 控制平面就会自动将令牌填充到该 Secret 中。

尽管存在手动创建长久 ServiceAccount 令牌的机制但还是推荐使用 TokenRequest 获得短期的 API 访问令牌。

2为 ServiceAccount 分配权限

💘 实战为 ServiceAccount 分配权限-2023.2.5(测试成功)

image-20230205180709817

  • 实验环境
实验环境
1、win10,vmwrokstation虚机
2、k8s集群3台centos7.6 1810虚机1个master节点,2个node节点
   k8s versionv1.25.4
   containerd://1.6.10
  • 实验软件无

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

  • 首先来创建一个 ServiceAccount 对象
[root@master1 ~]#kubectl create sa cnych-sa -n kube-system
serviceaccount/cnych-sa created

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

apiVersion: v1
kind: ServiceAccount
metadata:
  name: cnych-sa
  namespace: kube-system
  • 然后新建一个 Role 对象
# cnych-sa-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cnych-sa-role
  namespace: kube-system
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

可以看到我们这里定义的角色没有创建、删除、更 创建、删除、更新新 Pod 的权限待会我们可以重点测试一下

  • 创建该 Role 对象
[root@master1 ~]#kubectl apply -f cnych-sa-role.yaml
role.rbac.authorization.k8s.io/cnych-sa-role created
  • 然后创建一个 RoleBinding 对象将上面的 cnych-sa 和角色 cnych-sa-role 进行绑定
# cnych-sa-rolebinding.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: cnych-sa-rolebinding
  namespace: kube-system
subjects:
  - kind: ServiceAccount
    name: cnych-sa
    namespace: kube-system
roleRef:
  kind: Role
  name: cnych-sa-role
  apiGroup: rbac.authorization.k8s.io
  • 添加这个资源对象
[root@master1 ~]#kubectl apply -f cnych-sa-rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/cnych-sa-rolebinding created

然后我们怎么去验证这个 ServiceAccount 呢以前的版本 ServiceAccount 会自动生成一个 Secret 对象和它进行映射这个 Secret 里面包含一个 token可以利用这个 token 去登录 Dashboard然后就可以在 Dashboard 中来验证我们的功能是否符合预期了但是现在的版本默认已经不支持这种方式了。

但是我们可以手动创建一个长久有效的 ServiceAccount 令牌要为 ServiceAccount 创建一个不过期、持久化的API 令牌需要创建一个类型为 kubernetes.io/service-account-token 的 Secret附带引用ServiceAccount 的注解。控制平面随后生成一个长久的令牌并使用生成的令牌数据更新该 Secret。

  • 比如我们这里可以创建一个如下所示的 Secret 资源对象
# cnych-token.yaml
apiVersion: v1
kind: Secret
metadata:
  name: cnych-sec
  namespace: kube-system
  annotations:
    kubernetes.io/service-account.name: cnych-sa
type: kubernetes.io/service-account-token

也可以直接 kubectl create token 命令来创建 token。

部署

[root@master1 ~]#kubectl apply -f cnych-token.yaml
secret/cnych-sec created
  • 创建后我们就可以使用该 Secret 对象包含的 token 去登录我们的 Dashboard。
[root@master1 ~]#kubectl get secret cnych-sec -o jsonpath={.data.token} -n kube-system |base64 -d
eyJhbGciOiJSUzI1NiIsImtpZCI6ImJXaFVwN29KX0lXODl6SGtFZTN4TklxYnNiQzlmeExpb0dqQ2JYbFNBS3MifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjbnljaC1zZWMiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiY255Y2gtc2EiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI3MzMyZWI3ZC1iYTE1LTQ1MjktOGQ0My1iZjYwYjVjMTliMzQiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06Y255Y2gtc2EifQ.UZoduMQCp9rh5IiHqoQKxj_0MXkvmV3lgURZF5XDUmrhYOgIhKdv3HhCap8FFooZ4rjABZM7c818JuH_rye9RrxN6W85wdPYyur5Rps4vCmHVD4mCOrW3m2OwQgC0ADCtQjYobvYFQfuIiI5DpABngG0mtW_CbqOAQyI9junbcvYQjZ0xRaueCKBK449WIKYdY-lHYRhyEMsqKwaO61u2_rQjn5ZiJuYwaJKzKCG9J7UxOKn4kVHR9mwvSLLAhuB03rIYHuqLf5rJrzRvEc_W8GdVeqhFU7uKE7KrD7PX_398eVBPTNQEvsAKwpwVh6T1KHKHE_k9Jl6Q0w9-LDwxA[root@master1 ~]#
  • 使用这里的 token 去 Dashboard 页面进行登录

image-20230205161839335

我们可以看到上面的提示信息说我们现在使用的这个 ServiceAccount 没有权限获取当前命名空间下面的资源对象这是因为我们登录进来后默认跳转到 default 命名空间我们切换到 kube-system 命名空间下面就可以了需要手动修改浏览器中的 url 地址

image-20230205180709817

image-20230205180809850

我们可以看到可以访问 pod 列表了但是也会有一些其他额外的提示 events is forbidden: User“system:serviceaccount:kube-system:cnych-sa” cannot list events in the namespace “kubesystem” 这是因为当前登录用只被授权了访问 pod 和 deployment 的权限同样的访问下 deployment 看看可以了吗

同样的你可以根据自己的需求来对访问用户的权限进行限制可以自己通过 Role 定义更加细粒度的权限也可以使用系统内置的一些权限……

测试结束。😘

💘 实战cka-rbac考试题-创建sa并赋予权限-2023.2.6(测试成功)

image-20230206212352305

解答

image-20230206212403907

1、切换环境
kubectl config use-context kubernetes

2、配置
kubectl create clusterrole deployment-clusterrole --verb=create --resource=deployments,daemonsets,statefulsets
kubectl create serviceaccount cicd-token -n app-team1
# 题目中写了“限于 namespace app-team1 中”则创建 rolebinding。没有写的话则创建 clusterrolebinding。
kubectl create rolebinding cicd-token-rolebinding --serviceaccount=app-team1:cicd-token --clusterrole=deployment-clusterrole -n app-team1
# rolebinding 后面的名字 cicd-token-rolebinding 随便起的因为题目中没有要求如果题目中有要求就不能随便起了。

3、验证
#稍微验证下
kubectl describe rolebinding cicd-token-rolebinding -napp-team1

3.可以全局访问的 ServiceAccount

💘 实战可以全局访问的 ServiceAccount-2023.2.5(测试成功)

image-20230205181704742

刚刚我们创建的 cnych-sa 这个 ServiceAccount 和一个 Role 角色进行绑定的如果我们现在创建一个新的ServiceAccount需要他操作的权限作用于所有的 namespace这个时候我们就需要使用到 ClusterRole 和ClusterRoleBinding 这两种资源对象了。

  • 同样首先新建一个 ServiceAcount 对象
# cnych-sa2.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: cnych-sa2
  namespace: kube-system

创建

[root@master1 ~]#kubectl create -f cnych-sa2.yaml
serviceaccount/cnych-sa2 created
  • 然后创建一个 ClusterRoleBinding 对象
# cnych-clusterolebinding.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: cnych-sa2-clusterrolebinding
subjects:
  - kind: ServiceAccount
    name: cnych-sa2
    namespace: kube-system
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 这个集群角色是拥有最高权限的集群角色所以一般需要谨慎使用该集群角色。

部署

[root@master1 ~]#kubectl apply -f cnych-clusterolebinding.yaml
clusterrolebinding.rbac.authorization.k8s.io/cnych-sa2-clusterrolebinding created
  • 创建上面集群角色绑定资源对象然后我们可以使用 kubectl create token 命令来创建一个新的 token 去登录Dashboard
[root@master1 ~]# kubectl create token cnych-sa2 -n kube-system
eyJhbGciOiJSUzI1NiIsImtpZCI6ImJXaFVwN29KX0lXODl6SGtFZTN4TklxYnNiQzlmeExpb0dqQ2JYbFNBS3MifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNjc1NTk1NzY5LCJpYXQiOjE2NzU1OTIxNjksImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJjbnljaC1zYTIiLCJ1aWQiOiI2ZTA1NWM4MC0wMjdmLTQ1NzAtODhlMi1hZDJkMzdkM2I1NjEifX0sIm5iZiI6MTY3NTU5MjE2OSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmNueWNoLXNhMiJ9.ndUpljUIvFVIb-3dibZ_j8ZL4e5K4w5gqLlfZ1HK4K2C5bW-Ax3_ACNTz7BhdwRxQoT6mBWgIjuxyvqq7RuyCvleDRPq0x_9xgKIkl4I6jzX-XoexIO6HkskxtsCff8XkkyCfmdyD5bxnRUWvOCqr28d5E9C0gXwEv9LOasSkn4ebdcfV3HpFGtk0wpP04atVLq-deZh2iMSbSj8ttI0I6T3AKMN_upmJv5ivBfGgkJuHgi_R8iNj4uY780cA2j6shdA9maG8TyJmoeU7kPaOlLWL8ZcZqalMg7240gcGAyjKj3sOjNZViI3NO-a3nJ6Ow0a7VZ9jn1jgOaEzlB4rA
[root@master1 ~]#

可以看到使用该 token 登录后没有出现任何权限相关错误了

image-20230205181704742

我们在最开始接触到 RBAC 认证的时候可能不太熟悉特别是不知道应该怎么去编写 rules 规则大家可以去分析系统自带的 clusterrole、clusterrolebinding 这些资源对象的编写方法怎么分析还是利用 kubectl 的 get、describe、 -o yaml 这些操作所以 kubectl 最基本的操作用户一定要掌握好。

测试结束。😘

FAQ

问题ClusterRoleBinding可以绑定role吗

结论不可以。

image-20230203072622073

⚠️ 注意角色和绑定之间的对应关系

一般来说如下是对应绑定的但是也可以rolebinding和clusterrole对应
role --> rolebinding 有ns之说
clusterrole --> clusterrolebinding 无ns之说

serviceaccount 有ns之说

cluster-admin 是拥有最高权限的集群角色

这里我们使用的 cluster-admin 这个集群角色是拥有最高权限的集群角色所以一般需要谨慎使用该集群角色。

[root@master1 ~]# kubectl  get clusterrole
NAME                                                                   CREATED AT
……
cluster-admin                                                          2021-10-31T00:00:22Z
……

image-20230206205553097

Role资源清单文件里rules字段可以按如下方式编写

1.可以把不同apiGroup放在一起
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cnych-role
  namespace: kube-system
rules:
- apiGroups: ["", "apps"]
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']
  
2.或者把不同apiGroup分开写
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: cnych-role
  namespace: kube-system
rules:
- apiGroups: [""] #核心组
  resources: ["pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*'] 
- apiGroup: ["apps"] #apps组
  resources: ["deployments", "replicasets", "pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 也可以使用['*']   
  
3.参考cluster-admin 这个cluster-role
[root@master1 ~]#kubectl get clusterrole cluster-admin -nkube-system -oyaml
rules:
- apiGroups: #资源对象
  - '*'
  resources:
  - '*'
  verbs:
  - '*'
- nonResourceURLs: #非资源对象
  - '*'
  verbs:
  - '*'

Forbidden字段报错更大可能性要想到的可能是权限问题

我们可以先给业务一个小的权限可根据报错来进一步看他们需要什么权限
[root@master1 rbac]#kubectl get svc --context=cnych-context
Error from server (Forbidden): services is forbidden: User "cnych" cannot list resource "services" in API group "" in the namespace "kube-system"
[root@master1 rbac]#

我们可以去分析系统自带的 clusterrole、clusterrolebinding 这些资源对象的编写方法

我们在最开始接触到 RBAC 认证的时候可能不太熟悉特别是不知道应该怎么去编写 rules 规则大家可以去分析系统自带的 clusterroleclusterrolebinding 这些资源对象的编写方法怎么分析还是利用 kubectl 的 get、describe、 -o yaml 这些操作所以 kubectl 最基本的操作用户一定要掌握好。

kubectl get clusterrole system:basic-user  -nkube-system -oyaml
kubectl get clusterrole cluster-admin  -nkube-system -oyaml
kubectl get clusterrole view  -nkube-system -oyaml

我们可以通过如下命令来查看当前用户在k8s中拥有哪权限

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

关于我

我的博客主旨

  • 排版美观语言精炼
  • 文档即手册步骤明细拒绝埋坑提供源码
  • 本人实战文档都是亲测成功的各位小伙伴在实际操作过程中如有什么疑问可随时联系本人帮您解决问题让我们一起进步

🍀 微信二维码
x2675263825 舍得 qq2675263825。

image-20230107215114763

🍀 微信公众号
《云原生架构师实战》

image-20230107215126971

🍀 博客
www.onlyyou520.com

image-20230107215612315

image-20230107215651525

🍀 csdn
https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

image-20230107215149885

🍀 知乎
https://www.zhihu.com/people/foryouone

image-20230107215203185

最后

好了关于本次就到这里了感谢大家阅读最后祝大家生活快乐每天都过的有意义哦我们下期见

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: k8s