十. k8s--访问控制 serviceaccount和RBAC 学习笔记

用户账户与服务账户

Kubernetes 区分用户账户和服务账户的概念主要基于以下原因:

  • 用户账户是针对人而言的。 服务账户是针对运行在pod中的进程而言的。
  • 用户账户是全局性的。 其名称在集群各namespace中都是全局唯一的,未来的用户资源不会做namespace隔离, 服务账户是namespace隔离的。
  • 通常情况下,集群的用户账户可能会从企业数据库进行同步,其创建需要特殊权限,并且涉及到复杂的业务流程。 服务账户创建的目的是为了更轻量,允许集群用户为了具体的任务创建服务账户 (即权限最小化原则)。
  • 对人员和服务账户审计所考虑的因素可能不同。
  • 针对复杂系统的配置可能包含系统组件相关的各种服务账户的定义。 因为服务账户可以定制化地创建,并且有namespace级别的名称,这种配置是很轻量的。
UserAccount常用于复杂业务逻辑管控,作用于系统全局,独立于K8s之外
ServiceAccount仅用于实现某些特定操作任务,隶属于名称空间,由API Server管理

访问控制过程

客户端 -> API Server -> 认证插件 -> 授权插件 -> 准入控制插件 -> 写入成功

需要注意:认证授权过程只存在HTTPS形式的API中。也就是说,如果客户端使用HTTP连接到kube-apiserver,是不会进行认证授权的。所以说,可以这么设置,在集群内部组件间通信使用HTTP集群, 外部就使用HTTPS,这样既增加了安全性,也不至于太复杂。
### K8s内建用户组:
  • system:unauthenticated,未通过认证测试的用户所属的组
  • system:authenticated,认证成功的用户自动加入的组,用于快捷引用所有正常通过认证的用户帐号
  • system:serviceaccounts,当前系统上所有Service Account对象
  • system:serviceaccounts:<namespace>,特定名称空间内所有Service Account对象

认证. 授权与准入控制

  • API Server支持同时启用多种认证机制, 但至少包括UserAccount和ServiceAccount中的一种
  • 启用多种认证插件时, 认证过程会以串行方式进行, 直到一种成功即可, 认证失败会返回401

认证方式

  1. X509客户端证书认证:客户端请求报文中携带X509格式证书,通过后,CN字段是用户名,O字段是所属的组,O可以有多个,即属于多个组
  2. 静态令牌文件:由kube-apiserver 选项--token-auth-file加载,启动后不可更改;HTTP客户端也能使用承载令牌进行身份验证,将令牌编码后,请求报文中Authorization承载传递
  3. 引导令牌:kubeadm join将节点加入集群时,就是这种方式
  4. 静态密码文件:用户名密码等以明文存储的CSV格式文件,由kube-apiserver通过--basic-auth-file加载
  5. 服务帐户令牌:由kube-apiserver自动启用。ServiceAccount通常由API Server自动创建,并通过ServiceAccount准入控制器将其注入Pod对象,容器中应用请求API Server的服务时将以此完成身份证
  6. OpenID连接令牌:OAuth2认证
  7. Webhook令牌:客户端使用kubeconfig格式的配置文件
  8. 认证代理:X-Remote-User
  9. Keystone密码:借助Keystone服务器进行身份认证
  10. 匿名请求:未被任何验证机制明确拒绝的用户即匿名用户,system:anonymous 属于 system:unauthenticated组;匿名用户可通过 --anonymous-auth=false禁用

内建的授权插件:

  1. Node,基于Pod资源的目标调度节点来实现对kubelet的访问控制

  2. ABAC,基于属性的访问控制,attribute-based access control

  3. RBAC,基于角色的访问控制,role-based access control

  4. Webhook,基于HTTP回调机制通过外部REST服务检查确认用户授权的访问控制

  5. AlwaysDeny,总是拒绝,仅用于测试

  6. AlwaysAllow,总是允许

    启用API Server时 --authorization-mode定义要启用的授权机制,多个选项以逗号分隔

准入控制器

