kubernetes安全机制

kubernetes安全机制

大概分为三个部分,其一Kubernetes安全框架,其二传输安全,认证。授权准入控制,其三使用RBAC授权,这算是一系列流程,了解一下每个环节都做了哪些操作。

kubernetes安全框架

当你使用kubectl||API||UI实际上就是操作apiserver上的资源,之前创建过Deployment,使用api版本为apps/v1,也就是这个,

apiVersion: apps/v1
kind: Deployment

在你创建的时候apiserver会识别你请求的资源,也就是上面的那两个,如果无法识别直接报错,识别成功后会经历三个阶段,第一认证,第二授权,第三准入控制,当你发起一个请求需要过了这三步验证K8S才会为你创建资源,如果这三步有任意一步出现问题,那你看到的就是一个失败的结果。

通常用户如果要安全访问集群Apiserver往往需要证书、token、或用户名加密码,token之前配置过,手动生成的一个token,而且指定了一个token文件,也就是这里。

[root@k8s01 ~]# cat /opt/kubernetes/cfg/kube-apiserver.conf | grep token.csv
--token-auth-file=/opt/kubernetes/cfg/token.csv \
[root@k8s01 ~]# 

这个token文件有一个值是随机生成的,这里就是使用token来认证的,指定了用户,把token对应的用户绑定相对应的权限,那么拿着个token值就有相对应的权限来访问apiserver了。

[root@k8s01 ~]# kubectl get serviceaccounts 
NAME                     SECRETS   AGE
default                  1         7h2m
nfs-client-provisioner   1         6h46m
[root@k8s01 ~]# 

可以通过serveraccountpod中去访问apiserver,说白了就是不同类型的来访问apiserver都会有不同的方式,apiserver在各组件之间起到了协调的作用,和集群访问入口的功能,你想访问集群资源就必须得经过Apiserver

K8S安全控制框架主要是由以下三个阶段进行控制,

  • Authentication
  • Authorrization
  • AdmissionControl

如图所示

每一个阶段都支持插件方式,需要通过API Server配置来启用插件,之前都已经配置过了,现在看一下,例如准入控制

[root@k8s01 ~]#  cat /opt/kubernetes/cfg/kube-apiserver.conf | grep -i Admission
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,ResourceQuota,NodeRestriction \

授权启用了RBAC

[root@k8s01 ~]#  cat /opt/kubernetes/cfg/kube-apiserver.conf | grep -i Author
--authorization-mode=RBAC,Node \

Authentication

也就是认证,在认证之前还有个传输,现在已经告别了8080,使用了6443,现在8080已经不对外提供服务了,对外提供服务的是64438080主要是本地master组件来连接使用。

认证方面提供了三种客户端认证方式。

  • HTTPS证书认证:基于CA证书签名的数字证书认证
    • 之前部署K8S时我们生成了N多证书,通过证书内的CN字段就可以识别出您是谁。
  • HTTP TOKEN认证: 通过TOKEN来识别用户
    • 这个也用到了,就是在apiserver中配置的那个token文件,那个是做kubelet-bootstrap认证时候用到的,这个用的比较广泛
  • HTTP Base认证: 用户名加密码的方式认证
    • 这种用的就很少了,安全系数比较低。

这是传输和认证层面,第一阶段验证你的身份,你可以理解为这是门禁,你通过工卡进行身份验证,验证通过之后你就能进入到某片区域了。

Authorrization

第二阶段,授权,第一阶段你身份验证通过了,然后进入到了某片区域,但是这片区域有很多房间,具体你能进入到哪个房间就得看你工卡的授权了,你有权限就可以刷开某个门,没权限你就是刷不开,所以这就涉及到授权了,一般用的就是RBAC,基于角色的访问控制,角色就是具体的访问权限的集合,他是负责完成授权工作的。

他去判断你是否有权限去访问某些资源,他会检查以下属性,如图。

在你请求的时候我绝对会携带我要访问哪个资源,下面他就开始检查你有没有权限去访问那个资源,如果没授权的话在这个阶段直接给你拒绝了,你看到的是没有权限访问,所以这就是授权这个阶段。

AdmissionControl

准入控制,前两步认证都过了就该这个了,他实际上是一个准入控制器插件列表,发送到API Server的请求都需要经过这个列表中的每个准入控制器检查,检查不通过,则拒绝请求,啥意思呢,大概是这样,我现在想通过apiserver限制pod资源,但是想限制pod资源需要用到apiserverLimitRanger插件,如果这个插件没启用直接拒绝请求,提示我不支持这个撒,现在这个插件启着呢,所以不会有这个问题,他的工作逻辑就是这样,下面主要看一下RBAC授权。

RBAC授权

