K8s之认证,授权及准入控制

第1章 访问认证的概述

1.1 概念的引入

API Server作为Kubernetes集群系统的网关,是访问及管理资源对象的唯一人口,
余下所有需要访问集群资源的组件,包括kube-controller-manager、kube- scheduler 、
kubelet和kube-proxy等集群基础组件、CoreDNS等集群的附加组件以及此前使用的kubectl
命令等都要经由此网关进行集群访问和管理。这些客户端均要经由API Server访问或改变集群状态并
完成数据存储,并由它对每一次的访问请求进行合法性检验,包括用户身份鉴别、操作权限
验证以及操作是否符合全局规范的约束等。所有检查均正常完成且对象配置信息合法性检验
无误之后才能访问或存人数据于后端存储系统etcd中

第2章 ServiceAccount

2.1 概述

Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。它与User account不同
1)User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;
2)User account是跨namespace的,而service account则是仅局限它所在的namespace;
3)每个namespace都会自动创建一个default service account
4)Token controller检测service account的创建,并为它们创建secret
开启ServiceAccount Admission Controller后
  1.每个Pod在创建后都会自动设置spec.serviceAccount为default(除非指定了其他ServiceAccout)
  2.验证Pod引用的service account已经存在,否则拒绝创建
  3.如果Pod没有指定ImagePullSecrets,则把service account的ImagePullSecrets加到Pod中
  4.每个container启动后都会挂载该service account的token和ca.crt到/var/run/secrets/kubernetes.io/serviceaccount/

2.2 查看相关信息

当创建pod的时候,如果没有指定一个service account,系统会自动在与该pod相同的namespace下为其指派一个default service account。
而pod和apiserver之间进行通信的账号,称为serviceAccountName。如下:
[root@master ~]# kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
filebeat-ds-hxgdx        1/1       Running   1          34d
filebeat-ds-s466l        1/1       Running   2          34d
myapp-0                  1/1       Running   0          3h
myapp-1                  1/1       Running   0          3h
myapp-2                  1/1       Running   0          4h
myapp-3                  1/1       Running   0          4h
pod-vol-demo             2/2       Running   0          2d
redis-5b5d6fbbbd-q8ppz   1/1       Running   1          2d
[root@master ~]# kubectl get pods/myapp-0 -o yaml |grep "serviceAccountName"
  serviceAccountName: default
[root@k8s-master ~]# kubectl describe pods myapp-0
Name:               myapp-0
Namespace:          default
......
Volumes:
  ......
  default-token-j5pf5:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-j5pf5
    Optional:    false
从上面可以看到每个Pod无论定义与否都会有个存储卷,这个存储卷为default-token-*** token令牌,
这就是pod和serviceaccount认证信息。通过secret进行定义,由于认证信息属于敏感信息,所以需要保存在secret资源当中,
并以存储卷的方式挂载到Pod当中。从而让Pod内运行的应用通过对应的secret中的信息来连接apiserver,并完成认证。
每个namespace中都有一个默认的叫做default的service account资源。进行查看名称空间内的secret也可以看到对应的default-token。
让当前名称空间中所有的pod在连接apiserver时可以使用的预制认证信息,从而保证pod之间的通信。

2.3 service account定义的方式

[root@master ~]# kubectl explain sa
KIND:     ServiceAccount
VERSION:  v1
FIELDS:
apiVersion    <string>
automountServiceAccountToken    <boolean>
imagePullSecrets    <[]Object>
kind    <string>   
metadata    <Object>
secrets    <[]Object>

2.4 service account的创建

[root@master mainfests]# kubectl create serviceaccount mysa -o yaml --dry-run #不执行查看定义方式
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: null
  name: mysa
[root@master mainfests]# kubectl create serviceaccount mysa -o yaml --dry-run > serviceaccount.yaml  #直接导出为yaml定义文件,可以节省敲键盘的时间
[root@master mainfests]# kubectl apply -f serviceaccount.yaml 
serviceaccount/mysa created
[root@master mainfests]# kubectl get serviceaccount/mysa -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"creationTimestamp":null,"name":"mysa","namespace":"default"}}
  creationTimestamp: 2018-10-11T08:12:25Z
  name: mysa
  namespace: default
  resourceVersion: "432865"
  selfLink: /api/v1/namespaces/default/serviceaccounts/mysa
  uid: 62fc7782-cd2d-11e8-801a-000c2972dc1f
secrets:
- name: mysa-token-h2mgk
看到有一个token已经被自动创建,并被service account引用。设置非默认的service account
只需要在pod的spec.serviceAccountName字段中将name设置为您想要用的service account名字即可。
在pod创建之初service account就必须已经存在,否则创建将被拒绝。需要注意的是不能更新已创建的pod的service account

