集群的认证 鉴权 访问控制 原理及其流程
k8s使用了认证(Authentication)、鉴权(Authorization)、准入控制(Adminssion Control)三步来保证API Sserver的安全
Authentication
- HTTP Token认证:通过一个Token来识别用户客户端携带一个token来请求server端,如果server端含有这个token,那么认证成功否则失败
- HTTP Base认证:用户名+密码的方式认证 (比较原始的方式,在k8s中基本很少使用)
- 最严格的HTTPS 证书认证:基于CA根证书签名的客户端身份认证方式
需要认证的节点
2种类型
- Kubenetes 组件对APl Server 的访问:kubectl .、Controller
Manager、Scheduler、kubelet 、kube-proxy - Kubernetes 管理的Pod对容器的访问:od(dashborad 也是以Pod形式运行)
安全说明
- Controller Manager .、Scheduler 与API Server 在同一台机器,所以直接使用APl Server
的非安全端口方问, --insecure -bind-address=127.0.0.1 - kubectl、kubelet、kube-proxy 访问Server 就都需要证书进行HTTPS 双向认证
证书颁发
- 手动签发:通过k8s集群的跟ca进行签发HTTPS 证书
- 自动签发:kubelet 首次访问Server 时,使用token 做认证,通过后,Controller Manager
会为kubelet 生成一个证书,以后的访问都是用证书做认证了
kubeconfig
master节点
#cd .kube/
kubeconfig 文件包含集群参数(cA证书、APl Server 地址),客户端参数(上面生成的证书和私钥),集群
context 信息(集群名称、用户名)Kubenetes 组件通过启动时指定不同的kubeconfig 文件可以切换到不同的集群
ServiceAccount
pod中的容器访问Server .因为pod的创建、销毁是动态的,所以要为它手动生成证书就不可行了。
Kubenetes 使用了Service account 解决pod访问Server 的认证问题
Secret 与的关系
k8s设计了一种资源对象叫做Secret ,分为两类,一种是用于ServiceAccount 的service -account,另一种是用于保存用户自定义保密信息的Opaque 。ServiceAccount I中用到包含三个部分:Token ca.crt、namespace
- token 是使用APl Server 私钥签名的j.用于访问Serverl 时,Server 端认证
- ca.crt,根证书用于Clienti 端验证Server 发送的证书
- namespace ,标识这个service -account-token 的作用域名空间
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
kubectl get secret --all-namespace
kubectl describe secret default-token-5gm9r --namespace=kube-system
默认情况下,每个namespace 都会有一个ServiceAccount ,如果pod在创建时没有指定ServiceAccount
就会使用Pod所属的namespace 的ServiceAccount
Authorization
上面认证过程,只是确认通信的双方都确认了对方是可信的,可以相互通信。而鉴权是确定请求方有哪些资源的权限。Server 目前支持以下几种授权策略(通过APl Server 的启动参数"–authorization -mode设置)
-
AlwaysDeny :表示拒绝所有的请求,一般用于测试
-
AlwaysAllow :允许接收所有请求,如果集群不需要授权流程,则可以采用该策略
-
ABAC(( Attribute-Based Access Control ):基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制 【需要重启】
-
Webbook :通过调用外部REST服务对用户进行授权
-
RBAC(role-Based Access Control ):基角色的访问控制,现行默认规则
RBAC授权模式
基于角色的访问控制,在Kubernetes 1.5中引入,现行版本成为默认标准。相对其它访问控制方式,拥有以下优势: -
对集群中的资源和非资源均拥有完整的覆盖
-
整个RBAC完全由几个AP1对象完成,同其它AP对象一样,可以用kubectl 或APl进行操作
-
可以在运行时进行调整,无需重启Server
RBAC的API资源对象说明
RBAC引入了4个新的顶级资源对象:Role、ClusterRole .、RoleBinding 、ClusterRoleBinding .4种对象类型 均可以通过kubectl !与AP操作
需要注意的是k8s并不会提供用户管理,那么user、group、ServiceAccount指定的用户又是从哪来的那?k8s组建(kubectl、kube-proxy)或是其他自定义的用户在向CA申请证书时,需要提供一个证书请求文件。API Server会把客户端证书的cn字段作为User,把names .o字段作为Group
kubelet 使用TLS Bootstaping 认证时,APl Server 可以使用Bootstrap Tokens 或者Token authentication fle验证=-token,无论哪一种,Kubenetes 都会为token 绑定一个默认的User和Group
pod使用ServiceAccount 认证时,service -account -token 中的j会保存User信息
有了用户信息,再创建一对角色/角色绑定(集群角色/集群角色绑定)资源对象,就可以完成权限绑定了
Role and clusterrole
在RBAC API中,Role表示一组规则权限,权限只会增加(累加权限),不存在一个资源一开始就有很多权限而通过RBAC对其进行减少的操作;Role可以定义在一个namespace 中,如果想要跨namespace 则可以创建ClusterRole
ClusterRole可以用于:
- 集群级别的资源控制
- 非资源类型endpoints访问
- 所有命名空间资源控制
# kubectl explain role.apiVersion
# vim role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: [ "pods"]
verbs: [ "get"," watch"," list"]
[root@k8s role]# kubectl apply -f role.yaml
[root@k8s role]# kubectl get role
# vim clusterrole.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: [ "srcrets"]
verbs: [ "get"," watch"," list"]
[root@k8s role]# kubectl apply -f clusterrole.yaml
[root@k8s role]# kubectl get clusterrole
RoleBinding and ClusterRoleBinding
RoloBinding 可以将角色中定义的权限授予用户或用户组,RoleBinding 包含一组权限列表(( subjects),权限列表中包含有不同形式的待授予权限资源类型(users ,groups ,or service accounts );RoloBinding 同样包含对被Bind的role引用;RoleBinding 适用于某个命名空间内授权,而ClusterRoleBinding 适用于集群范围内的授权
将default 命名空间的pod-reader Role 授予jane用户,此后jane用户在default 命名空间中将具有pod
# vim rb.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: read-pods
subjects:
- kind: User
name: Jane
apiGroup: rbac.authorization.k8s.io
roleRef :
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
# kubectl apply -f rb.yaml
RoleBinding 同样可以引用Clusterrole 来对当前namespace 内用户、用户组或ServiceAccount 进行授权这种操作允许集群管理员在整个集群内定义一些通用的Clusterrole ,然后在不同的namespace 中使用 RoleBinding 来引用
例如,以下RoleBinding 引用了一个ClusterRole ,这个ClusterRole 具有整个集群内对secrets 的访问权限;但是其授权用户dave只2能访问development 空间中的secrets ((因为RoleBinding 定义在development 命名空间
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: development
name: read-secrets
subjects:
- kind: User
name: dave
apiGroup: rbac.authorization.k8s.io
roleRef :
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
使用ClusterRoleBinding可以对整个集群中的所有命名空间资源进行授权;以下ClusterRoleBinding样例展示了授权manager组内所有用户在全部命名空间中对secrets进行访问
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-secrets-gloabel
subjects:
- kind: Group
name: manager
apiGroup: rbac.authorization.k8s.io
roleRef :
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
Rescurces
集群内一些资源一般以其名称字符串来表示,这些字符串一般会在AP的URL地址中出现;同时某
资源也会包含子资源,例如logs资源就属于pods的子资源,AP中URL样例如下
GET / api/v1/namespaces/{
namespace}/pods/{
name} /log
如果要在RBAC授权模型中控制这些子资源的访问权限,可以通过/分隔符来实现,以下是一个定义pods资资源logs访问权限的Role定义样例
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
resources: [ "pods/log"]
verbs: [ "get"," list"]
to Subjects
RoleBinding 和ClusterRoleBinding 可以将ole绑定到Subjects ;Subjects 可以是groups 、users 或者
service accounts
Subjects 中Users 使用字符串表示,它可以是一个普通的名字字符串,如’ alice";也可以是格式的邮箱
地址,如 “[email protected]”;甚至是一组字符串形式的数字id但是Users 的前缀system :是系统
保留的,集群管理员应该确保普通用户不会使用这个前缀格式
Groups 书写格式与Users 相同,都为一个字符串,并且没有特定的格式要求;同样system 前缀为系统保留
创建一个用户只能管理dev空间
1.linux一个用户 devuser/123456
# useradd devuser
# passwd devuser
2.创建证书文件 vim devuser-csr.json
{
"CN": "devuser",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "ShenZhen",
"L": "ShenZhen",
"O": "k8s",
"OU": "System"
}
]
}
3下载证书生成工具
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
mv cfssl_linux-amd64 /usr/local/bin/cfssl
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
mv cfssljson_linux-amd64 /usr//bin/cfssljson
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo
# chmod +x /usr/bin/cfssljson
# chmod +x /usr/local/bin/cfssl
# chmod +x /usr/local/bin/cfssl-certinfo
# cd /etc/kubernetes/pki/
[root@k8s pki]# cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /root/cert/devuser-csr.json | cfssljson -bare devuser
2021/02/07 17:51:29 [INFO] generate received request
2021/02/07 17:51:29 [INFO] received CSR
2021/02/07 17:51:29 [INFO] generating key: rsa-2048
2021/02/07 17:51:30 [INFO] encoded CSR
2021/02/07 17:51:30 [INFO] signed certificate with serial number 55463356715190284045106279256637384627615346901
2021/02/07 17:51:30 [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").
4设置集群参数
# cd /root/cert/
export KUBE_APISERVER="https://192.168.44.129:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=devuser.kubeconfig
[root@k8s cert]# ls
devuser-csr.json devuser.kubeconfig
5设置客户端认证参数
kubectl config set-credentials devuser \
--client-certificate=/etc/kubernetes/pki/devuser.pem \
--client-key=/etc/kubernetes/pki/devuser-key.pem \
--embed-certs=true \
--kubeconfig=devuser.kubeconfig
创建dev空间
# kubectl create namespace dev
6设置上下文参数
# kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=devuser \
--namespace=dev \
--kubeconfig=devuser.kubeconfig
进行RoleBinding角色绑定
kubectl create rolebinding devuser-admin-rolebinding(rolebinding的名字) --clusterrole=admin(clusterrole的名字,admin在k8s所有namespace下都有最高权限) --user=devuser(将admin的权限赋予devuser用户) --namespace=dev(范围是dev这个namespace下) 即dev
# kubectl create rolebinding devuser-admin-rolebinding --clusterrole=admin --user=devuser --namespace=dev
将devuser.kubeconfig复制到/home/devuser/.kube目录下
# mkdir -p /home/devuser/.kube
# cp devuser.kubeconfig /home/devuser/.kube/
# chown devuser:devuser /home/devuser/.kube/devuser.kubeconfig
# cd /home/devuser/.kube
# mv devuser.kubeconfig config
在dev用户下切换上下文
# kubectl config use-context kubernetes --kubeconfig=config
用devtest登录
[devuser@k8s .kube]$ kubectl get pod
No resources found in dev namespace
Adminssion Control
准入控制是API Server 的插件集合,通过添加不同的插件,实现额外的准入控制规则甚至于API Serverl 的一些主要的功能都需要通过Admission Controllers 实现,比如ServiceAccount
列举几个插件的功能:
- NamespaceLifecycle :防止在不存在的namespace 上创建对象,防止删除系统预置namespace ,删除
- namespace 时,连带删除它的所有资源对象
- LimitRanger :确保请求的资源不会超过资源所在Namespace 的LimitRange 的限制
- ServiceAccount :实现了自动化添加ServiceAccount .
- ResourceQuota :确保请求的资源不会超过资源的ResourceQuota 限制