也就是上文第二阶段的授权,它允许我们通过API Server来动态修改配置,实时生效,在开始之前先来了解一下RBAC的组成。

RBAC核心概念

  • 角色(Role,ClusterRole)
    • Role:授权特定命名空间的访问权限,K8S逻辑隔离是使用namespaces实现的,它的授权是在命名空间层面的,你能不能访问某个命名空间
    • ClusterRole:此为集群层面的,针对所有的命名空间,
  • 主体(User,Group,ServiceAccount)
    • User: 用户
    • Group: 用户组
    • ServicAccount:服务账号
  • 角色绑定(RoleBinding,ClusterRoleBinding)
    • RoleBinding:将角色绑定到主体,既subject ,它对应Role,创建Role使用这个去绑定,绑定后才会有相对应的权限
    • ClusterRoleBinding: 将集群角色绑定到主体,它对应ClusterRole,创建ClusterRole使用这个去绑定,绑定后才会有相对应的权限

RBAC授权普通用户访问命名空间

现在授权一个用户对某个命名空间有读取的权限,说白了就是只读,让你看看就行了,现在随便创建一个命名空间,然后在这个命名空间里启动几个pod

[root@k8s01 ~]# kubectl create namespace opesn
namespace/opesn created
[root@k8s01 ~]# kubectl get namespaces opesn 
NAME    STATUS   AGE
opesn   Active   8s
[root@k8s01 ~]# kubectl run nginx --image=nginx --replicas=3 --namespace=opesn
[root@k8s01 ~]# kubectl get pods -n opesn
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6db489d4b7-9xg6b   1/1     Running   0          26s
nginx-6db489d4b7-bfgwf   1/1     Running   0          26s
nginx-6db489d4b7-s6hrn   1/1     Running   0          26s
[root@k8s01 ~]# 

现在新建一个用户opesn,他的权限为只读opesn命名空间,其他的全部拒绝,首先要创建一个Role角色,需要定义规则了,基于官方文档

[root@k8s01 ~]# cat rbac-role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: opesn
  name: opesn
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

权限为get,watch,list,只读的,创建看一下

[root@k8s01 ~]# kubectl apply -f rbac-role.yaml 
role.rbac.authorization.k8s.io/opesn created
[root@k8s01 ~]# kubectl get role -n opesn
NAME    AGE
opesn   12s
[root@k8s01 ~]# 

现在有一个角色了,现在把他绑定到这个角色里。

[root@k8s01 ~]# cat rbac-rolebinding.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: read-pods
  namespace: opesn
subjects:
- kind: User
  name: opesn # Name is case sensitive
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role #this must be Role or ClusterRole
  name: opesn # this must match the name of the Role or ClusterRole you wish to bind to
  apiGroup: rbac.authorization.k8s.io
[root@k8s01 ~]# 

主要两块,命名空间,subjectskind指定为User,不是程序,用户名是opesn,在下面就是角色绑定了,指定了类型和名称,也就是上面创建的那个,这就可以了,创建吧。

[root@k8s01 ~]# kubectl create -f rbac-rolebinding.yaml 
rolebinding.rbac.authorization.k8s.io/read-pods created
[root@k8s01 ~]# kubectl get role,rolebinding -n opesn
NAME                                   AGE
role.rbac.authorization.k8s.io/opesn   4m40s

NAME                                              AGE
rolebinding.rbac.authorization.k8s.io/read-pods   10s
[root@k8s01 ~]# 

现在是创建完了,现在还差识别身份,现在使用基于证书的来识别身份,直接上脚本吧。

[root@k8s01 kubernetes]# cat rabc-user.sh
cat > opesn-csr.json <<EOF
{
  "CN": "opesn",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing"
    }
  ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes opesn-csr.json | cfssljson -bare opesn

kubectl config set-cluster kubernetes \
  --certificate-authority=ca.pem \
  --embed-certs=true \
  --server=https://192.168.10.4:6443 \
  --kubeconfig=opesn-kubeconfig
  
kubectl config set-credentials opesn \
  --client-key=opesn-key.pem \
  --client-certificate=opesn.pem \
  --embed-certs=true \
  --kubeconfig=opesn-kubeconfig

kubectl config set-context default \
  --cluster=kubernetes \
  --user=opesn \
  --kubeconfig=opesn-kubeconfig

kubectl config use-context default --kubeconfig=opesn-kubeconfig

opesn就是我之前定义的用户名,apiserver我写的是负载均衡地址,会用到apiserver的根证书,所以要复制过来,下面执行一下吧。

