kubernetes进阶 -- 访问控制

概述

访问控制主要包括三个部分:

  1. 认证
  2. 授权
  3. 准入控制

认证和授权再apiserver的pod上完成.

  • kubernetes API 访问控制
    kubernetes进阶 -- 访问控制_第1张图片

kubernetes进阶 -- 访问控制_第2张图片
上面的图片由三部分组成:

  • 首先用户的请求要通过认证,认证通过许多插件来完成,
  • 认证通过后同样调用插件来进行授权,常用的授权就是node, rbac,
  • 第三部分是准入控制,就是对访问的行为再做一些控制,我们也可以不进行控制

认证通或后就可以从etcd里面获取信息了.

  • Authentication(认证)
    • 认证方式现共有8种,可以启用一种或多种认证方式,只要有一种认证方式通过,就不再
      进行其它方式的认证。通常启用X509 Client Certs和Service Accout Tokens两种认证方式。
    • Kubernetes集群有两类用户:由Kubernetes管理的Service Accounts (服务账户)和
      (Users Accounts) 普通账户。k8s中账号的概念不是我们理解的账号,它并不真的存在,
      它只是形式上存在。
    • 当我们不指定sa时,默认使用default sa.
[root@server2 ~]# kubectl get sa
NAME      SECRETS   AGE
default   1         21d
[root@server2 ~]# kubectl describe sa default 
Name:                default
Namespace:           default
Labels:              
Annotations:         
Image pull secrets:  
Mountable secrets:   default-token-j7pl7
Tokens:              default-token-j7pl7
Events:              
  • Authorization(授权)

    • 必须经过认证阶段,才到授权请求,根据所有授权策略匹配请求资源属性,决定允许或拒绝请求。授权方式现共有6种,AlwaysDeny、AlwaysAllow、ABAC、RBAC、Webhook、Node。默认集群强制开启RBAC。
  • Admission Control(准入控制)

    • 用于拦截请求的一种方式,运行在认证、授权之后,是权限认证链上的最后一环,对请求API资源对象进行修改和校验。
  • 访问k8s API Server的客户端主要分为两类:

    • kubectl :用户家目录中的 .kube/config 里面保存了客户端访问API Server的密钥相关信息,这样当用kubectl访问k8s时,它就会自动读取该配置文件,向API Server发起认证,然后完成操作请求。
    • pod:Pod中的进程需要访问API Server,如果是人去访问或编写的脚本去访问,这类访问使用的账号为:UserAccount;而Pod自身去连接API Server时,使用的账号是:ServiceAccount,生产中后者使用居多。