在对象持久化存储etcd前,强制执行对象的语义验证等功能
读取资源信息的请求不会经过准入控制器检查

  1. AlwaysAdmit,允许所有请求
  2. AlwaysDeny,拒绝所有请求,仅用于测试
  3. AlwaysPullImages,总是下载镜像
  4. NamespaceLifecycle,拒绝在不存在的名称空间创建资源,删除名称空间会级联删除其下所有资源
  5. LimitRanger,可用资源范围界定,确保资源请求不会超限
  6. ServiceAccount,实现ServiceAccount管理机制自动化,创建Pod对象时自动为其附加相关ServiceAccount对象
  7. PersistnetVolumeLabel,为由云计算服务商提供的PV自动附加region或zone标签
  8. DefaultStorageClass,监控所有创建PVC对象的请求,保证没有附加专用StorageClass的请求会自动设定一个默认值
  9. ResourceQuota,对名称空间设置可用资源上限,确保在其中创建的设置了资源限额的对象不会超出名称空间的资源配额
  10. DefaultTolerationSeconds,如果Pod对象上不存在污点宽容期限,则为它们设置默认宽容期,以宽容 notready:NoExecute 和 unreachable:NoExctute 类污点5min
  11. ValidatingAdmissionWebhook,并行调用匹配当前请求的所有验证类Webhook,任何一个校验失败,请求即失败
  12. MutatingAdmissionWebhook,串行调用匹配当前请求的所有变异类Webhook,每个调用都可能会更改对象

ServiceAccount管理与应用

Service Account 资源一般由用户名和相关的Secret对象组成
用于让Pod对象内的容器进程访问其他服务时提供身份认证信息,这些其他服务包括:API 调度器 Pod控制器 节点控制器 私有Registry服务等

Service Account 自动化

每个Pod都会自动关联一个存储卷,挂载至 /var/run/secrets/kubernetes.io/serviceaccount

[root@master ~]# kubectl exec nginx-554b9c67f9-r5852 ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt # 这是API Server的CA公钥证书,用于Pod中的Process对API Server的服务端数字证书进行校验时使用的
namespace
token  # token保存了Service Account的认证token 容器中进程使用它向API Server发起连接请求
每个Pod对象都只有一个服务帐户,若创建时未明确指定,会自动附加当前名称空间中默认服务帐户default
``` [root@master ~]# kubectl describe serviceaccounts default Name: default Namespace: default Labels: Annotations: Image pull secrets: Mountable secrets: default-token-l5bzk Tokens: default-token-l5bzk Events: ```

K8s中的SSL/TLS认证

  • etcd集群内对等节点通信:默认2380端口,基于SSL/TLS通信
  • etcd服务器与客户端通信:Restful API 默认2379端口,基于SSL/TLS通信

创建一个ServiceAccount

#测试
[root@master ~]# kubectl create serviceaccount admin -o yaml --dry-run #干跑
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: null
  name: admin

kubectl create serviceaccount admin
 
#查看以创建的service帐号
[root@master ~]# kubectl get sa
NAME      SECRETS   AGE
admin     1         6s
default   1         24d
 
#查看详细信息
kubectl describe sa admin 
 
##简洁输出
kubectl get pods myapp-0 -o yaml --export

pod使用上述创建的ServiceAccount

apiVersion: v1
kind: Pod
metadata:
  name: pod-sa-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
  annotations:
    leiyan.com/reatedby: "cluster admin"
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
  serviceAccountName: admin

客户端配置文件kubeconfig

包括kubectl、kubelet、kube-controller-manager等在内的API Server的各类客户端都可以使用kubeconfig配置文件提供接入多个集群的相关配置信息

包括API Server的URL及认证信息,且可设置不同的上下文,并在各环境之间快速切换

/etc/kubernetes/admin.conf即为kubeconfig格式的配置文件

查看当前正在使用的配置文件, 上下文是集群和用户的配对
``` kubectl config view #显示群集列表、用户列表、上下文列表、当前使用的上下文 ```
[root@master ~]# kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://10.0.0.50: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

kubeconfig配置文件可通过kubectl config命令进行设定