2.5 serviceaccount的自定义使用

这里在default名称空间创建了一个sa为admin,可以看到已经自动生成了一个Tokens:admin-token-7k5nr
[root@master mainfests]# kubectl create serviceaccount admin
serviceaccount/admin created
[root@master mainfests]# kubectl get sa
NAME      SECRETS   AGE
admin     1         3s
default   1         50d
[root@master mainfests]# kubectl describe sa/admin
Name:                admin
Namespace:           default
Labels:              <none>
Annotations:         <none>
Image pull secrets:  <none>
Mountable secrets:   admin-token-7k5nr
Tokens:              admin-token-7k5nr
Events:              <none>
[root@master mainfests]# kubectl get secret
NAME                    TYPE                                  DATA      AGE
admin-token-7k5nr       kubernetes.io/service-account-token   3         31s
default-token-j5pf5     kubernetes.io/service-account-token   3         50d
mysecret                Opaque                                2         1d
tomcat-ingress-secret   kubernetes.io/tls                     2         10d
[root@master mainfests]# vim pod-sa-demo.yaml  #Pod中引用新建的serviceaccount
apiVersion: v1
kind: Pod
metadata:
  name: pod-sa-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
  serviceAccountName: admin
[root@master mainfests]# kubectl apply -f pod-sa-demo.yaml 
pod/pod-sa-demo created
[root@master mainfests]# kubectl describe pods pod-sa-demo
......
Volumes:
  admin-token-7k5nr:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  admin-token-7k5nr
    Optional:    false

在K8S集群当中,每一个用户对资源的访问都是需要通过apiserver进行通信认证才能进行访问的,那么在此机制当中,对资源的访问可以是token,也可以是通过配置文件的方式进行保存和使用认证信息,可以通过kubectl config进行查看配置,如下:

[root@master mainfests]# kubectl config view
apiVersion: v1
clusters:  #集群列表
- cluster:
    certificate-authority-data: REDACTED
    server: https://192.168.56.11: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

在上面的配置文件当中,定义了集群、上下文以及用户。其中Config也是K8S的标准资源之一,在该配置文件当中定义了一个集群列表,指定的集群可以有多个;
用户列表也可以有多个,指明集群中的用户;而在上下文列表当中,是进行定义可以使用哪个用户对哪个集群进行访问,以及当前使用的上下文是什么。
如图:定义了用户kubernetes-admin可以对kubernetes该集群的访问,用户kubernetes-user1对Clluster1集群的访问

上图解析:
1. kubectl config中定义了有哪些集群和哪些用户(都是以列表的形式)
2. contexts就是定义哪个用户去访问哪个集群(从kubectl config中选出来)
3. contexts可以是多个的(一个contexts用来包含一个账号和一个集群),所以用的列表的形式
4. current-context: kubernetes-admin@kubernetes 就是表示从众多的contexts选出一个当前使用的contexts

第3章 自建证书和账号进行访问apiserver流程

3.1 生成证书

[root@master pki]# (umask 077;openssl genrsa -out magedu.key 2048)
Generating RSA private key, 2048 bit long modulus
............................................................................................+++
...................................................................................+++
e is 65537 (0x10001)
[root@master pki]# ll magedu.key 
-rw------- 1 root root 1675 Oct 12 23:52 magedu.key

3.2 使用ca.crt进行签署

[root@master pki]# openssl req -new -key magedu.key -out magedu.csr -subj "/CN=magedu"  证书签署请求
[root@master pki]# openssl x509 -req -in magedu.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out magedu.crt -days 365  #证书签署
Signature ok
subject=/CN=magedu
Getting CA Private Key
[root@master pki]# openssl x509 -in magedu.crt -text -noout

3.3 添加到用户认证

[root@master pki]# kubectl config set-credentials magedu --client-certificate=./magedu.crt --client-key=./magedu.key --embed-certs=true
User "magedu" set.
[root@master pki]# kubectl config set-context magedu@kubernetes --cluster=kubernetes --user=magedu
Context "magedu@kubernetes" created.
[root@master pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: REDACTED
    server: https://192.168.56.11:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
- context:
    cluster: kubernetes
    user: magedu
  name: magedu@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: magedu
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
[root@master pki]# kubectl config use-context magedu@kubernetes
Switched to context "magedu@kubernetes".
[root@k8s-master pki]# kubectl get pods
No resources found.
Error from server (Forbidden): pods is forbidden: User "magedu" cannot list pods in the namespace "default"
从上面的演示,当切换成magedu用户进行访问集群时,由于magedu该账户没有管理集群的权限,所以在获取pods资源信息时,会提示Forrbidden。那么下面就再来了解一下怎么对账户进行授权

第4章 RBAC----基于角色的访问控制

4.1 授权的引入

Kubernetes的授权是基于插件形式的,其常用的授权插件有以下几种:
1) Node(节点认证)
2) ABAC(基于属性的访问控制)
3) RBAC(基于角色的访问控制)
4) Webhook(基于http回调机制的访问控制)
让一个用户(Users)扮演一个角色(Role),角色拥有权限,从而让用户拥有这样的权限,随后在授权机制当中,只需要将权限授予某个角色,
此时用户将获取对应角色的权限,从而实现角色的访问控制。如图

