K8S 安全机制
成都创新互联长期为上千余家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为雨花台企业提供专业的网站设计制作、做网站,雨花台网站改版等技术服务。拥有十年丰富建站经验和众多成功案例,为您定制开发。
一、K8S的安全框架
• 访问K8S集群的资源需要过三关:认证、鉴权、准入控制
• 普通用户若要安全访问集群API Server,往往需要证书、Token或者用户名+密码;Pod访问,比如ingress控制器Ui的Dashboard都需要ServiceAccount,主要是让这个容器能够访问这个API,也就是所有的交互都是通过API的,这可能通过一个人去通过kubectl去交互,也有可能你的程序去调用API,但这些都是需要授权的
• K8S安全控制框架主要由下面3个阶段进行控制,每一个阶段都支持插件方式,通过API Server配置来启用插件。
说在前面的话,也就是每个阶段都是插件化的设计,可以自己开发插件,把这些集成到步骤里面,来实现相关的访问控制,这样的话你就不需要去修改原有的代码去增加了,所以k8s设计原则有很多都是以扩展性去设计的,都尽可能的让用户自定义一些东西,集成到里面。
接下来看一张图,这是访问API经历的一些阶段
从上面kubectl、API、UI,访问的是k8sAPI,k8s的API提供了很多的接口
这些都是Apiserver去提供的,也支持不同的功能,来完成相关的处理的,相关的认证,再往下就是API内置有三层的授权,第一层就是认证,第二层就是鉴权,第三层就是准入控制,然后通过之后就可以访问相关的资源了,这些资源都是从ETCD中去调用的,一些存储状态的信息
传输安全:
现在k8s都已经改成https进行访问,也就是不管你是kubeadm部署还是二进制部署,他都是建议你使用https进行全栈的通信,告别8080,使用6443
认证:
API收到用户发送的请求之后,他会先认证,认证它这边有三个可以做到
三种客户端身份认证:
• HTTPS 证书认证:基于CA证书签名的数字证书认证,也就是k8s,CA签出来的证书可以作为你客户端访问携带的证书,它会帮你认证,这是一种方式,从这个证书里面去提取你有没有权限去访问。
• HTTP Token认证:通过一个Token来识别用户。
• HTTP Base认证:用户名+密码的方式认证,这是基于http自身的一个认证,不过这个很少人去用,因为安全系数比较低。
第一关就是标识你是用哪个证书进来的,还是token标识进来的,看看我这里是不是可信任的,看看我这个token我这里有没有相关的授权,也就是我这里有没有这个token,如果没有就不允许通过,然后下面就不会再进行了,如果通过的话,就比如本地已经创建这个token了,有的话就给你放行,进行下一个判断,也就是第二关授权。
授权:
RBAC(Role-Based Access Control,基于角色的访问控制):负责完成授权(Authorization)工作。也就是会查看你的访问符不符合权限,所以它会在这个地方去给你判断,如果你来的这个身份,虽然有这个身份,但是没有这个权限访问这个资源,也会不允许你通过。
授权的资源有很多类型的支持
准入控制:
简单讲就是开发将一些高级的功能,直接插件化的去设计,也就是准入控制器就是一个插件的集合,集合里面就有一些高级的特性,都是以插件去实现的,如果不启用这些插件的话,那你就使用不了这个功能,这也就是第三关,也就是你的请求会经过你的插件准入控制,准入控制呢会给你效验请求的实现的这个方法,到底这个插件有没有启用这一块,不过大多数的方式默认的插件都是启用的,启动之后来请求相关的资源,才会被允许,因为它启用插件了,如果没启动的话也会不通过
Adminssion Control实际上是一个准入控制器插件列表,发送到API Server的请求都需要经过这个列表中的每个准入控制器,插件的检查,检查不通过,则拒绝请求。
1.11版本以上推荐使用的插件:
--enable-admission-plugins= \
NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,ResourceQuota
使用RBAC授权
RBAC(Role-Based Access Control,基于角色的访问控制),允许通过Kubernetes API动态配置策略。也就是即使配置,即时生效,不需要重启服务
角色
• Role:授权特定命名空间的访问权限
• ClusterRole:授权所有命名空间的访问权限
角色绑定
• RoleBinding:将角色绑定到主体(即subject)
• ClusterRoleBinding:将集群角色绑定到主体
主体(subject)
• User:用户
• Group:用户组
• ServiceAccout: 服务账号
要做一个权限的管理系统,有两块,第一块就是对象是谁,创建的用户,第二就是权限组,比如创建一个开发组,开发组有哪些权限,可以访问这个系统,这也是为了方便去管理这些权限,来划分这个权限组,每个用户都给他创建一个权限很麻烦,有这个组的话,直接将用户加入这个组里面就可以了,比如来一个开放,并给他设置权限,他是一个来宾用户的组,这个组里面只能查看一些东西,但是他是一个开发组的,对一些项目有一些开发权限,管理员进去呢,在这个管理页面去再去加一个开发组,这样的话他就有开发组的权限了
K8s和刚才说的其实都是一样的,用户就是这个主体,就是谁来访问,然后权限组呢就是角色,定义了一组权限的集合,用户要想将用户与权限集合做一个附加,将开发附加一个权限组,就称为角色绑定,角色里面又分为了,角色及集群角色,集群角色是授权集群命名空间的,
也就是k8s有命名空间这一说,所以有分为了单个命名空间和所有命名空间,这个权限集合的设置,ClusterRole也就是授权所有命名空间,也就是说将某个用户加入这个权限角色里,那就意味着它可以访问所有命名空间,相关的一些权限。
示例:为zhaocheng用户授权default命名空间Pod读取权限
比如就是只能查看pod默认的空间的运行的一些资源,像svc,日志是没有权限查看的,当你试用期过了之后,再给你加一些权限,再做一些相关的操作
实现这个目标需要完成以下三步
创建RBAC权限策略
Ca.crt 和 Ca.key就是这两个需要签发的证书
[root@k8s-master ~]# ls /etc/kubernetes/pki/
apiserver.crt apiserver.key ca.crt front-proxy-ca.crt front-proxy-client.key
apiserver-etcd-client.crt apiserver-kubelet-client.crt ca.key front-proxy-ca.key sa.key
apiserver-etcd-client.key apiserver-kubelet-client.key etcd front-proxy-client.crt sa.pub
[root@k8s-master ~]# cd demo/
[root@k8s-master demo]# mkdir rbac
[root@k8s-master demo]# cd rbac/
[root@k8s-master rbac]# rz -E
rz waiting to receive.
[root@k8s-master rbac]# ls
cert.sh cfssl.sh config.sh rbac.yaml
[root@k8s-master rbac]# cat cfssl.sh
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x cfssl*
mv cfssl_linux-amd64 /usr/bin/cfssl
mv cfssljson_linux-amd64 /usr/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo
[root@k8s-master rbac]# sh cfssl.sh
然后这里我们把我们证书签发的脚本拿过来,这里注意的是签发用户的CN这里是指签发用户的用户名,就是说k8s拿这个CA来认证,它不单效验是不是我颁发的证书,还要效验里面的用户名,就是CN这个字段是不是授权过的,相当于鉴权那一块,O是用户组,也可以基于这个用户组去做这个权限限制
[root@k8s-master rbac]# chmod +x cert.sh
[root@k8s-master rbac]# vim cert.sh
cat > ca-config.json < zhaocheng-csr.json <
主要生成的就是zhaocheng-key.pem zhaocheng.pem
[root@k8s-master rbac]# ls
ca-config.json cert.sh cfssl.sh config.sh rbac.yaml zhaocheng.csr zhaocheng-csr.json zhaocheng-key.pem zhaocheng.pem
需要用这两个证书来对客户端做请求认证,写到客户端授权文件里,用这个授权文件就能请求这个k8s集群了
比如公司有多个集群,那么这个开发需要登录这个集群,需要这个config证书,到时候可以拿这个来回切换登录不同的集群
--kubeconfig=zhaocheng.kubeconfig
[root@k8s-master rbac]# vim config.sh
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=https://192.168.30.21:6443 \
--kubeconfig=zhaocheng.kubeconfig
设置客户端认证
kubectl config set-credentials zhaocheng \
--client-key=zhaocheng-key.pem \
--client-certificate=zhaocheng.pem \
--embed-certs=true \
--kubeconfig=zhaocheng.kubeconfig
设置默认上下文
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=zhaocheng \
--kubeconfig=zhaocheng.kubeconfig
设置当前使用配置
kubectl config use-context kubernetes --kubeconfig=zhaocheng.kubeconfig
[root@k8s-master rbac]# bash config.sh
[root@k8s-master rbac]# cat zhaocheng.kubeconfig
现在就可以拿这个kubeconfig去访问集群了
到这呢其实是到认证这个地方给打回去了,node节点是没有访问权限的,已经识别出来是zhaocheng用户了,但是鉴权这块没有相关的授权,所以现在要为这个用户授权
[root@k8s-master rbac]# kubectl get --kubeconfig=./zhaocheng.kubeconfig node
Error from server (Forbidden): nodes is forbidden: User "zhaocheng" cannot list resource "nodes" in API group "" at the cluster scope
如果有一个组的命名空间,权限比较大,就是可以访问所有命名空间,比如运维来讲,有很多的运维,可以创建集群的角色,这样它是管控所有命名空间的角色,这个角色就是针对于特定的命名空间的,比如开发,测试,它只能访问命名空间的项目,它负责的项目,然后可以使用这个指定命名空间,然后就是集群的绑定,然后绑定到zhaocheng这个用户身上,这里我定义的是user,也可以是group组。
pod也是不能访问的
[root@k8s-master rbac]# kubectl get --kubeconfig=./zhaocheng.kubeconfig pod
Error from server (Forbidden): pods is forbidden: User "zhaocheng" cannot list resource "pods" in API group "" in the namespace "default"
[root@k8s-master rbac]# vim 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: zhaocheng
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
[root@k8s-master rbac]# kubectl create -f rbac.yaml
然后现在就可以进行访问了
[root@k8s-master rbac]# kubectl get --kubeconfig=./zhaocheng.kubeconfig pod
NAME READY STATUS RESTARTS AGE
my-pod 1/1 Running 0 10h
nfs-744d977b46-dh9xj 1/1 Running 0 29h
nfs-744d977b46-kcx6h 1/1 Running 0 29h
nfs-744d977b46-wqhc6 1/1 Running 0 29h
nfs-client-provisioner-fbc77b9d4-kkkll 1/1 Running 0 11h
nginx-797db8dc57-tdd5s 1/1 Running 0 8h
nginx-a1-6d5fd7b8dd-w647x 1/1 Running 0 4h65m
nginx-statefulset-0 1/1 Running 0 7h7m
nginx-statefulset-1 1/1 Running 0 7h7m
nginx-statefulset-2 1/1 Running 0 7h7m
web-0 1/1 Running 0 4h65m
web-1 1/1 Running 0 4h63m
web-2 1/1 Running 0 4h62m
但是svc是没有定义的所以还不能访问
[root@k8s-master rbac]# kubectl get --kubeconfig=./zhaocheng.kubeconfig svc
Error from server (Forbidden): services is forbidden: User "zhaocheng" cannot list resource "services" in API group "" in the namespace "default"
比如我们加一个别的访问权限,比如service,deployment
在刚才我们的rbac的策略里面加上这些权限
- apiGroups: [""]
resources: ["pods","services"]
verbs: ["get", "watch", "list"]
再来测试一下,已经可以正常去访问svc了
[root@k8s-master rbac]# kubectl get --kubeconfig=./zhaocheng.kubeconfig service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.1.0.1 443/TCP 30h
my-service ClusterIP None 80/TCP 7h32m
nginx ClusterIP None 80/TCP 4h69m
service NodePort 10.1.207.32 80:30963/TCP 8h
zhao ClusterIP 10.1.75.232 80/TCP 7h41m
zhaocheng ClusterIP 10.1.27.206 80/TCP 7h43m
像其他的授权可以查看官方提供
https://kubernetes.io/docs/reference/access-authn-authz/rbac/