kubectl config view,打印文件内容
kubectl config set-cluster,设置clusters段
kubectl config set-credentials,设置users段
kubectl config set-context,设置contexts段
kubectl config set-use-context,设置current-context段

添加ServiceAccount

  1. 为帐号kube-user1创建私钥及证书文件,保存于/etc/kubernetes/pki目录中 #需要在master节点以root用户执行

    cd /etc/kubernetes/pki
    
    (umask 077; openssl genrsa -out kube-user1.key 2048)
    
    openssl req -new -key kube-user1.key -out kube-user1.csr -subj "/CN=kube-user1/O=kubeusers" # 其中 CN是用户名,O是用户组
    
    openssl x509 -req -in kube-user1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out kube-user1.crt -days 3650 
    
    openssl x509 -in kube-user1.crt -text -noout # 验证证书(可选)
    
  2. 以默认管理员 kubernetes-admin@kubernetes为新用户kube-user1设定配置文件,默认保存于 .kube/config 也可使用 --kubeconfig指定自定义路径

    2.1 配置集群信息,存在可省略此步骤

    kubectl config set-cluster kubernetes-new --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.crt --server="https://10.0.0.50:6443"
    

    2.2 配置客户端证书及密钥,用户名组名会自动提取

    kubectl config set-credentials kube-user1 --embed-certs=true --client-certificate=/etc/kubernetes/pki/kube-user1.crt --client-key=/etc/kubernetes/pki/kube-user1.key
    

    2.3 配置context,组合cluster和credentials

    kubectl config set-context kube-user1@kubernetes-new --cluster=kubernetes-new --user=kube-user1
    

    2.4 指定当前上下文

    kubectl config use-context kube-user1@kubernetes-new
    

    2.5 测试

    [root@master pki]# kubectl get pods
    Error from server (Forbidden): pods is forbidden: User "kube-user1" cannot list resource "pods" in API group "" in the namespace "default"
    
    #切换回来
    kubectl config use-context kubernetes-admin@kubernetes
    
    [root@master pki]# kubectl get pods
    NAME                     READY   STATUS        RESTARTS   AGE
    nginx-554b9c67f9-r5852   1/1     Running       0          89m
    pod-cm-1                 1/1     Running       0          6d
    pod-cm-2                 1/1     Running       0          6d
    pod-hostpath-demo        1/1     Terminating   0          7d21h
    

角色访问控制RBAC (Role-Based Access Control)

相关概念

Role与ClusterRole

在RBAC API中,一个角色包含了一套表示一组权限的规则。 权限以纯粹的累加形式累积(没有”否定”的规则)。 角色可以由命名空间(namespace)内的Role对象定义,而整个Kubernetes集群范围内有效的角色则通过ClusterRole对象实现。


一个Role对象只能用于授予对某一单一命名空间中资源的访问权限。
以下示例描述了”default”命名空间中的一个Role对象的定义,用于授予对pod的读访问权限:
**创建一个`role`**
[root@master manifests]# cat role-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pods-reader
  namespace: default
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
[root@master manifests]# kubectl apply -f role-demo.yaml
role.rbac.authorization.k8s.io/pods-reader created

将role和user绑定, 并验证已经生效, 可以get到pod资源

# 将kube-user1和pods-reader绑定
[root@master manifests]# kubectl create rolebinding kube-user1-read-pods --role=pods-reader --user=kube-user1
rolebinding.rbac.authorization.k8s.io/kube-user1-read-pods created

# 切换用户到kube-user1
[root@master manifests]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".

# 测试可以get到pod信息
[root@master manifests]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
myapp-0   1/1     Running   0          5d4h
myapp-1   1/1     Running   0          5d4h
myapp-2   1/1     Running   0          5d4h
myapp-3   1/1     Running   0          5d4h
ClusterRole对象可以授予与Role对象相同的权限,但由于它们属于集群范围对象, 也可以使用它们授予对以下几种资源的访问权限:
- 集群范围资源(例如节点,即node) - 非资源类型endpoint(例如”/healthz”) - 跨所有命名空间的命名空间范围资源(例如pod,需要运行命令`kubectl get pods --all-namespaces`来查询集群中所有的pod)

创建ClusterRole