kubectl向apiserver发起的命令,采用的是http方式,其实就是对URL发起增删改查的操作。

}[root@server2 ~]#kubectl proxy --port=8888 & 用 proxy 打开一个端口,可以直接用curl访问.
[root@server2 ~]# netstat -tnlp | grep 8888
tcp        0      0 127.0.0.1:8888          0.0.0.0:*               LISTEN      18339/kubectl       
[root@server2 ~]# curl http://localhost:8888/api/v1/namespaces/default
{
  "kind": "Namespace",
  "apiVersion": "v1",
  "metadata": {
    "name": "default",
    ...
[root@server2 ~]# curl http://localhost:8888/apis/apps/v1/namespaces/default/deployments
{
  "kind": "DeploymentList",
  "apiVersion": "apps/v1",
  "metadata": {
    "selfLink": "/apis/apps/v1/namespaces/default/deployments",
    "resourceVersion": "793632"
  },
  "items": [
...

以上两种api的区别是:

  • api它是一个特殊链接,只有在核心v1群组中的对象才能使用。
  • apis 它是一般API访问的入口固定格式名。

UserAccount与serviceaccount的区别:

  • 用户账户是针对人而言的。 服务账户是针对运行在 pod 中的进程而言的。
  • 用户账户是全局性的。 其名称在集群各 namespace 中都是全局唯一的,未来的用户资源不会做 namespace 隔离, 服务账户是 namespace 隔离的。
  • 通常情况下,集群的用户账户可能会从企业数据库进行同步,其创建需要特殊权限,并且涉及到复杂的业务流程。 服务账户创建的目的是为了更轻量,允许集群用户为了具体的任务创建服务账户 ( 即权限最小化原则 )。
[root@server2 ~]# kubectl config view 
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://172.25.254.2:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin			/这就是用户帐号
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

认证

创建serviceaccount:

[root@server2 ~]# kubectl create serviceaccount admin
serviceaccount/admin created
[root@server2 ~]# kubectl get sa
NAME      SECRETS   AGE
admin     1         5s
default   1         21d
[root@server2 ~]# kubectl describe sa admin 
Name:                admin
Namespace:           default
Labels:              
Annotations:         
Image pull secrets:  			/镜像拉取的secrets
Mountable secrets:   admin-token-lbb4q			/集群自动创建了token令牌.确保sa 建立会后可用
Tokens:              admin-token-lbb4q
Events:              

此时时没有授权的.但是我们还可以网sa 中加入一些参数,比如镜像拉取的secrets:


[root@server2 cm]# kubectl get secrets 
NAME                  TYPE                                  DATA   AGE
admin-token-lbb4q     kubernetes.io/service-account-token   3      5m51s
basic-auth            Opaque                                1      9d
db-user-pass          Opaque                                2      8d
default-token-j7pl7   kubernetes.io/service-account-token   3      21d
dev-db-secret         Opaque                                2      8d
myregistrykey         kubernetes.io/dockerconfigjson        1      8d			/这是我们之前创建的一个用于拉取镜像的secret
tls-secret            kubernetes.io/tls                     2      9d
[root@server2 cm]# vim pod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: game2048
      image: reg.caoaoyuan.org/caoaoyuan/game2048
  imagePullSecrets:
    - name: myregistrykey			我们在使用的时候必须要再资源清单中指定才可以使用.
[root@server2 cm]# kubectl apply -f pod.yml 
kubc	pod/mypod created
[root@server2 cm]# kubectl describe pod mypod
Volumes:
  default-token-j7pl7:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-j7pl7		/系统进行挂载

我们就可以把这个secret 加入到指定的 sa中,这样每次创建pod就不用指定了.
添加secrets到serviceaccount中:

[root@server2 cm]# kubectl patch serviceaccount admin -p '{"imagePullSecrets": [{"name":"myregistrykey"}]}'
serviceaccount/admin patched
[root@server2 cm]# kubectl describe sa admin 
Name:                admin
Namespace:           default
Labels:              
Annotations:         
Image pull secrets:  myregistrykey		/加近来了
Mountable secrets:   admin-token-lbb4q
Tokens:              admin-token-lbb4q
Events:              

更改pod文件;

[root@server2 cm]# vim pod.yml 
[root@server2 cm]# cat pod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: game2048
      image: reg.caoaoyuan.org/caoaoyuan/game2048
  serviceAccountName: admin			/直接指定sa即可

[root@server2 scheduler]# kubectl delete -f deployment.yml 
deployment.apps "deployment-v1" deleted
[root@server2 scheduler]# kubectl describe pod  mypod 
Volumes:
  admin-token-lbb4q:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  admin-token-lbb4q				/就是我们指定的admin 的sa了 

如果我们不指定的话就会使用默认的sa, 但是里面是没有secret的,就会拉取镜像失败.

[root@server2 cm]# kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name":"myregistrykey"}]}'
serviceaccount/default patched
[root@server2 cm]# kubectl describe sa default 		
Name:                default
Namespace:           default
Labels:              
Annotations:         
Image pull secrets:  myregistrykey				/加到默认sa中去
Mountable secrets:   default-token-j7pl7
Tokens:              default-token-j7pl7
Events:              


[root@server2 cm]# cat pod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: myapp				没有指定sa
      image: myapp:v1
      
kubec	[root@server2 cm]# kubectl apply -f pod.yml 
pod/mypod created
[root@server2 cm]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
mypod   1/1     Running   0          6s			成功运行起来了

通过这种方式,我们就是 将认证信息添加到serviceAccount中,要比直接在Pod指定imagePullSecrets要安全很多。

创建UserAccount:

用于登陆集群,连接api,给用户使用.

首先给用户创建证书:

[root@server2 cm]# cd /etc/kubernetes/pki/				/证书创建目录

/生成key
[root@server2 pki]# openssl genrsa -out test.key 2048		
Generating RSA private key, 2048 bit long modulus

/生成证书请求
[root@server2 pki]# openssl req -new -key test.key -out test.csr -subj "/CN=test"	
[root@server2 pki]# ls
  test.key		test.csr ...

/生成证书
[root@server2 pki]# openssl x509 -req -in test.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out test.crt -days 365	
Signature ok
subject=/CN=test
Getting CA Private Key

/设置test用用户,并识别证书和key
[root@server2 pki]# kubectl config set-credentials test --client-certificate=/etc/kubernetes/pki/test.crt --client-key=/etc/kubernetes/pki/test.key --embed-certs=true
User "test" set.
[root@server2 pki]# kubectl config view
...
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: test			用户出现了
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

加入到context\中
[root@server2 pki]# kubectl config set-context test@kubernetes --cluster=kubernetes --user=test
Context "test@kubernetes" created.
[root@server2 pki]# kubectl config view
..
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
- context:
    cluster: kubernetes
    user: test
  name: test@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
...

/切换
[root@server2 pki]# kubectl config use-context test@kubernetes
Switched to context "test@kubernetes".
[root@server2 pki]# kubectl get pod
Error from server (Forbidden): pods is forbidden: User "test" cannot list resource "pods" in API group "" in the namespace "default"

此时用户通过认证,但还没有权限操作集群资源,需要继续添加授权。

授权

  • RBAC(Role Based Access Control):基于角色访问控制授权。
    • 允许管理员通过Kubernetes API动态配置授权策略。RBAC就是用户通过角色与权限进行关联。
    • RBAC只有授权,没有拒绝授权,所以只需要定义允许该用户做什么即可。不用直接解绑就行
    • RBAC包括四种类型:Role、ClusterRole、RoleBinding、ClusterRoleBinding。

kubernetes进阶 -- 访问控制_第3张图片

  • RBAC的三个基本概念 :
    • Subject:被作用者,它表示k8s中的三类主体, user, group, serviceAccount
    • Role:角色,它其实是一组规则,定义了一组对 Kubernetes API 对象的操作权限。
    • RoleBinding:定义了“被作用者”和“角色”的绑定关系。
  • Role 和 ClusterRole
    • Role是一系列的权限的集合,Role只能授予单个namespace 中资源的访问权限。
    • ClusterRole 跟 Role 类似,但是可以在集群中全局使用。

我们先切回管理员用户,进行授权

[root@server2 pki]# kubectl config use-context kubernetes-admin@kubernetes 
Switched to context "kubernetes-admin@kubernetes".
[root@server2 pki]# kubectl get pod
No resources found in default namespace.

角色 和 角色绑定

[root@server2 ~]# mkdir rbac
[root@server2 ~]# cd rbac/
[root@server2 rbac]# vim role.yml
[root@server2 rbac]# cat role.yml 
kind: Role			/rbac类型为role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default			/针对默认namespace
  name: myrole
rules:
- apiGroups: [""]
  resources: ["pods"]			/授权对应的资源
  verbs: ["get", "watch", "list", "create", "update", "patch", "delete"]		/对应的权限,自己定义

[root@server2 rbac]# kubectl apply -f role.yml 
kubec	role.rbac.authorization.k8s.io/myrole created
[root@server2 rbac]# kubectl get role
NAME     CREATED AT
myrole   2020-07-10T04:35:24Z

[root@server2 rbac]# kubectl describe role myrole 
Name:         myrole
Labels:       
Annotations:  PolicyRule:
  Resources   Non-Resource URLs  Resource Names  Verbs
  ---------   -----------------  --------------  -----
  pods        []                 []              [get watch list create update patch delete]
  • RoleBinding和ClusterRoleBinding
    • RoleBinding是将Role中定义的权限授予给用户或用户组。它包含一个subjects列表(users,groups ,service accounts),并引用该Role。
    • RoleBinding是对某个namespace 内授权,ClusterRoleBinding适用在集群范围内使用。

绑定:

[root@server2 rbac]# vim role.yml 
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: myrole
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list", "create", "update", "patch", "delete"]

---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: test-read-pods
  namespace: default			/针对的默认命名空间
subjects:
- kind: User			/绑定用户
  name: test			/用户名
  apiGroup: rbac.authorization.k8s.io			/api组
roleRef:
  kind: Role			/绑定角色
  name: myrole
  apiGroup: rbac.authorization.k8s.io

[root@server2 rbac]# kubectl apply -f role.yml 
role.rbac.authorization.k8s.io/myrole unchanged
rolebinding.rbac.authorization.k8s.io/test-read-pods created
[root@server2 rbac]# kubectl config use-context test@kubernetes 
Switched to context "test@kubernetes".
[root@server2 rbac]# kubectl run demo --image=busybox --restart=Never
pod/demo created		/可以创建pod
[root@server2 rbac]# kubectl get pod
NAME   READY   STATUS      RESTARTS   AGE
demo   0/1     Completed   0          7s		查看pod
[root@server2 rbac]# kubectl delete  pod demo 
pod "demo" deleted

[root@server2 rbac]# kubectl get svc
Error from server (Forbidden): services is forbidden: User "test" cannot list resource "services" in API group "" in the namespace "default"
[root@server2 rbac]# kubectl get cm
Error from server (Forbidden): configmaps is forbidden: User "test" cannot list resource "configmaps" in API group "" in the namespace "default"
[root@server2 rbac]# kubectl get pod -n kube-system
Error from server (Forbidden): pods is forbidden: User "test" cannot list resource "pods" in API group "" in the namespace "kube-system"

可以看出 test 这个用户账户值可以对 pod 进行相应的操作,对于没有授权的不可以操作.而且只能在授权的命名空间内.
而且创建 控制器 cm,等等都是不可以的.

集群角色

[root@server2 rbac]# kubectl config use-context kubernetes-admin@kubernetes 
Switched to context "kubernetes-admin@kubernetes".
依然先切回管理员,进行授权
[root@server2 rbac]# vim role.yml 
..上面不变,只在下面添加:
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: myclusterrole
rules:			/多个规则
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list", "delete", "create", "update"]
- apiGroups: ["extensions", "apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

集群角色不仅可以 使用 clusterrolebinding 进行绑定,还可以使用 rolebinding 绑定:

[root@server2 rbac]# vim role.yml 
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: myclusterrole
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list", "delete", "create", "update"]
- apiGroups: ["extensions", "apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rolebind-myclusterrole
  namespace: default			同样只能指定一个命名空间.
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole		/绑定集群角色
  name: myclusterrole
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: test			/绑定用户


[root@server2 rbac]# kubectl get deployments.apps 
No resources found in default namespace.		/可以对控制器进行操作了
[root@server2 rbac]# kubectl get deployments.apps -n kube-system
Error from server (Forbidden): deployments.apps is forbidden: User "test" cannot list resource "deployments" in API group "apps" in the namespace "kube-system"

但是还是不能跨namespace 进行使用,因为我们使用的是角色绑定而不是集群角色绑定.
集群角色绑定:

[root@server2 rbac]# vim role.yml
...

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:			集群角色绑定不用指定namespace,因为是针对所有namespace的.
  name: clusterrolebinding-myclusterrole
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: myclusterrole				
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: test

[root@server2 rbac]# kubectl apply -f role.yml

[root@server2 rbac]# kubectl config use-context test@kubernetes 
Switched to context "test@kubernetes".
[root@server2 rbac]# kubectl config get-contexts 
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
          kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   
*         test@kubernetes               kubernetes   test
[root@server2 rbac]# kubectl get pod -n kube-system 
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-76d4774d89-9fp2s   1/1     Running   1          2d23h
calico-node-bg9c4                          1/1     Running   9          11d
calico-node-lvxrc                          1/1     Running   8          11d
calico-node-smn7b                          1/1     Running   9          11d
coredns-5fd54d7f56-2d7h9                   1/1     Running   1          2d22h

[root@server2 rbac]# kubectl get deployments.apps -n kube-system 
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
calico-kube-controllers   1/1     1            1           11d
coredns                   2/2     2            2           21d

就可以获取所有namespace下的 pod 和 deployment 的指定操作权限了.
但是只能对pod 和 deployment 进行操作,因为没指定其他的权限,clusterrole 只是可以对所有的命名空间操作,

准入控制

我们在最初搭建集群的时候,并没有做一些证书,或者token的建立操作,但是我们仍然可以正常使用,这是因为集群自动化的帮我们创建了一些内容.

  • 服务账户(sa)的自动化
    • 服务账户准入控制器(Service account admission controller)
      • 如果该 pod 没有 ServiceAccount 设置,将其 ServiceAccount 设为 default。
      • 保证 pod 所关联的 ServiceAccount 存在,否则拒绝该 pod。
      • 如果 pod 不包含 ImagePullSecrets 设置,那么 将 ServiceAccount 中的ImagePullSecrets 信息添加到 pod 中。
      • 将一个包含用于 API 访问的 token 的 volume 添加到 pod 中。
      • 将挂载于 /var/run/secrets/kubernetes.io/serviceaccount 的 volumeSource 添加到pod 下的每个容器中。
[root@server2 rbac]# kubectl create namespace linux
namespace/linux created
[root@server2 rbac]# kubectl get sa -n linux 
NAME      SECRETS   AGE
default   1         7s			/自动创建的sa

[root@server2 rbac]# kubectl -n kube-system describe pod coredns-5fd54d7f56-2d7h9 
      /var/run/secrets/kubernetes.io/serviceaccount from coredns-token-t4kqs (ro)		/自动创建的token
  • Token 控制器(Token controller)
    • 检测服务账户的创建,并且创建相应的 Secret 以支持 API 访问。
    • 检测服务账户的删除,并且删除所有相应的服务账户 Token Secret。
    • 检测 Secret 的增加,保证相应的服务账户存在,如有需要,为 Secret 增加 token。
    • 检测 Secret 的删除,如有需要,从相应的服务账户中移除引用。
kubec	[root@server2 rbac]# kubectl get sa
NAME      SECRETS   AGE
admin     1         3h21m			/这是我们自己创建的sa
default   1         21d
[root@server2 rbac]# kubectl get secrets 
NAME                  TYPE                                  DATA   AGE
admin-token-lbb4q     kubernetes.io/service-account-token   3      3h21m		secret
basic-auth            Opaque                                1      9d
..
[root@server2 rbac]# kubectl delete sa admin 
serviceaccount "admin" deleted
[root@server2 rbac]# kubectl get secrets 
NAME                  TYPE                                  DATA   AGE
basic-auth            Opaque                                1      9d
删除sa后secret也不见了.
  • 服务账户控制器(Service account controller)
    服务账户管理器管理各命名空间下的服务账户,并且保证每个活跃的命名空间下存在
    一个名为 “default” 的服务账户
[root@server2 rbac]# kubectl create namespace linux
namespace/linux created
[root@server2 rbac]# kubectl get secrets -n linux 
NAME                  TYPE                                  DATA   AGE
default-token-z59zk   kubernetes.io/service-account-token   3      9s

[root@server2 rbac]# kubectl -n linux delete sa default 			/删除默认sa
serviceaccount "default" deleted
[root@server2 rbac]# kubectl get sa -n linux 
NAME      SECRETS   AGE
default   1         7s

[root@server2 rbac]# kubectl get secrets -n linux 
NAME                  TYPE                                  DATA   AGE
default-token-qp48s   kubernetes.io/service-account-token   3      34s

我们可以看出创建命名空间时会自动创建一个secret,而且当我们删除了创建的默认的sa时,回立即重新拉起一个sa,并删除之前的secret,重新拉起一个.

  • Kubernetes 还拥有“用户组”(Group)的概念:
  • ServiceAccount对应内置“用户”的名字是:
    • system:serviceaccount:
  • 而用户组所对应的内置名字是:
    • system:serviceaccounts:

示例1:表示mynamespace中的所有ServiceAccount

subjects:
- kind: Group
  name: system:serviceaccounts:mynamespace
  apiGroup: rbac.authorization.k8s.io

示例2:表示整个系统中的所有ServiceAccount

subjects:
- kind: Group
  name: system:serviceaccounts			不指定命名空间
  apiGroup: rbac.authorization.k8s.io

Kubernetes 还提供了四个预先定义好的 ClusterRole 来供用户直接使用:
他们各自有不同的权限

[root@server2 rbac]# kubectl get clusterrole
NAME                                                                   CREATED AT
admin                                                                  2020-06-18T09:31:41Z
cluster-admin                                                          2020-06-18T09:31:41Z
edit                                                                   2020-06-18T09:31:41Z
view                                                                   2020-06-18T09:31:42Z

[root@server2 rbac]# kubectl describe clusterrole cluster-admin 
Name:         cluster-admin
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  *.*        []                 []              [*]
             [*]                []              [*]
这是其中嗯权限最大的

例如:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: readonly-default
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: ClusterRole
  name: view			我们可以用系统的集群角色,赋予给这个sa 权限
  apiGroup: rbac.authorization.k8s.io

准入控制主要是通过插件来完成的.

你可能感兴趣的:(k8s)