4.2 基于角色的访问控制(Role-Based Access Control(RBAC))

在k8s的授权机制当中,采用RBAC的方式进行授权,其工作逻辑是
1)把对对象的操作权限定义到一个角色当中,再将用户绑定到该角色,从而使用户得到对应角色的权限。
2)此种方式仅作用于名称空间当中,这是什么意思呢?
当User1绑定到Role角色当中,User1就获取了对该NamespaceA的操作权限,但是对NamespaceB是没有权限进行操作的,如get,list等操作。
3)另外,k8s为此还有一种集群级别的授权机制,就是定义一个集群角色(ClusterRole),
对集群内的所有资源都有可操作的权限,从而将User2,User3通过ClusterRoleBinding到ClusterRole,从而使User2、User3拥有集群的操作权限。
Role、RoleBinding、ClusterRole和ClusterRoleBinding的关系如下图:

4.2.1 角色的绑定

role RoleBinding 
ClusterRole ClusterRoleBinding
这2中都好理解,但是还有一种role RoleBinding clusterrole
这种就是假设有10个名称空间,以管理员为例,
名称空间1,需要一个admin,拥有全部权限
名称空间2,需要一个admin,拥有全部权限
...
这样绑定起来就很麻烦,实际上就是一个用户对每个名称空间都有相同的权限,只是相当于名称空间而言它们所在的名称空间不一样
我们可以把这个用户拿出来,用role绑定clusterrole,这样只需要定义一个用户,救可以管理这10个名称空间了!

4.3 Kubernetes RBAC的演示

4.3.1 User =--> Rolebinding --> Role

  • (1)角色的创建
[root@master pki]# kubectl create role -h
Create a role with single rule.

Examples:
  # Create a Role named "pod-reader" that allows user to perform "get", "watch" and "list" on pods
  kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods
  
  # Create a Role named "pod-reader" with ResourceName specified
  kubectl create role pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod
  
  # Create a Role named "foo" with API Group specified
  kubectl create role foo --verb=get,list,watch --resource=rs.extensions
  
  # Create a Role named "foo" with SubResource specified
  kubectl create role foo --verb=get,list,watch --resource=pods,pods/status

Options:
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in
the template. Only applies to golang and jsonpath output formats.
      --dry-run=false: If true, only print the object that would be sent, without sending it.
  -o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
      --resource=[]: Resource that the rule applies to
      --resource-name=[]: Resource in the white list that the rule applies to, repeat this flag for multiple items
      --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the
annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
      --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The
template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
      --validate=true: If true, use a schema to validate the input before sending it
      --verb=[]: Verb that applies to the resources contained in the rule

Usage:
  kubectl create role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run]
使用kubectl create进行创建角色,指定角色名称,--verb指定权限,--resource指定资源或者资源组,--dry-run单跑模式并不会创建
[options]

Use "kubectl options" for a list of global command-line options (applies to all commands).
[root@master pki]# kubectl create role pods-reader --verb=get,list,watch --resource=pods --dry-run -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role #资源类型
metadata:
  creationTimestamp: null
  name: pods-reader
rules:
- apiGroups: #对那些api组内的资源进行操作
  - ""
  resources:  #对那些资源定义
  - pods
  verbs:      #操作权限定义
  - get
  - list
  - watch
kubectl create role pods-reader --verb=get,list,watch --resource=pods --dry-run -o yaml > /mainfest/role-demo.yaml
  • 2 角色绑定用户
[root@master mainfest]# kubectl create rolebinding -h
Create a RoleBinding for a particular Role or ClusterRole.

Examples:
  # Create a RoleBinding for user1, user2, and group1 using the admin ClusterRole
  kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1

Options:
      --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in
the template. Only applies to golang and jsonpath output formats.
      --clusterrole='': ClusterRole this RoleBinding should reference
      --dry-run=false: If true, only print the object that would be sent, without sending it.
      --generator='rolebinding.rbac.authorization.k8s.io/v1alpha1': The name of the API generator to use.
      --group=[]: Groups to bind to the role
  -o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
      --role='': Role this RoleBinding should reference
      --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the
annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
      --serviceaccount=[]: Service accounts to bind to the role, in the format <namespace>:<name>
      --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The
template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
      --validate=true: If true, use a schema to validate the input before sending it