[root@master manifests]# cat cluster-role-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-role
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
[root@master manifests]# kubectl apply -f cluster-role-demo.yaml
clusterrole.rbac.authorization.k8s.io/cluster-role created

ClusterRoleUser绑定, 并验证权限是否生效

[root@master manifests]# cat clusterrolebinding-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: user1-read-all-pods
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: kube-user1
[root@master manifests]# kubectl apply -f clusterrolebinding-demo.yaml
clusterrolebinding.rbac.authorization.k8s.io/user1-read-all-pods created

验证权限

# 切换用户到kube-user1
[root@master manifests]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".

# 成功获取到默认namespace的pod信息
[root@master manifests]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
myapp-0   1/1     Running   0          5d4h
myapp-1   1/1     Running   0          5d4h
myapp-2   1/1     Running   0          5d4h
myapp-3   1/1     Running   0          5d4h

# 成功获取到其他namespace的pod信息
[root@master manifests]# kubectl get pod -n ingress-nginx
NAME                                        READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-7995bd9c47-crpwt   1/1     Running   0          12d

RoleBinding与ClusterRoleBinding

角色绑定将一个角色中定义的各种权限授予一个或者一组用户。 角色绑定包含了一组相关主体(即subject, 包括用户——User、用户组——Group、或者服务账户——Service Account)以及对被授予角色的引用。 在命名空间中可以通过RoleBinding对象授予权限,而集群范围的权限授予则通过ClusterRoleBinding对象完成。

RoleBinding可以引用在同一命名空间内定义的Role对象。 下面示例中定义的RoleBinding对象在”default”命名空间中将”pod-reader”角色授予用户”kube-user1”。 这一授权将允许用户”kube-user1”从”default”命名空间中读取pod。
```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: user1-read-pods namespace: default roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: pod-reader subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: kube-user1 ```
RoleBinding对象也可以引用一个ClusterRole对象用于在RoleBinding所在的命名空间内授予用户对所引用的ClusterRole中 定义的命名空间资源的访问权限。这一点允许管理员在整个集群范围内首先定义一组通用的角色,然后再在不同的命名空间中复用这些角色。
**将clusterrole通过rolebinding和user绑定到一起, 会降级到rolebinding所在的namespace**
[root@master manifests]# cat rolebinding-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: user1-read-pods
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: kube-user1
[root@master manifests]# kubectl apply -f rolebinding-clusterrole.yaml
rolebinding.rbac.authorization.k8s.io/user1-read-pods created

这时候发现只能获取到RoleBinding设置的namespace中的pod

[root@master ~]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
[root@master ~]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
myapp-0   1/1     Running   0          5d4h
myapp-1   1/1     Running   0          5d4h
myapp-2   1/1     Running   0          5d4h
myapp-3   1/1     Running   0          5d4h
[root@master ~]# kubectl get pod -n ingress-nginx
Error from server (Forbidden): pods is forbidden: User "kube-user1" cannot list resource "pods" in API group "" in the namespace "ingress-nginx"

最后将ClusterRoleUser通过ClusterRoleBinding绑定到一起

允许用户kube-user1读取所有namespace的pod信息

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: user1-read-all-pods
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: kube-user1
[root@master manifests]# kubectl apply -f clusterrolebinding-demo.yaml
clusterrolebinding.rbac.authorization.k8s.io/user1-read-all-pods created
[root@master manifests]# kubectl config use-context kube-user1@kubernetes
Switched to context "kube-user1@kubernetes".
[root@master manifests]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
myapp-0   1/1     Running   0          5d7h
myapp-1   1/1     Running   0          5d7h
myapp-2   1/1     Running   0          5d7h
myapp-3   1/1     Running   0          5d7h
[root@master manifests]# kubectl get pod -n ingress-nginx
NAME                                        READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-7995bd9c47-crpwt   1/1     Running   0          13d

参考链接

https://pdf.us/2019/03/21/3061.html

https://jimmysong.io/kubernetes-handbook/concepts/rbac.html

posted @ 2019-09-17 21:12  培天王  阅读(2377)  评论(0编辑  收藏  举报