k8s之RBAC
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
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 对象实际上就可以用如下的树形结构表示出来
从上图中我们也可以看出 Kubernetes 的 API 对象的组织方式在顶层我们可以看到有一个核心组由于历史原因是 /api/v1
下的所有内容而不是在 /apis/core/v1
下面和命名组路径 /apis/$NAME/$VERSION
和系统范围内的实体比如 /metrics
。
比如我们来查看批处理这个操作在我们当前这个版本中存在两个版本的操作/apis/batch/v1
和 /apis/batch/v1beta1
分别暴露了可以查询和操作的不同实体集合。
通常Kubernetes API 支持通过标准 HTTP POST
、PUT
、DELETE
和 GET
在指定 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(测试成功)
- 实验环境
实验环境
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 了
- 如果想看系统支持哪些 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。
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 的形式来的而组织的路径就是
我们这里不是说是 G(roup)V(ersion)K(ind) 吗怎么现在又变成了 G(roup)V(ersion)R(esource) 这就是API Server 中的第二个概念 GVR。
2.GVR
理解了 GVK 之后再理解 GVR 就很容易了这就是面向对象编程里面的类和对象的概念是一样的
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 以及支持的操作等。
在代码中其实就对应于这个接口
这样就把 GVK 和 GVR 联系起来了。
noResources
如何确定某个资源对象属于哪个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]#
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;
接下来我们来通过几个简单的示例来学习下在 Kubernetes 集群中如何使用 RBAC。
1.只能访问某个 namespace 的普通用户
💘 实战1只能访问某个 namespace 的普通用户-2023.2.3(测试成功)openssl
- 实验环境
实验环境
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"
因此需要按如下思路去操作
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
- 实验环境
实验环境
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实验软件
- 背景
案例为指定用户授权访问不同命名空间权限例如新入职一个小弟希望让他先熟悉K8s集群为了安全性先不能给他太大权限因此先给他授权访问default命名空间Pod读取权限。
实施大致步骤
- 用K8S CA签发客户端证书
- 生成kubeconfig授权文件
- 创建RBAC权限策略
- 指定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签发客户端证书
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文件
此时我们可以测试下
[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"]
……
再次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
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
🍀 画图说明
⚠️ 注意2种方式访问k8s集群serviceaccount只能在pod里使用
1.集群外访问kubectl
2.集群内访问sa
但是需要注意的是不同的 K8s 版本对该 token 文件的使用是不一样的所以我们可以分几个版本来分别讨论下。
1<=1.20版本
💘 实战<=1.20 k8s版本sa测试-2023.1.18(测试成功)
- 实验环境
实验环境
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/
右侧部分显示了 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(测试成功)
- 实验环境
实验环境
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 网站进行解码。
从解码后的值可以看到该 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值。
可以看到该 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(测试成功)
- 实验环境
实验环境
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 里进行解码。
从上面的数据可以看到这里的 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(测试成功)
- 实验环境
实验环境
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 页面进行登录
我们可以看到上面的提示信息说我们现在使用的这个 ServiceAccount 没有权限获取当前命名空间下面的资源对象这是因为我们登录进来后默认跳转到 default 命名空间我们切换到 kube-system 命名空间下面就可以了需要手动修改浏览器中的 url 地址
我们可以看到可以访问 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(测试成功)
解答
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(测试成功)
刚刚我们创建的 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 登录后没有出现任何权限相关错误了
我们在最开始接触到 RBAC 认证的时候可能不太熟悉特别是不知道应该怎么去编写 rules 规则大家可以去分析系统自带的 clusterrole、clusterrolebinding 这些资源对象的编写方法怎么分析还是利用 kubectl 的 get、describe、 -o yaml 这些操作所以 kubectl 最基本的操作用户一定要掌握好。
测试结束。😘
FAQ
问题ClusterRoleBinding可以绑定role吗
结论不可以。
⚠️ 注意角色和绑定之间的对应关系
一般来说如下是对应绑定的但是也可以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
……
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 规则大家可以去分析系统自带的 clusterrole
、clusterrolebinding
这些资源对象的编写方法怎么分析还是利用 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。
🍀 微信公众号
《云原生架构师实战》
🍀 博客
www.onlyyou520.com
🍀 csdn
https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421
🍀 知乎
https://www.zhihu.com/people/foryouone
最后
好了关于本次就到这里了感谢大家阅读最后祝大家生活快乐每天都过的有意义哦我们下期见