3、RBAC
RBAC
目录
[toc]
本节实战
实战名称 |
---|
💘 实战:查看k8s里api对象-2023.1.18(测试成功) |
💘 实战1:只能访问某个 namespace 的普通用户-2023.2.3(测试成功)(openssl) |
💘 实战2:对用户授权访问K8s(TLS证书-cfgssl)-2023.2.6(测试成功)(cfgssl) |
💘 实战:<=1.20 k8s版本sa测试-2023.1.18(测试成功) |
💘 实战 :对应用程序授权访问K8s(ServiceAccount)-2023.5.24(测试成功) |
💘 实战:>=1.21版本 && <=1.23版本sa测试-2023.1.18(测试成功) |
💘 实战:>=1.24版本sa测试-2023.2.5(测试成功) |
💘 实战:为 ServiceAccount 分配权限-2023.2.5(测试成功) |
💘 实战:命令行配置sa权限-2023.5.24(测试成功) |
💘 实战: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 里的完整资源路径,是由:Group(API 组)
、Version(API 版本)
和 Resource(API 资源类型)
三个部分组成的。通过这样的结构,整个 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 对象的资源类型(Resource),apps
就是它的组(Group),v1
就是它的版本(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 version:v1.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 中简称为GVK,GVK 是定位一种类型的方式,例如 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呢
方法1:kubectl explains命令
[root@master1 rbac]#kubectl explain pod
KIND: Pod
VERSION: v1
……
方法2:kubectl 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、Kubernetes 安全框架
• K8S安全控制框架主要由下面3个阶段进行控制,每一个阶段都支持插件方式,通过API Server配置来启用插件。
- Authentication(鉴权)
- Authorization(授权)
- Admission Control(准入控制)
• 客户端要想访问K8s集群API Server,一般需要证书、Token或者用户名+密码;如果Pod访问,需要ServiceAccount
#形象记忆
门卫:鉴权
门禁卡:授权
准入控制:安全扫描设备