[root@k8s01 kubernetes]# bash rabc-user.sh
2020/06/07 23:14:29 [INFO] generate received request
2020/06/07 23:14:29 [INFO] received CSR
2020/06/07 23:14:29 [INFO] generating key: rsa-2048
2020/06/07 23:14:29 [INFO] encoded CSR
2020/06/07 23:14:29 [INFO] signed certificate with serial number 147728077879656546154832435011075986225633644035
2020/06/07 23:14:29 [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").
Cluster "kubernetes" set.
User "opesn" set.
Context "default" created.
Switched to context "default".
[root@k8s01 kubernetes]# 

[root@k8s01 kubernetes]# kubectl --kubeconfig=opesn-kubeconfig get pod -n default
Error from server (Forbidden): pods is forbidden: User "opesn" cannot list resource "pods" in API group "" in the namespace "default"
[root@k8s01 kubernetes]# kubectl --kubeconfig=opesn-kubeconfig get pod -n opesn
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6db489d4b7-9xg6b   1/1     Running   0          16m
nginx-6db489d4b7-bfgwf   1/1     Running   0          16m
nginx-6db489d4b7-s6hrn   1/1     Running   0          16m
[root@k8s01 kubernetes]# kubectl --kubeconfig=opesn-kubeconfig get service
Error from server (Forbidden): services is forbidden: User "opesn" cannot list resource "services" in API group "" in the namespace "default"
[root@k8s01 kubernetes]# 

只能看到opesn命名空间下的pod,什么service之类的都不行,因为没有授权,

RBAC授权ServiceAccount访问命名空间

创建一个WEBUI

wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml
vi recommended.yaml
…
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  type: NodePort
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 30001
  selector:
    k8s-app: kubernetes-dashboard
…
# kubectl apply -f recommended.yaml

#创建service account并绑定默认cluster-admin管理员集群角色:
cat dashboard-adminuser.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard

#启动
apply -f dashboard-adminuser.yaml 

#获取token
kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}')

访问地址:http://NodeIP:30001
使用输出的token登录Dashboard。

现在创建一个ServiceAccount,只允许访问opesn命名空间,权限和上面的一样,首先要创建一个ServiceAccount,然后把这个ServiceAccount绑定到上面创建的角色里。

[root@k8s01 ~]# cat sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-reader
  namespace: opesn

---

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: sa-read-pods
  namespace: opesn 
subjects:
- kind: ServiceAccount
  name: pod-reader
roleRef:
  kind: Role
  name: opesn
  apiGroup: rbac.authorization.k8s.io
[root@k8s01 ~]# 

就是这样,然后创建

[root@k8s01 ~]# kubectl create -f sa.yaml 
serviceaccount/pod-reader created
rolebinding.rbac.authorization.k8s.io/sa-read-pods created
[root@k8s01 ~]# kubectl get secrets -n opesn pod-reader-token-fv9qg 
NAME                     TYPE                                  DATA   AGE
pod-reader-token-fv9qg   kubernetes.io/service-account-token   3      38s
[root@k8s01 ~]# kubectl describe secrets -n opesn pod-reader-token-fv9qg 
Name:         pod-reader-token-fv9qg
Namespace:    opesn
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: pod-reader
              kubernetes.io/service-account.uid: 009f347c-be63-40cf-97c2-b4631f5e5b4c

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1359 bytes
namespace:  5 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IlNqcHV5S0V5dnZEWDJtck9TSGdZYkppb0V5SFdyOXpVUnd5b3NHX1Zmd00ifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJvcGVzbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJwb2QtcmVhZGVyLXRva2VuLWZ2OXFnIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InBvZC1yZWFkZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIwMDlmMzQ3Yy1iZTYzLTQwY2YtOTdjMi1iNDYzMWY1ZTViNGMiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6b3Blc246cG9kLXJlYWRlciJ9.j8ZryrAGx4c2VAiW2ZR_McJCDSUDYKXpDf5hwkLxOzYAt5_gIzvJCWE3htCd3IGiALanK88iDCid3nwRzyNPXSEcMtTGeLtAdIJ9ZwtFfxZVTNuHhW0p4C1Gw-9PWTNvbZiLQv4IUKzJRlSvfn121lo7OSG5WdovmCkmGug_c8es4FJvOHPVtQBXvOTWihlvwZMO6NRLQ9mTtBaqbpXseBUUjfENk7tuRs-LsS31bqlmCH2DkcPGlLArpMBp0bnjtAH0OAfYJbfErTfeXyNjHDVSx1tOJV7yly4nvKwe5_PFYlKBKZ-FDMT6T0qTmitDvYjB6cml9AdzgukJjHJ9AQ

下面去用这个token登陆一下UI

命名空间需要你手动输入了,然后会发现各种权限不足,就是这种效果,只读opesn命名空间,其他的全部权限不足,这就是RBAC授权

posted @ 2020-06-30 09:38  helloord  阅读(673)  评论(0编辑  收藏  举报