目录
ClusterRoleBinding+ClusterRole
1、机制说明
kubernetes作为一个分布式集群的管理工具,保证集群的安全性是其一个重要任务。API Server是集群内部各个组件通信的中介,也是外部控制的入口。所以kubernetes的安全机制基本就是围绕保护API Server来设计的
图片解析,当用户或者Pod服务要访问k8s集群内部的一些资源就要3A机制,也就是经过三个步骤,这三个步骤都封装在了API Server内部,并且按序进行
- Authentication(验证/认证):验证用户或者服务是否是有来到进群内部的资格,就像进公司刷门禁卡
- AUthorization(鉴权/授权):鉴定用户或服务的权利,可以干什么不能干什么
- AdmissionControl(准入控制):在认证和授权通过后,还可以进一步检查请求是否满足集群的策略要求。就像进了公司,有了进机房的权利,但是你不能放火,放火就会阻止你
2、认证
认证有三种类型
- HTTP Token:通过一个Token来识别合法用户
- 它的认证用一个很长的特殊编码方式的并且难以被模仿的字符串-Token来表达客户的一种方式。Token是一个很长很复杂的字符串,每个Token对应一个用户名存储在APIServer能访问的文件中。当客户端发起API调用请求是,需要在HTTP Header里放入Token
- HTTP Base:通过用户名+密码的方式认证
- 用户名和密码用BASE64算法进行编码后的字符串放在HTTP Request中的Header Authorization域里发送给服务端,服务端收到后进行编码,获取用户名、密码
- HTTPS:最严格的证书认证,基于CA根证书签名的客户端身份认证方式
- https认证分为单向和双向
- 单向:比如访问百度,是我们需要认证百度的资质,百度服务器向用户提供身份认证,客户端通过验证服务器的数字证书确保服务器的真实性,客户端无需向服务器提供认证信息
- 双向:比如ATM机,需要银行和我们双向认证。就是客户端除了验证服务器的数字证书外,还需要向服务器提供自己的证书。服务器和客户端都要向对方提供认证
- https认证分为单向和双向
而k8s用的就是用的https双向认证,认证流程如下图
简单来说就是张三(client)想和李四(server)做生意,但是双方互不认识。
这时王二(CA)出现了,德高望重。分别给了张三、李四一张推荐信(证书)。到了两人见面时候了,李四先给出自己的推荐信,张三一看推荐信确认是李四了,这时候在把自己的推荐信给李四看,双方通过认证以后,就可以关起门发财了(加密通讯)
就是这么个流程
组件和插件对apiserver的访问
kubernetes组件对API Server的访问
- kubectl:命令行工具 ,命令需要传达给apiserver去处理
- Controller Manger:通过apiserver确认每个节点的控制器、pod状态
- Scheduler:通过apiserver监听各个节点的状态进行Pod的调度
- kubelet:通过apiserver监听当前节点需要运行的Pod,通过调用CRI接口实现容器的创建
- kube-proxy:监听apiserver当前节点相关的ipvs规则合法防火墙规则,实现规则的制定
从上面组件可以看到集群中自带的组件都需要对apiversion发起访问。还有一些插件比如calico,dns这些插件是Pod方式工作在集群中的,当然部分组件也是这种形式。
所以calico、dns这些插件如果不访问apiserver的话,怎么知道哪些Pod需要分配IP地址,需要进行dns解析呢
API Server需要认证的类型
先说组件,无需加密的组件:
- Contorller Mangeer、Scheduler和API Server。
因为在同一台机器,所以直接用API Server的非安全端口访问“--insecure-bind-address=127.0.0.1”。基于kubeadm安装的方式它们才在一起,二进制安装的话不一定,所以二进制安装的话它们也需要双向认证
需要加密的组件分两种,手动颁发证书和自动颁发证书:
- 手动颁发证书:kube-proxy、kubectl通过k8s集群的根CA进行签发HTTPS证书。
从集群的安装到目前都没有做过手动签发证书的操作,因为基于kubeadm安装的方式,它已经把手动签发证书的操作替我们给做了,并不是不需要手动签发
- 自动颁发证书:kubelet。kubelet首次访问API Server时,使用token做认证,通过后Controller Manager会为kubelet生成一个证书,以后的访问就都是用证书做认证了。
为什么apiserver会如此信任kubelet会给它自动签发证书?来看下
kubeadm join 192.168.176.101:6443 --token 7vw0x2.yhu1b4sob2fem9a5 --discovery-token-ca-cert-hash sha256:6126cbbab761e2f56c3a9bf1cfc590ad05508b289552bd9ea683ef629b929f20 --cri-socket unix:///var/run/cri-dockerd.sock
192.168.176.101:6443 --token 7vw0x2.yhu1b4sob2fem9a5
先看命令前半部分,这个就是集群给node节点颁发的令牌,在令牌时效内用这个令牌访问apiserver,它就把这个node当作自己人
--discovery-token-ca-cert-hash sha256:6126cbbab761e2f56c3a9bf1cfc590ad05508b289552bd9ea683ef629b929f20
再看命令后半部分,这是当前CA证书的哈希值,用来给kubelet确认apiserver是否合法,防止它认错人。当kubbelet拿着集群给的令牌找apiserver时候,apiserver会拿出自己的证书给kubelet看,kubelet会用哈希值和apiserver证书的哈希值做确认。这是就是一个双向加密的方式
再说Pod,先想一个问题,组件和是集群同生死的,签发证书没问题。但是Pod的寿命是动态的,有1000个Pod就要签发1000次证书么?要是刚签发完证书Pod就死了呢?
所以Pod认证不是通过双向认证做到的,而是另一个东西Service Account
ps:部分组件也是pod状态运行的,
ServiceAccount(SA)
Pod中的容器访问API Server,因为Pod的创建、销毁是动态的,所以要为他手动生成证书就不可行了。k8s用了sa来解决Pod访问apiserver的认证问题
ServiceAccount的组成
k8s设计了一种资源对象叫Secret,分为两类。一种是用于sa的Service-account-token,另一种是用于保护用户自定义保密信息的Opaque。sa中用到三个文件:
- ca.crt:根证书。用于client端验证API Server发送的证书
- token:根据API Server私钥基于JWT规范签发出来的字符串。用于Pod访问API Server时的Server端认证
- namespace:标识这个servcie-account-token的作用域名空间。因为Pod是名称空间级别的,而apiserver是集群级别,名称空间级别访问集群级别时候,就要告诉集群Pod在什么名字空间上
Json web token(JWT)。不用了解太多,只要知道它的主要功能:适用于分布式站点的单点登录(SSO)场景。
通俗来说就是A访问B,B不需要访问A,这就是单点登录。在集群中就是Pod访问API Server,但是API Server不可能访问Pod
ServiceAccount补充
默认情况下,每个namespace都会有个SA,如果Pod在创建时没有指定SA,就会使用Pod所属的namespace中的SA。
如上图,新创建了一个ns,然后get ns就可以看到默认的sa,如果在test这个ns下运行pod,pod就会默认调用此sa发起对apiserver的访问,如果需要的话
当pod使用了sa后,它会挂载到容器内的这个路径下
/run/secrets/kubernetes.io/serviceaccount/
认证过程一图流
kubeconfig
kubeconfig这个文件包含了集群参数(CA证书、API Server地址),客户端参数(证书和私钥),集群context信息(集群名称、用户名)。k8s组件通过启动是指定不同的kubeconfig文件可以切换到不同的集群
其实在一开始就对这个文件进行过操作了,还记得集群安装结束后提醒我们要执行的命令吗?
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
这个admin.conf文件就是kubeconfig文件类型
看下文件中有什么
这个文件就是管理员通向集群的钥匙,相当关键。kubernetes-admin
用户是由 kubeadm
默认创建的管理员用户
当kubectl执行命令时候,就会调用当前家目录的.kube/config文件来加载配置。通过这个文件,kubectl
知道应该连接哪个集群、使用哪个用户认证以及在哪个命名空间执行操作来试一下。
将文件移动到别的目录然后执行命令,如下图
3、鉴权
上面的认证过程只是确认通信的双方都是可信的,可以互相通信。而鉴权是确定请求方有哪些资源的权限。API Server目前支持以下几种授权策略(可通过API Server的启动参数“--authorization-mode”设置)
- AlwaysDeny :拒绝所有的请求,一般用于测试
- AlwaysAllow:接收所有请求,如果集群不需要授权流程可以采取该策略
- ABAC(Attribute-Based Access Control):基于属性的访问控制,表示使用用户配置的授权规则对用户进行请求匹配和控制。很麻烦,快被淘汰了
- Webhook:通过调用外部REST服务对用户进行授权
- RBAC(Role-Based Access Control):基于角色的访问控制,现行默认规则
RBAC特性优势
RBAC机制在k8s 1.5中引入,现行版本成为了默认标准。相对于其他访问控制方式,拥有以下优势:
- 对进群中的资源和非资源均拥有完整的覆盖
- 整个RBAC完全由几个API对象完成,同其他API对象一样,可以用kubectl或API进行操作
- 可以在运行是调整,无需重启API Server
RBAC资源对象
RBAC引入了4个新的顶级资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding,4种对象类型均可以通过kubectl和API进行操作
图片解析:右边的资源对象,不管是对象的建立、获取还是更新等操作,可以理解为一种权限。将这种权限具象化成Role,再将Role通过RoleBinding和用户、用户组及服务账户进行绑定,使它们拥有对应的权限
通过图片有个大致的了解了,在看下资源对象的绑定关系,分为三种
-
Role必须通过
RoleBinding绑定
,作用范围仅限于命名空间 -
ClusterRole通过ClusterRoleBinding绑定,作用范围是集群
- ClusterRole通过RoleBinding绑定,作用范围仅限于特定命名空间,是特殊的绑定关系
特殊的绑定关系
这种方式其实就是限制ClusterRole的作用域,让它的辐射范围从整个集群,通过RoleBinding限制在各个namespace中
解析上图:现在有四个命名空间,分别在每个命名空间下创建一个用户。如果想让四个用户具备分别管理各自所在空间的管理权限的话,必须要创建Role,然后RoleBinding。算一算分别创建了三个用户、三个角色、三个角色绑定,共12个资源对象
换个方式创建Role看下
解析上图:不在每个ns中创建一个Role,直接创建一个ClusterRole来管理所有ns空间权限,现在随便一个用户ClusterRoleBinding和它进行绑定会怎样? 看图,B-user绑定了ClusterRole,现在它不仅是自己ns的管理员,还是所有ns的。虽然只创建了9个资源对象,但是这样就越权了,不安全
在换个方式看下
看图,创建RoleBinding资源对象的时候,必须在其定义中指定 metadata.namespace
字段,也就是说必须要指定它当前所在的命名空间,这样各个用户在自己所在的ns中用ClusterRole,就等同于在各自ns中有了管理员权限
通俗点说,一个学校校长(admin-ClusterRole)的权利最大它和整个学校(集群)绑定(ClusterRoleBinding);班主任(ABCD-user)在它们各自班级(namespace)的权利(Role)最大,它们和自己的班级绑定(RoleBinding);这时候校长(admin-ClusterRole)来到A班级,把他关在A班(namespace),把它和A班绑定(RoleBindind),他再大的权利也只能在A班级使用,出不去
从第一张图到第三张图,资源对象从12个缩减到了9个,看着不多。
但是如果集群中有10个ns呢?100个呢?
所以通过这种特殊的绑定关系,来减少资源对象的创建,也更容易管理
用户/组哪里来?
前面的理论中提到了权限的的附着点有“用户”、“用户组”、“Service Account”
SA前面说过了创建方式,命令或者资源清单的方式都可以。它背后的ns、ca.crt、token都是自动封装,自动生成。不需要手动干预
kuberctl create sa saName -n nsName
kubectl create sa test --dry-run=client -o yaml
但是在k8s中并没有创建用户和组的相关命令,该怎么获取用户呢?看官方的描述如下:
所有 Kubernetes 集群都有两类用户:由 k8s 管理的服务账号(Service Account)和普通用户。
Kubernetes 假定普通用户是由一个与集群无关的服务通过以下方式之一进行管理的:
- 负责分发私钥的管理员
- 类似 Keystone 或者 Google Accounts 这类用户数据库
- 包含用户名和密码列表的文件
Kubernetes 本身并不内置普通用户的管理功能,也没有专门的 API 对象(如 User 对象)来表示普通用户,普通用户的认证通常依赖于外部机制,比如证书、OAuth、LDAP 或 OpenID Connect(OIDC)。在这里,就说基于证书的用户认证
签发证书是apiserver.crt来签发的,目录在/etc/kubernetes/pki下,参数这里用json格式列出来
{
"CN": "admin" #用户名
"hosts": [], #证书可访问地址,客户端ip/源ip,没写就是什么样的源ip都可以使用此证书
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Hangzhou",
"L": "XS",
"O": "system:masters", #用户组
"OU": "System"
}
]
}
Role
在RBAC API中,Role表示一组权限,权限只会增加(累加权限),不存在一个资源开始就有很多权限然后通过RBAC对其进行减少的操作;Role可以定义在一个namespace中,如果想跨ns则可以创建ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: default # 不写默认就是它,这里方便理解所以写上。
rules:
- apiGroups: [""] # 空字符串表示核心 API 组,例如 Pod 属于核心组。
resources: ["pods"] # 定义资源类型,这里是 pods。
verbs: ["get", "watch", "list"] # 允许的操作,包括获取、监听和列出 Pod。
代码是角色的创建方式
ClusterRole
ClusterRole具有与Role相同的额权限角色控制能力,不同的是ClusterRole是集群级别的,ClusterRole可以用于
- 集群级别的资源控制(如node访问权限)
- 非资源型endpoints(如“/health访问”)
- 所有命名空间资源控制(如pod)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-reader #这里没写命名空间,因为已经是集群级别了,狮子不会住在老鼠洞
rules:
- apiGroup: [""]
resources: ["secrets"]
verbs: ["get","watch","list"]
代码是集群角色的创建方式
RoleBinding+Role
RoleBinding可以将角色中定义的权限授予用户或者用户组,RoleBinding包含一组权限列表(subject),权限列表中包含有不同形式的待授予权限资源类型(users、groups、service account);RoleBinding同样包含对Bind的Role引用;RoleBinding适用于某个命名空间内授权,而ClusterRoleBinding适用于集群范围内的授权
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects: # 定义绑定的用户、组或服务账号。也就是权限的附着点
- kind: User # 绑定的主体类型,这里是单个用户。
name: jane # 用户的名称,必须与认证时的用户名一致。
apiGroup: rbac.authorization.k8s.io # 指定 RBAC 的 API 组。
roleRef: # 定义与哪个 Role 或 ClusterRole 绑定。
kind: Role # 绑定的角色类型,这里是 Role。
name: pod-reader # 绑定的 Role 名称,这里是 pod-reader。
apiGroup: rbac.authorization.k8s.io # 指定 Role 的 API 组。
代码是角色绑定的创建方式
RoleBinding+ClusterRole
RoleBinding同样可以引用ClusterRole来对当前namespace内用户、用户组、Service account进行授权,这种操作允许集群管理员在整个集群内定义一些通用的ClusterRole,然后在不同的namespace中使用RoleBinding来引用
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-secrets
namespace: dev
subject: # 定义绑定的用户、组或服务账号。
- kind: User # 绑定的主体类型,这里是单个用户。
name: dave # 用户的名称,必须与认证时的用户名一致。
apiGroup: rbac.authorization.k8s.io # 指定 RBAC 的 API 组。
roleRef: # 定义与哪个 Role 或 ClusterRole 绑定。
kind: ClusterRole # 绑定的角色类型,这里是 ClusterRole。
name: secret-reader # 绑定的 ClusterRole 名称,这里是 secret-reader。
apiGroup: rbac.authorization.k8s.io # 指定 ClusterRole 的 API 组。
ClusterRoleBinding+ClusterRole
使用ClusterRoleBinding可以对整个集群中的所有命名空间资源权限进行授权;一下ClusterRoleBinding样例展示了授权manager组内所有用户在全部命名空间中随secret进行访问
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subject: # 定义绑定的用户、组或服务账号。
- kind: Group # 绑定的主体类型,这里是一个用户组。
name: manager # 组的名称,所有属于该组的用户都会继承权限。
apiGroup: rbac.authorization.k8s.io # 指定 RBAC 的 API 组。
roleRef: # 定义与哪个 Role 或 ClusterRole 绑定。
kind: ClusterRole # 绑定的角色类型,这里是 ClusterRole。
name: secret-reader # 绑定的 ClusterRole 名称,这里是 secret-reader。
apiGroup: rbac.authorization.k8s.io # 指定 ClusterRole 的 API 组。
概念的补充
Resource子资源
k8s集群内一些资源一般一起名称字符串来表示,这些字符串一般会在API的URL地址中出现,同时某些资源也会包含子资源,例如logs资源就属于pods的子资源,API中RUL样例如下
GET /api/v1/namespace/{namespace}/pods/{name}/logs #相当于获取命名空间下的pod demo的日志
#这个样例就是查看日志时候,其操作的本质:像API发送URL的请求
如果要在RBAC授权模型中控制这些子资源的访问权限,可以通过/分隔符来实现,以下是一个定义pods资源logs访问权限的Role定义样例
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-and-pod-logs-reader
namespace: default
rules:
- apiGroup: [""]
resource: ["pods/log"]
verbs: ["get","list"]
Subject
RoleBinding和ClusterRoleBinding可以将Role绑定到Subject;Subject可以是groups、users或者Service accounts
Subject中使用Users使用字符串表示,它可以是一个普通的名字字符串,如“jim”;也可以是email格式的邮箱地址,如“xxxx@163.com”;甚至可以使一组字符串形式的数字ID。但是Users的前缀system:是系统保留的,集群管理员应该确保普通用户不会使用这个前缀格式
Group书写格式与Users相同,都为同一个字符串,并且没有特定的格式要求;同样system:前缀为系统保留
4、开始实验
前面认证和鉴权一大堆理论,现在将理论化为实践。过程比较繁琐
创建一个用户并且只能管理dev命名空间,流程如下
创建证书》转换为kubeconfig文件》创建命名空间》角色绑定
下载证书生成工具cfssl
比openssl更加方便,openssl太复杂了,而且k8s相关的证书生成都是用这个
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssljson_1.6.5_linux_amd64
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssl_1.6.5_linux_amd64
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.5/cfssl-certinfo_1.6.5_linux_amd64
mv cfssl_1.6.5_linux_amd64 /usr/local/bin/cfssl
mv cfssl-certinfo_1.6.5_linux_amd64 /usr/local/bin/cfssl-certinfo
mv cfssljson_1.6.5_linux_amd64 /usr/local/bin/cfssljson
chmod a+x /usr/local/bin/cfssl
生成证书
最好是在/etc/kubernetes/pki/目录下,比较方便
#创建证书文件,内容是定义证书生成所需的参数,更加的直观
vim devuser.json
{
"CN": "devuser", // CN 表示证书的通用名称 (Common Name),通常是用户名或域名
"hosts": [], // 适用主机列表,空数组表示不限定主机或 IP 地址
"key": { // 定义密钥的相关参数
"algo": "rsa", // 指定密钥的加密算法,这里使用 RSA
"size": 2048 // 指定密钥的长度,2048 位是常见的安全选择
},
"names": [ // 证书的组织信息列表
{
"C": "CN", // 国家代码,CN 表示中国
"ST": "BeiJing", // 省份,这里填写北京
"L": "BeiJing", // 城市,这里填写北京
"O": "k8s", // 组织名称,例如 k8s
"OU": "System" // 组织单位名称,例如 System
}
]
}
#生成证书
cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes devuser.json |cfssljson -bare devuser
#cfssl gencert:调用 cfssl 生成证书。
#-ca=ca.crt:指定根证书(CA 证书)。
#-ca-key=ca.key:指定 CA 的私钥,用来签发证书。
#-profile=kubernetes:指定 Kubernetes 配置文件,以定义证书的策略。
#devuser.json:提供证书请求的 JSON 文件,包含 CN 和组织信息等。
#| cfssljson -bare devuser:将生成的证书输出转换为 .pem 文件,文件名为 devuser
#执行该命令将得到一个新的证书(devuser.pem)、私钥(devuser-key.pem)和可能的 CSR 文件,所有文件的名称以 devuser 为前缀
设置集群参数
#这个命令设置了一个环境变量 KUBE_APISERVER,其值为 Kubernetes API 服务器的URL。192.168.176.101:6443 是 Kubernetes API 服务器的地址和端口。这个地址用于访问集群的控制平面。
这一步是为了便于后续的命令中引用 API 服务器地址。
export KUBE_APISERVER="https://192.168.176.101:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=devuser.kubeconfig
#kubectl config set-cluster kubernetes
kubectl config set-cluster 是 kubectl 命令中的一个子命令,用于设置集群的配置信息。kubernetes 是集群的名称。这个名称将在 kubeconfig 文件中引用该集群。
# --certificate-authority=ca.crt
这个选项指定了一个证书文件 ca.crt,该文件包含 Kubernetes API 服务器的根证书。ca.crt 是用于验证 Kubernetes API 服务器的证书。它确保客户端与 API 服务器的通信是安全的。
# --embed-certs=true
这个选项告诉 kubectl 将证书嵌入到 kubeconfig 文件中,而不是单独引用文件。这意味着 ca.crt 的内容将被直接嵌入 devuser.kubeconfig 文件,而不需要单独的证书文件。
# --server=${KUBE_APISERVER}
这个选项指定了 Kubernetes API 服务器的地址。这里使用的是前面设置的环境变量 ${KUBE_APISERVER},即 https://192.168.176.101:6443。该 URL 用于与 Kubernetes API 服务器通信。
# --kubeconfig=devuser.kubeconfig
这个选项指定了配置文件的路径,即 devuser.kubeconfig。kubectl 将在这个文件中保存集群的配置信息。
总结:
这条命令的目的是为 devuser 创建一个新的 kubeconfig 文件(devuser.kubeconfig),配置与 Kubernetes 集群的连接。它包括以下内容:
集群名称:kubernetes
API 服务器的地址:https://172.20.0.113:6443
CA 证书:ca.crt(嵌入到 kubeconfig 文件中)
执行此命令后,devuser.kubeconfig 将包含访问 Kubernetes 集群所需的配置信息,包括证书、服务器地址等。
图中各种信息问问gpt吧,描述的很详细
设置客户端认证参数
#这条命令会在指定的 devuser.kubeconfig中更新user部分
kubectl config set-credentials devuser \
--client-certificate=devuser.pem \
--client-key=devuser-key.pem \
--embed-certs=true \
--kubeconfig=devuser.kubeconfig
#kubectl config set-credentials devuser
含义设置用户 devuser 的认证信息。
上下文:在 Kubernetes 的配置文件(kubeconfig)中创建或更新一个名为 devuser 的用户条目。
#--client-certificate=devuser.pem
含义:指定用户 devuser 的客户端证书文件。客户端证书通常是一个 .pem 文件,证明用户的身份。
用途:当用户 devuser 通过 kubectl 访问 Kubernetes 集群时,会使用该证书进行身份认证。
#--client-key=devuser-key.pem
含义:指定用户 devuser 的私钥文件。
用途:配合客户端证书,用于完成双向 TLS(双向身份认证),确保通信安全并验证用户身份。
# --embed-certs=true
含义:将证书和私钥的内容直接嵌入到 kubeconfig 文件中,而不是以文件路径的形式引用它们。
优势:提高了配置的独立性和可移植性,因为 kubeconfig 文件中已经包含了所有必要的认证信息。
避免因证书文件丢失或路径不正确导致的问题。
# --kubeconfig=devuser.kubeconfig
含义:指定操作的 kubeconfig 文件为 devuser.kubeconfig。
用途:将用户的认证信息写入或更新到指定的配置文件中,而不是默认的 ~/.kube/config 文件。
总结
这条命令的主要功能是为 devuser 配置基于客户端证书的认证信息,并将其写入到指定的 kubeconfig 文件(devuser.kubeconfig)中。这是 Kubernetes 用户管理中配置认证的重要步骤之一,尤其是在多用户、多角色的场景下
可以看到用户证书信息被添加进来了
设置上下文参数
#命令执行后,devuser.kubeconfig 文件中的 contexts 部分会更新或新增一个名为 kubernetes 的上下文
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=devuser \
--namespace=dev \
--kubeconfig=devuser.kubeconfig
#kubectl config set-context kubernetes
含义:设置一个名为 kubernetes 的上下文。
上下文(context):Kubernetes 的 kubeconfig 文件中,context 是一个逻辑配置项,用于关联:
集群(cluster)
用户(user)
命名空间(namespace)
用途:通过上下文快速切换集群、用户和命名空间的组合。
#--cluster=kubernetes
含义:指定上下文中关联的集群,名称为 kubernetes。
上下文作用:告诉 kubectl 使用配置文件中定义的 kubernetes 集群(在 clusters 部分定义)。
#--user=devuser
含义:指定上下文中关联的用户,名称为 devuser。
上下文作用:告诉 kubectl 使用配置文件中定义的 devuser 用户(在 users 部分定义)。
用户配置示例(来自 devuser.kubeconfig 文件的 users 部分):
#--namespace=dev
含义:指定上下文中关联的命名空间,名称为 dev。
上下文作用:告诉 kubectl 默认在 dev 命名空间中执行操作。
优点:
如果省略 --namespace,kubectl 命令会默认作用于 default 命名空间。
通过设置上下文,避免每次运行 kubectl 命令时都指定 --namespace=dev。
#--kubeconfig=devuser.kubeconfig
含义:指定将上下文配置写入的 kubeconfig 文件为 devuser.kubeconfig。
用途:避免修改默认的 ~/.kube/config 文件,保持独立性和可移植性。
可以看到上下文信息被添加进来了
至此,devuser用户的kubeconfig文件配置结束了,只要拿着这个文件交给kubectl去连接集群,集群就能帮助用户完成认证
创建kubeconfig文件过程就像系统中创建用户。因为k8s没有创建用户的功能,所以通过创建kubeconfig文件,并且在文件中表明用户及它的访问方式,等同于创建用户。但是k8s中用户权限是累加的,不存在开始就有默认权限然后对它进行限制 (个人理解)
权限绑定
上面提到权限是累加的,现在devuser用户没有和Role/ClusterRole进行任何RoleBinding/ClusterRoleBinding的绑定,也就意味着devuser是没有任何权限的,现在进行权限的绑定操作;并且在上下文参数中规定了要在dev的命名空间下操作
#创建dev命名空间
kubectl create ns dev
#创建rolebinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: devuser-admin-binding
namespace: dev
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: devuser
先在default命名空间下创建几个pod,等下有用
kubectl create deployment default-deploy --image=nginx --replicas=3
然后设置默认上下文
kubectl config use-context kubernetes --kubeconfig=devuser.kubeconfig
#kubectl config use-context:
这是 kubectl 的一个子命令,用于切换当前的上下文(context)。
Kubernetes 的上下文是一个配置集,包括了 集群(cluster)、用户(user) 和 命名空间(namespace),它定义了 kubectl 的默认行为,例如操作哪个集群,使用哪个用户身份,以及默认命名空间。
kubernetes
这是目标上下文的名称。此命令会将当前的上下文切换为名为 kubernetes 的上下文。
具体的上下文名字是根据 kubeconfig 文件中定义的配置而定,kubernetes 是这里的示例名称。
--kubeconfig=devuser.kubeconfig:
指定了 kubeconfig 文件的路径(此处为 devuser.kubeconfig)。
默认情况下,kubectl 使用位于 ~/.kube/config 的配置文件。如果你有多个 kubeconfig 文件,并想使用特定的文件,可以通过这个选项指定。
在这里,kubectl 将使用 devuser.kubeconfig 文件中的内容,而不是默认的配置文件。
mv /root/.kube/config /root/
cp -a /etc/kubernetes/pki/devuser.kubeconfig /root/.kube/config
这个步骤就相当于切换到devuser用户了,在来验证用户的权限
看上图, 查看全部pod是没有权限的,上面提到过权限是累加的,没有累加之前权限为空。所以devuser只给了它dev命名空间下的相关管理员权限,并没有给default空间的权限
#在dev名字空间下创建个控制器
kubectl create deployment test-deploy --image=nginx --replicas=10
再将初始kubeconfig放回原位
看上图,所有pod都能看到了
现在有两个kubeconfig文件了,一个admin,一个devuser。假设A要在集群内进行操作
管理员和A说:有两个文件,一个是dev空间操作管理,一个是集群内随便操作,你看想要实现什么样的功能,再去拿对应文件。
那A想了,为什么不拿集群文件呢?谁来直接拿集群文件不就行了,为什么我要被限制权限?
那么基于这个想法,用户的划分还有什么意义呢?所以,能不能配合当前linux系统用户,去做到用户级别的隔离?
基于系统用户的权限隔离(非必须,一个扩展)
现在有devuser这个用户,而它就是管理dev命名空间的管理员,然后和它说要连接的服务器地址是192.168.176.101;用户是dev,密码是123。就可以连接到linxu服务器中,它默认的权限就是devuser,这才是最舒服的状态。如何做到?
kubectl会默认寻找当前用户家目录的.kube/confg文件。如果在linux中创建一个dev用户,它也有自己的家目录,只要把刚才创建的那个config放在这个家目录下就可以了
试一下
useradd dev
passwd dev
mkdir /home/dev/.kube
mv dev-config /home/dev/.kube/config
chown -R dev:dev /home/dev/.kube/
再开个终端,用dev用户进行登录
完全没有问题
补充-资源与角色类型的匹配
访问的资源 | 使用的角色类型 | 使用的绑定类型 |
集群级别资源 (Nodes、PersistentVolumes...) | ClusterRole | ClusterRoleBinding |
非资源型URL (/api、/healthz...) | ClusterRole | ClusterRoleBinding |
在任何命名空间中的资源 (和跨所有命名空间的资源) | ClusterRole | ClusterRoleBinding |
在具体命名空间中的资源 (在多个命名空间中重复使用ClusterRole RoleBinding) | ClusterRole | RoleBinding |
在具体命名空间中的资源 (Role必须在每个命名空间中定义好) | Role | RoleBinding |
不管是集群角色还是角色,都可以自己去编写创建。还有很多基础类型的权限角色,官方给我们准备好了,用kubectl get clusterrole可以查一下。“system:“”开头的都是集群用的
除此以外还有一些没有“system:”开头的,这些就可以理解为是官方给我们准备的,公共可以使用的
详细介绍一下
补充-常见的预定义角色
view ClusterRole
- 允许读取一个命名空间中的大多数资源,除了Role、RoleBinding和Secret
edit ClusterRole
- 允许读取和修改Secret。但是,它也不允许查看或修改Role和RoleBinding,防止权限扩散
admin ClusterRole
- 一个命名空间中资源的完全控制权是由admin ClusterRole赋予的。有这个ClusterRole的主体可以读取和修改命名空间中的任何资源,除了ResourceQuota和命名空间资源本身。edit和admin集群角色之前的主要区别是:能否在命名空间中查看和修改Role和RoleBinding
cluster-admin ClusterRole
- 通过将cluster-admin集群角色赋予给主体,主体可以获得k8s集群完全控制的权限,谁有了cluster-admin就相当于是这个集群的创造人,它是最大的
5、准入控制
准入控制是API Server的插件集合,通过添加不同的插件实现额外的准入控制规则。甚至于API Server的一些主要的功能都需要通过Admission Controllers实现,比如ServerAccount
kube-apiserver | Kuberneteshttps://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-apiserver/这是官方的准入控制器推荐列表,太多了。有需要各位自己按需查找吧