Usage:
  kubectl create rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname]
[--serviceaccount=namespace:serviceaccountname] [--dry-run] [options]
使用kubectl create进行创建角色绑定,指定角色绑定的名称,--role|--clusterrole指定绑定哪个角色,--user指定哪个用户
Use "kubectl options" for a list of global command-line options (applies to all commands).
[root@master mainfest]# kubectl create rolebinding magedu-read-pods --role=pods-reader --user=magedu --dry-run -o yaml > rolebinding-demo.yaml
[root@master mainfest]# kubectl apply -f rolebinding-demo.yaml 
  • 3 看角色绑定的信息
[root@master mainfest]# kubectl describe rolebinding magedu-read-pods
Name:         magedu-read-pods
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"RoleBinding","metadata":{"annotations":{},"creationTimestamp":null,"name":"magedu-rea...
Role:
  Kind:  Role
  Name:  pods-reader
Subjects:
  Kind  Name    Namespace
  ----  ----    ---------
  User  magedu  
以看到user:magedu绑定到了pods-reader这个角色上
  • 4 切换magedu这个用户,并使用get获取pods资源信息
 [root@k8s-master ~]# kubectl config use-context magedu@kubernetes 
Switched to context "magedu@kubernetes".
[root@k8s-master ~]# kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
filebeat-ds-hxgdx        1/1       Running   1          36d
filebeat-ds-s466l        1/1       Running   2          36d
myapp-0                  1/1       Running   0          2d
myapp-1                  1/1       Running   0          2d
myapp-2                  1/1       Running   0          2d
myapp-3                  1/1       Running   0          2d
pod-sa-demo              1/1       Running   0          1d
pod-vol-demo             2/2       Running   0          3d
redis-5b5d6fbbbd-q8ppz   1/1       Running   1          4d
[root@k8s-master ~]# kubectl get pods -n ingress-nginx  #测试获取ingress-nginx这个名称空间的pods信息
No resources found.
Error from server (Forbidden): pods is forbidden: User "magedu" cannot list pods in the namespace "ingress-nginx"
从上面的操作,可以总结出,role的定义和绑定,仅作用于当前名称空间,在获取ingress-nginx名称空间时,一样会出现Forbidden!

4.3.2 User--> Clusterrolebinding --> Clusterrole

  • 1 定义clusterrole和权限
[root@master mainfests]# vim clusterrole-demo.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-read
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
  • 2 创建clusterrole
[root@ mainfests]# kubectl apply -f clusterrole-demo.yaml
  • 3 创建角色绑定
magedu绑定到clusterrole:magedu-read-all-pods上,
1. 先删除前面的绑定
 kubectl delete rolebinding magedu-read-pods
2. 绑定角色
vim clusterrolebinding-demo.yaml 
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: magedu-read-all-pods
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-read
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: magedu
kubectl apply -f clusterrolebinding-demo.yaml 
kubectl get clusterrolebinding
从上面的实验,我们可以知道对用户magedu进行集群角色绑定,用户magedu将会获取对集群内所有资源的对应权限。

4.3.3 User --> Rolebinding --> Clusterrole

将maedu通过rolebinding到集群角色magedu-read-pods当中,此时,magedu仅作用于当前名称空间的所有pods资源的权限
[root@master mainfests]# kubectl delete clusterrolebinding magedu-read-all-pods
clusterrolebinding.rbac.authorization.k8s.io "magedu-read-all-pods" deleted

[root@master mainfests]# kubectl create rolebinding magedu-read-pods --clusterrole=cluster-read --user=magedu --dry-run -o yaml > rolebinding-clusterrole-demo.yaml
[root@master mainfests]# vim rolebinding-clusterrole-demo.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: magedu-read-pods
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-read
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: magedu

[root@master mainfests]# kubectl apply -f rolebinding-clusterrole-demo.yaml 
rolebinding.rbac.authorization.k8s.io/magedu-read-pods created

[root@master ~]$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
filebeat-ds-hxgdx        1/1       Running   1          36d
filebeat-ds-s466l        1/1       Running   2          36d
myapp-0                  1/1       Running   0          2d
myapp-1                  1/1       Running   0          2d
myapp-2                  1/1       Running   0          2d
myapp-3                  1/1       Running   0          2d
pod-sa-demo              1/1       Running   0          1d
pod-vol-demo             2/2       Running   0          4d
redis-5b5d6fbbbd-q8ppz   1/1       Running   1          4d
[root@k8s-master ~]$ kubectl get pods -n ingress-nginx
No resources found.
Error from server (Forbidden): pods is forbidden: User "magedu" cannot list pods in the namespace "ingress-nginx"
posted @ 2020-07-13 15:07  液体之火  阅读(68)  评论(0编辑  收藏