企业级实战模块四:Kubernetes 配置管理及RBAC机制

企业级实战模块四:Kubernetes 配置管理及RBAC机制

1 配置管理中心configmap

1.1 Configmap 概述

1)什么是 Configmap

Configmap是 kubernetes 中的资源对象,用于保存非机密性的配置的,数据可以用 key/value键值对 的形式 保存 ,也可通过文件的形式保存

2)Configmap能解决哪些问题

我们在部署服务的时候,每个服务都有自己的配置文件,如果一台服务器上部署多个服务: nginx 、 tomcat 、 apache 等,那么这些配置都存在这个节点上, 假如一台服务器不能满足线上高并发的要求,需要对服务器扩容,扩容之后的服务器还是需要部署多个服务 nginx 、 tomcat 、 apache 新增加的服务器上还是要管理这些服务的配置如果有一个服务出现问题。

需要修改配置文件, 每台物理节点上的配置都需要修改,这种方式肯定满足不了线上 大批量的配置变更要求。 所以, k 8s 中引入了 Configmap资源对象,可以当成 volume 挂载到 pod 中,实现统一的配置管理 。

image-20211027190319658

  • Configmap 是 k8s 中的资源,相当于配置文件,可以有一个或者多个 Configmap

  • Configmap 可以做成 Volume,k8s pod 启动之后,通过 volume 形式映射到容器内部指定目录上;

  • 容器中应用程序按照原有方式读取容器特定目录上的配置文件。

  • 在容器看来,配置文件就像是打包在容器内部特定目录,整个过程对应用没有任何

3)Configmap 应用场景

  • 使用 k8s 部署应用,当你将应用配置写进代码中,更新配置时也需要打包镜像,configmap 可以将配置信息和 docker 镜像解耦以便实现镜像的可移植性和可复用性,因为一个 configMap 其实就是一系列配置信息的集合,可直接注入到 Pod 中 给 容器使用 。 configmap 注入方式有两种,一种将 configMap 做为存储卷,一种是将configMap 通过 env 中 configMapKeyRef 注入到容器中 。

  • 使用微服务架构的话,存在多个服务共用配置的情况,如果每个服务中单独一份配置的话,那么更新配置就很麻烦,使用 configmap 可以友好的进行配置共享。

4)局限性

ConfigMap在设计上不是用来保存大量数据的。在 Con figMap 中保存的数据不可超过 1MiB 。如果你需要保存超出此尺寸限制的数据, 可以 考虑挂载存储卷或者使用独立的数据库或者文件服务。

1.2 Configmap创建方法

1)命令行直接创建

直接在命令行中指定configmap 参数创建, 通过 --from-literal 指定参数

kubectl create configmap tomcat-config --from-literal=tomcat_port=8080 --from-literal=server_name=myapp.tomcat.com
kubectl get cm

image-20211028093338061

kubectl describe configmap tomcat-config

image-20211028093352866

2)通过文件创建

通过指定文件创建一个configmap, --from-file=<文件>

cat <<EOF> nginx.conf
server {
server_name www.nginx.com;
listen 80;
root /home/nginx/www
}
EOF

定义一个 key 是 www ,值是 nginx .conf 中的内容

kubectl create configmap www-nginx --from-file=www=./nginx.conf
kubectl get cm

image-20211028094039305

kubectl describe configmap www-nginx

image-20211028094056965

3)指定目录创建 configmap

mkdir test-cm && cd test-cm
cat <<EOF>my-server.cnf
server-id=1
EOF

cat <<EOF>my-slave.cnf
server-id=2
EOF
kubectl create configmap mysql-config --from-file=/root/test-cm/
kubectl get cm

image-20211028094605938

kubectl describe configmap mysql-config

image-20211028094645799

4)编写 configmap 资源清单 YAML 文件

cat <<EOF> mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql
labels:
  app: mysql
data:
master.cnf: |
  [mysqld]
  log-bin
   log_bin_trust_function_creators=1
   lower_case_table_names=1
  slave.cnf: |
  [mysqld]
  super-read-only
   log_bin_trust_function_creators=1
EOF
kubectl apply -f mysql-configmap.yaml

kubectl get cm

image-20211028095102839

kubectl describe configmap mysql

image-20211028095213575

1.3 使用Configmap

1)通过环境变量引入: 使用 configMapKeyRef

#创建一个存储 mysql 配置的 configmap
cat <<EOF> mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql
labels:
  app: mysql
data:
  log: "1"
  lower: "1"
EOF

kubectl apply -f mysql-configmap.yaml

image-20211028101639135

#创建 pod ,引用 Configmap 中的内容
cat <<EOF> mysql-pod.yaml
apiVersion: v1
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod
spec:
containers:
 - name: mysql
  image: busybox
  command: [ "/bin/sh", "-c", "sleep 3600" ]
  env:
   - name: log_bin # 定义环境变量 log_bin
    valueFrom:
      configMapKeyRef:
        name: mysql # 指定 configmap 的名字
        key: log # 指定 configmap 中的 key
   - name: lower # 定义环境变量 lower
    valueFrom:
      configMapKeyRef:
        name: mysql
        key: lower
restartPolicy: Never
EOF

kubectl apply -f mysql-pod.yaml

image-20211028102038695

# 进入pod内进行验证
kubectl exec -it mysql-pod -- /bin/sh

image-20211028102845761

2)通过环境变量引入: 使用 envfrom

# 创建 pod ,引用 Configmap 中的内容
cat <<EOF> mysql-pod-envfrom.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod-envfrom
spec:
containers:
 - name: mysql
  image: busybox
  command: [ "/bin/sh", "-c", "sleep 3600" ]
  envFrom:
   - configMapRef:
      name: mysql # 指定 configmap 的名字
restartPolicy: Never
EOF

kubectl apply -f mysql-pod-envfrom.yaml

image-20211028103402985

3)把 configmap 做成 volume ,挂载到 pod

cat <<EOF> mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-1
labels:
  app: mysql
data:
log: "1"
lower: "1"
my.cnf: |
  [mysqld]
   Welcome= word
EOF

kubectl apply -f mysql-configmap.yaml
cat <<EOF> mysql-pod-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: mysql-pod-volume
spec:
containers:
 - name: mysql
  image: busybox
  command: [ "/bin/sh","-c","sleep 3600" ]
  volumeMounts:
   - name: mysql-config
    mountPath: /tmp/config
volumes:
 - name: mysql-config
  configMap:
    name: mysql-1
restartPolicy: Never
EOF

kubectl apply -f mysql-pod-volume.yaml
kubectl exec -it mysql-pod-volume -- /bin/sh

image-20211028104958243

1.4 Configmap热更新

kubectl edit configmap mysql-1

image-20211028105613932

kubectl exec -it mysql-pod-volume -- /bin/sh

image-20211028105640913

注意,更新ConfigMap 后:

  • 使用该ConfigMap 挂载的 Env 不会同步更新

  • 使用该ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概 10 秒)才能同步更新

2 配置管理中心secret

2.1 Secret 是什么?

1)介绍

Configmap 一般是用来存放明文数据的,如配置文件,对于一些敏感数据,如密码、私钥等数据时,要用 secret 类型。

Secret解决了密码、 token 、秘钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec 中。 Secret 可以以 Volume 或者环境变量的方式使用。

要使用secret pod 需要引用 secret 。 Pod 可以用两种方式使用 secret :作为volume 中的文件被挂载到 pod 中的一个或者多个容器里,或者当 kubelet 为 pod 拉取镜像时使用。

2)secret可选参数

  • generic:通用类型,通常用于存储密码数据。

  • tls :此类型仅用于存储私钥和证书。

  • docker registry: 若要保存 docker 仓库的认证信息的话,就必须使用此种类型来创建。

3)Secret类型

  • Service Account用于被 serviceaccount 引用。 serviceaccout 创建时Kubernetes 会默认创建对应的 secret 。 Pod 如果使用了 serviceaccount ,对应的secret 会自动挂载到 Pod 的/run/secrets/kubernetes.io/serviceaccount 目录中。

  • Opaque:base64 编码格式的 Secret,用来存储密码、秘钥等。可以通过 base64-decode 解码获得原始数据,因此安全性弱

  • kubernetes.io/dockerconfigjson:用来存储私有 docker registry 的认证信息。

2.2 使用 Secret

1)通过环境变量引入 Secret

kubectl create secret generic mysql-password --from-literal=password= pwd123456

kubectl get secret

image-20211029130921393

kubectl describe secret mysql-password

image-20211029131023236

# 创建POD 

cat <<EOF> pod-secret.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-secret
labels:
  app: myapp
spec:
containers:
 - name: mysql
  image: ikubernetes/myapp:v1
  ports:
   - name: http
    containerPort: 80
  env:
    - name: MYSQL_ROOT_PASSWORD # 它是 Pod 启动成功后 ,Pod 中容器的环境变量名
      valueFrom:
        secretKeyRef:
          name: mysql-password # 这是secret的对象名
          key: password # 它是secret中的key名
EOF

kubectl apply -f pod-secret.yaml
kubectl exec -it pod-secret -- /bin/sh

image-20211029131829387

2)通过 volume 挂载 Secret

# 创建手动加密,基于base64 加密
echo -n 'admin' | base64
YWRtaW4=

echo -n 'pwd123456' | base64
cHdkMTIzNDU2


# 解密
echo cHdkMTIzNDU2 | base64 -d
pwd123456
# 创建 secret 
cat <<EOF> secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: cHdkMTIzNDU2
EOF

kubectl apply -f secret.yaml
kubectl describe secret mysecret

image-20211029133017047

# 将Secret挂载到Volume 中
cat <<EOF> pod-secret-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-secret-volume
spec:
containers:
 - name: myapp
  image: registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
  volumeMounts:
   - name: secret-volume
    mountPath: /etc/secret
    readOnly: true
volumes:
 - name: secret-volume
  secret:
    secretName: mysecret
EOF

kubectl apply -f pod-secret-volume.yaml
kubectl exec -it pod-secret-volume -- /bin/sh 

image-20211029134021472

image-20211029134031538

3 RBAC授权

3.1 Kubernetes 安全管理:认证、授权、准入控制概述

k8s对我们整个系统的认证,授权,访问控制做了精密的设置;对于 k8s 集群来说, apiserver 是整个集群访问控制的唯一入口,我们在 k8s 集群之上部署应用程序的时候,也可以通过宿主机的NodePort 暴露的端口访问里面的程序,用户访问 kubernetes 集群需要经历如下认证过程:认证授权准入控制( adminationcontroller)

 

认证 ( 是对客户端的认证,通俗点就是用户名密码验证)

授权 ( 是对资源的授权, k8s 中的资源无非是容 器,最终其实就是容器的计算,网络,存储资源,当一个请求经过认证后,需要访问某一个资源(比如创建一个 pod ),授权检查 会 根据授权规则判定该资源(比如某 namespace 下的 pod )是否是该客户可访问的。

准入 (Admission) 机制准入控制器(Admission Controller )位于 API Server 中,在对象被持久化之前,准入控制器拦截对 API Server 的请求,一般用来做身份验证和授权。其中包含两个特殊的控制器:

MutatingAdmissionWebhook和 ValidatingAdmissionWebhook 。分别作为配置的变异和验证 准入控制 webhook 。
  • 变更(Mutating )准入控制:修改请求的对象

  • 验证(Validating )准入控制:验证请求的对象

准入控制器是在API Server 的启动参数配置的。一个准入控制器可能属于以上两者中的一种,也可能两者都属于。当请求到达 API Server 的时候首先执行变更准入控制,然后再执行验证准入控制。

我们在部署Kubernetes 集群的时候都会默认开启一系列准入控制器,如果没有设置这些准入控制器的话可以说你的 Kubernetes 集群就是在裸奔,应该只有集群管理员可以修改集群的准入控制器。

例如我会默认开启如下的准入控制器。

--admission-control=ServiceAccount,NamespaceLifecycle,NamespaceExists,LimitRanger,ResourceQ
uota,MutatingAdmissionWebhook,ValidatingAdmissionWebhook

k8s的整体架构也是一个微服务的架构,所有的请求都是通过一个 GateWay ,也就是 kubeapiserver 这个组件(对外提供 REST 服务), k8s 中客户端有两类,一种是普通用户, 一种是集群内的 Pod ,这两种客户端的认证机制略有不同,但无论是哪一种,都需要依次经过认证,授权,准入这三个机制。

1)认证

1、 认证支持多种插件 (1 )令牌 token )认证 双方有一个共享密钥,服务器上先创建一个密码 下来 客户端登陆的时候拿这个密码登陆即可,这个就是对称密钥认证方式; k8s 提供了一个 restful 风格的接口,它的所有服务都是通过 http 协议提供的,因此认证信息只能经由 http 协议的认证首部进行传递,这种认证首部进行传递通常叫做令牌;

(2) ssl 认证: 对于k8s 访问来讲, ssl 认证能让客户端确认服务器的认证身份,我们在跟服务器通信的时候,需要服务器发过来一个证书,我们需要确认这个证书是不是 ca 签署的,如果是我们认可的 ca 签署的,里面的 subj 信息与我们访问的目标主机信息保持一致,没有问题,那么我们就认为服务 器的身份得到认证了, k8s 中最重要的是服务器还需要认证客户端的信息, kubectl 也应该有一个证书,这个证书也是 server 所认可的 ca 签署的证书,双方需要互相认证,实现加密通信,这就是 ssl 认证 。

2、kubernetes 账号

客户端对apiserver 发起请求, apiserver 要识别这个用户是否有请求的权限,要识别用户本身能否通过 apiserver 执行相应的操作,那么需要哪些信息才能识别用户信息来完成对用户的相关的访问控制呢?

kubectl explain pods.spec可以看到有一个字 段 serviceAccountName (服务账号名称),这个就是我们 pod 连接 apiserver 时使用的账号 因此整个 kubernetes 集群中的账号有两类,ServiceAccount (服务账号) User account (用户账号)

Useraccount :实实在在现实中的人,人可以登陆的账号,客户端想要对 apiserver 发起请求,apiserver 要识别这个客户端是否有请求的权限,那么不同的用户就会有不同的权限,靠用户账号表示,叫做 username

ServiceAccount:方便 Pod 里面的进程调用 Kubernetes API 或其他外部服务而设计的,是kubernetes 中的一种资源

sa账号:登陆 dashboard 使用的账号

user account:这个是登陆 k8s 物理机器的用户

(1)ServiceAccount

Service account 是为了方便 Pod 里面的进程调用 Kubernetes API 或其他外部服务而设计的。它与 User account 不同 User account 是为人设计的,而 service account 则是为 Pod 中的进程调用 Kubernetes API 而设计; User account 是跨 namespace 的,而 service account 则是仅局限它所在的 namespace ;每个 namespace 都会自动创建一个 default service account开启ServiceAccount Adm ission Controller 后

  • 每个 Pod 在创建后都会自动设置 spec.serviceAccount 为 default (除非指定了其他ServiceAccout)

  • 验证 Pod 引用的 service account 已经存在,否则拒绝创建;

当创建pod 的时候,如果没有指定一个 serviceaccount ,系统会自动在与该 pod 相同的namespace 下为其指派一个 default service account 。 这是 pod 和 apiserver 之间进行通信的账号,如下:

image-20211029140456805

image-20211029140610376

image-20211029140812577

 

从上面可以看到每个Pod 无论定义与否都会有个存储卷,这个存储卷为 default-token-*** 。 pod和 apiserver 的认证信息 通过 secret 进行定义,由于认证信息属于敏感信息,所以需要保存在secret 资源当中,并以存储卷的方式挂载到 Pod 当中。从而让 Pod 内运行的应用通过对应的secret 中的信息来连接 apiserver ,并完 成认证。每个 namespace 中都有一个默认的叫做default 的 serviceaccount 资源。查看名称空间内的 secret ,也可以看到对应的 default-token 。让当前名称空间中所有的 pod 在连接 apiserver 时可以使用的预制认证信息,从而保证pod 之间的通信。

image-20211029140935984

image-20211029141015044

默认的service account 仅仅只能获取当前 Pod 自身的相关属性,无法观察到其他名称空间 Pod的相关属性信息 。如果想要扩展 Pod ,假设有一个 Pod 需要用于管理其他 Pod 或者是其他资源对象,是无法通过自身的名称空间的 serviceaccount 进行获取其他 Pod 的相关属性信息的,此时就需要进行手动创建一个 serviceaccount ,并在创建 Pod 时进行定义。那么 serviceaccount 该如何进行定义呢?

实际上, service accout 也属于一个 k8s 资源, serviceAccount 也属于标准的k8s 资源,可以创建一个 serviceAccount ,创建之后由我们创建的 pod 使用serviceAccount Name 去加载自己定义的 serviceAccount 就可以了,如下

创建一个 serviceaccount

kubectl create serviceaccount test

image-20211029141330470

可以看到已经创建了test 的 serviceacount

# 查看 test 这个账号的详细信息
kubectl describe sa test

image-20211029141341202

上面可以看到生成了一个test-token-jw48z 的 secret 和 test-token-jw48z 的 token

image-20211029141501484

# 查看 test-token-jw48z 这个秘钥的详细信息

kubectl describe secret test-token-jw48z

image-20211029141607740

上面可以看到生成了test-token-jw48z 的 token 详细信息,这个 token 就是 sa 连接 apiserver的 认证信息 ,这个 token 也是 登陆 k8s dashboard 的 token ,这些是一个认证信息,能够登陆k8s ,能认证到 k8s 但是不能做别的事情,不代表权限,想要做其他事情,需要授权

(2)User account(kubeconfig 文件)

创建账号

#  创建证书
mkdir -p /usr/local/kubernetes/TLS/user && cd /usr/local/kubernetes/TLS/user

cat <<EOF> /usr/local/kubernetes/TLS/user/mywei.json
{
 "CN": "system:mywei",
 "hosts": [],
 "key": {
   "algo": "rsa",
   "size": 2048
},
 "names": [
  {
     "C": "CN",
     "L": "BeiJing",
     "ST": "BeiJing",
      "O": "k8s",
     "OU": "System"
  }
]
}
EOF

cfssl gencert -ca=../k8s/ca.pem -ca-key=../k8s/ca-key.pem -config=../k8s/ca-config.json -profile=kubernetes mywei.json | cfssljson -bare mywei

image-20211029150226399

# 设置集群、用户、上下文信息

kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=../k8s/ca.pem --server=https://192.168.5.3:6443

kubectl config set-credentials mywei --embed-certs=true --client-certificate=mywei.pem --client-key=mywei-key.pem

kubectl config set-context mywei --cluster=kubernetes --user=mywei
# 查看当前用户
kubectl config get-contexts

image-20211029154821113

# 切换账户到devman
kubectl config use-context mywei

image-20211029154905410

# 删除用户
kubectl config delete-context mywei && rm -rf /root/.kube/config

2)授权

如果用户通过认证,什么权限都没有,需要一些后续的授权操作,如对资源的增删该查等,

kubernetes1.6 之后开始有 RBAC (基于角色的访问控制机制)授权检查机制 。

Kubernetes 的授权是基于插件 形成 的,其常用的授权插件有以下几种:

  • Node (节点认证)

  • ABAC( 基于属性的访问控制)

  • RBAC (基于角色的访问控制)

  • Webhook (基于 http 回调机制的访问控制)

什么是RBAC (基于角色的访问控制)

让一个用户( Users )扮演一个角色 (Role ),角色拥有权限,从而让用户拥有这样的权限,随后在 授权机制当中,只需要将权限授予某个角色,此时用户将获取对应角色的权限,从而实现角色的访问控制。如图:

image-20211029155410016

在k8s 的授权机制当中,采用 RBAC 的方式进行授权,其工作逻辑是,把对对象的操作权限定义到一个角色当中,再将用户绑定到该角色,从而使用户得到对应角色的权限。如果通过 rolebinding绑定 role ,只能对rolebingding 所在的名称空间的资源有权限,上图 user1 这个用户绑定到role1 上,只对 role1 这个名称空间的资源有权限,对其他名称空间资源没有权限,属于名称空间级别的;

另外,k8s 为此还有一种集群级别的授权机制,就是定义一个集群角色( ClusterRole ),对集群内的所有资源都有可操作的权限,从而将 User2 通过 ClusterRoleBinding 到 ClusterRole ,从而使User2 拥有集群的操作权限。

Role、 RoleBinding 、 ClusterRole 和 ClusterRoleBinding 的关系如下图:

image-20211029155500728

通过上图可以看到,可以通过rolebinding 绑定 role r olebinding 绑定 clusterrole clusterrolebinding 绑定 clusterrole 。

  • 用户通过 rolebinding 绑定 role

  • 用户通过 clusterrolebinding 绑定 clusterrole

  • rolebinding 绑定 clusterrole

rolebinding绑定 clusterrole 的好处:

假如有6 个名称空间,每个名称空间的用户都需要对自己的名称空间有管理员权限,那么需要定义 6个 role 和 rolebinding ,然后依次绑定,如果名称空间更多,我们需要定义更多的 role ,这个是很麻烦的,所以我们引入 clusterrole ,定义一个 clusterrole ,对 clusterrole 授予所有权限,然后用户通过 rolebinding 绑定到 clusterrole ,就会拥有自己名称空间的管理员权限了

注:RoleBinding 仅仅对当前名称空间有对应的权限。

3)准入控制

一般而言,准入控制只是用来定义我们授权检查完成之后的后续的其他安全检查操作的,进一步补充了授权机制,由多个插件组合实行,一般而言在创建,删除,修改或者做代理时做补充;

Kubernetes的 Admission Control 实际上是一个准入控制器 (Admission 插件列表,发送到 APIServer 的请求都需要经过这个列表中的每个准入控制器插件的检查,如果某一个控制器插件准入失败,就准入失败。

控制器插件如下:

控制器控制器描述
AlwaysAdmit 允许所有请求通过
AlwaysPullImages 在启动容器之前总是去下载镜像,相当于每当容器启动前做一次用于是否有权 使用该容器镜像的检查
AlwaysDeny 禁止所有请求通过,用于测试
DenyEscalatingExec 拒绝 exec 和 attach 命令到有升级特权的 Pod 的终端用户访问。如果集中 包含升级特权的容器,而要限制终端用户在这些容器中执行命令的能力,推荐使用此插件ImagePolicyWebhook
ServiceAccount 这个插件实现了 serviceAccounts 等等自动化,如果使用 ServiceAccount 对 象,强烈推荐使用这个插件
SecurityContextDeny 将 Pod 定义中定义了的 SecurityContext 选项全部失效。 SecurityContext 包含在容器中定义了操作系统级别的安全选型如 fsGroup selinux 等选项
ResourceQuota 用于 namespace 上的配额管理,它会观察进入的请求,确保在 namespace 上 的配额不超标。推荐将这个插件放到准入 控制器列表的最后一个。 ResourceQuota 准入控制器既可 以限制某个 namespace 中创建资源的数量,又可以限制某个 namespace 中被 Pod 请求的资源总 量。 ResourceQuota 准入控制器和 ResourceQuota 资源对象一起可以实现资源配额管理。
LimitRanger 用于 Pod 和容器上的配额管理,它会观察进入的请求,确保 Pod 和容器上的配额不 会超标。准入控制器 LimitRanger 和资源对象 LimitRange 一起实现资源限制管理
NamespaceLifecycle 当一个请求是在一 个不存在的 namespace 下创建资源对象时,该请求会 被拒绝。当删除一个 namespace 时,将会删除该 namespace 下的所有资源对象

当Kubernetes 版本 >=1.6.0 ,官方建议使用这些插件

-admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,Def au
ltStorageClass,ResourceQuota,DefaultTolerationSeconds

当 Kubernetes 版本 >=1.4.0 ,官方建议使用这些插件

-admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,Resourc
eQuota

以上是标准的准入插件,如果是自己定制的话, k8s1.7 版 出了两个 alpha features, Initializers和 Exte rnal Admission Webhooks

3.2 ServiceAccount 介绍

kubernetes 中账户区分为: User Accounts (用户账户 和 Service Accounts (服务账户)两种:

UserAccount是给 kubernetes 集群外部用户使用的,例如运维或者集群管理人员, kubeadm 安装的 k8s ,默认用户账号是 kubernetes-admin

APIServer 需要对客户端做认证,使用 kubeadm 安装的 K8s ,会在用户家目录下创建一个认证配置文件 .kube/config 这里面保存了客户端访问 API Server 的密钥相关信息,这样当用 kubectl访问 k8s 时,它就会自动读取该配置文件,向 API Server 发起认证,然后完成操作请求。

ServiceAccount是 P od 使用的账号 Pod 容器的进程需要访问 API Server 时用的就是ServiceAccount 账户; ServiceAccount 仅局限它所在的 namespace ,每个 namespace 创建时都会自动创建一个 default service account ;创建 Pod 时,如果没有指定 Service Account Pod 则会使用 default Service Account 。

3.3 RBAC 认证授权策略

RBAC介绍

在Kubernetes 中,所有资源对象都是通过 API 进行操作,他们保存在 etcd 里。而对 etcd 的操作我们需要通过访问 kube api server 来实现,上面的 Service Account 其实就是 APIServer 的认证过程,而授权的机制是通过 RBAC :基于角色的访问控制实现。

RBAC有四个资源对象,分别是 Role、ClusterRole、RoleBinding、ClusterRoleBinding

1)Role:角色

一组权限的集合,在一个命名空间中,可以用其来定义一个角色,只能对命名空间内的资源进行授权。如果是集群级别的资源,则需要使用 ClusterRole 。例如:定义一个角色用来读取 Pod 的权限

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: rbac
name: pod-read
rules:
-apiGroups: [""]
resources: ["pods"]
resourceNames: [
  verbs: ["get","watch","list"]

rules中的参数说明:

  • apiGroups :支持的 API 组列表,例如: :"apiVersion: batch/ 等

  • resources :支持的资源对象列表,例如 pods 、 deplayments 、 jobs 等

  • resourceNames: 指定 resource 的名称

  • verbs :对资源对象的操作方法列表。

2)ClusterRole:集群角色

具有和角色一致的命名空间资源的管理能力,还可用于以下特殊元素的授权

  • 集群范围的资源,例如 Node

  • 非资源型的路径,例如:/healthz

  • 包含全部命名空间的资源,例如 Pods

例如:定义一个集群角色可让用户访问任意secrets

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secrets-clusterrole
rules:
-apiGroups: [""]
resources: ["secrets"]
verbs: ["get","watch","list"]

3)RoleBinding:角色绑定

角色绑定和集群角色绑定用于把一个角色绑定在一个目标上,可以是User,Group,ServiceAccount ,使用 RoleBinding 为某个命名空间授权,使用 ClusterRoleBinding 为集群范围内授权。

例如:将在rbac 命名空间中把 pod-read 角色授予用户 es

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-read-bind
namespace: rbac
subjects:
- kind: User
name: es
apiGroup: rbac.authorization.k8s.io
roleRef:
- kind: Role
name: pod-read
apiGroup: rbac.authorizatioin.k8s.io

RoleBinding也可以引用 ClusterRole ,对属于同一命名空间内的 ClusterRole 定义的资源主体进行授权.

例如: es 能获取到集群中所有的资源信息

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: es-allresource
namespace: rbac
subjects:
- kind: User
name: es
apiGroup: rbac.authorization.k8s.io
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin

4)ClusterRolebinding :集群角色绑定

集群角色绑定的角色只能是集群角色,用于进行集群级别或对所有命名空间都生效的授权

例如:允许manager 组的用户读取所有 namaspace 的 secrets

apiVersion: rabc.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-secret-global
subjects:
-kind: Group
name: manager
apiGroup: rabc.authorization.k8s.io
ruleRef:
-kind: ClusterRole
name: secret read
apiGroup: rabc.authorization.k8s.io

3.4 资源的引用方式

多数资源可以用其名称的字符串表示,也就是Endpoint 中的 URL 相对路径,例如 pod 中的日志是 GET /api/v1/namaspaces/{namespace}/pods/{podname}/log

如果需要在一个RBAC 对象中体现上下级资源,就需要使用 “//”分割资源和下级资源。

例如:若想授权让某个主体同时能够读取 Pod 和 Pod log ,则可以配置 resources 为一个数组

apiVersion: rabc.authorization.k8s.io/v1
kind: Role
metadata:
name: logs-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["pods","pods/log"]
verbs: ["get","list"]

资源还可以通过名称(ResourceName )进行引用,在指定 ResourceName 后,使用 get 、delete 、 update 、 patch 请求,就会被限制在这个资源实例范围内

例如,下面的声明让一个主体只能对名为my configmap 的 Con f igmap 进行 get 和 update 操作:

apiVersion: rabc.authorization.k8s.io/v1
kind: Role
metadata:
namaspace: default
name: configmap-update
rules:
-apiGroups: [""]
resources: ["configmap"]
resourceNames: ["my configmap"]
verbs: ["get","update"]

3.5 常见角色示例

1 )允许读取核心 API 组的 Pod 资源:

rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"]

2 )允许读写 extensions 和 apps 两个 API 组中的 deploym ent 资源:

rules:
- apiGroups: ["extensions ","apps"]
resources: ["deployments"]
verbs: ["get","list","watch","create","update","patch","delete"]

3 )允许读取 Pod 以及读写 job 信息:

rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","watch"] 、
- apiVersion: ["batch","extensions"]
resources: ["jobs"]
verbs: ["get","list","watch","create","update","patch","delete"]

4 )允许读取一个名为 my-config 的 ConfigMap (必须绑定到一个 RoleBinding 来限制到一个 Namespace 下的 ConfigMap:

rules:
- apiGroups :
resources: ["configmap"]
resourceNames: ["my-configmap"]
verbs: ["get"]

5 )读取核心组的 Node 资源( Node 属于集群级的资源,所以必须存在于 ClusterRole 中,并使 用 ClusterRoleBinding 进行绑定):

rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get","list","watch"]

6 )允许对非资源端点 healthzhealthz”及其所有子路径进行 GET 和 POST 操作(必须使用 ClusterRole 和 ClusterRoleBinding:

rules:
- nonResourceURLs: ["/healthz","/healthz/*"]
verbs: ["get","post"]

3.6 常见的角色绑定示例

1)用户名 alice

subjects:
- kind: User
name: alice
apiGroup: rbac.authorization.k8s.io

2)组名 alice

subjects:
- kind: Group
name: alice
apiGroup: rbac.authorization.k8s.io

3)kube system 命名空间中默认 Service Account

subjects:
- kind: ServiceAccount
name: default
namespace: kube-system

4)qa 命名空间中的所有 Service Account

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

5)所有 Service Account

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

6)所有认证用户

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

7)所有未认证用户

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

8)全部用户

subjects:
- kind: Group
name: system:authenticated
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: system:unauthenticated
apiGroup: rbac.authorization.k8s.io

3.7 对 Service Account 的授权管理

ServiceAccount 也是一种账号,是给运行在 Pod 里的进程提供了必要的身份证明。需要在 Pod定义中指明引用的 Service Account ,这样就可以对 Pod 的进行赋权操作。例如: pod 内可获取rbac 命名空间的所有 Pod 资源, pod reader sc 的 Service Account 是绑定了名为 pod read 的Role

apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: rbac
spec:
serviceAccountName: pod reader sc
containers:
- name: nginx
  image: nginx
  imagePullPolicy: IfNotPresent
  ports:
  - containerPort: 80

默认的RBAC 策略为控制平台组件、节点和控制器授予有限范围的权限,但是除 kube system 外的 Service Account 是没有任何权限的。 1 )为一个应用专属的 Service Account 赋权

此应用需要在Pod 的 spec 中指定一个 serviceAccountName ,用于 API、ApplicationManifest、kubectl create serviceaccount 等创建 Service Account 的命令。

例如为my-namespace 中的 my-sa Service Account 授予只读权限

kubectl create rolebinding my-sa-view --clusterrole=view --serviceaccount=my-namespace:my-sa --namespace=my-namespace

2 )为一个命名空间中名为 default 的 Service Account 授权

如果一个应用没有指定serviceAccountName ,则会使用名为 default 的 Service Account 。注意,赋予 Service Account default ”的权限会让所有没有指定 serviceAccountName 的 Pod都具有这些权限

例如,在my-namespace 命名空间中为 Service Account “default” 授予只读权限

kubectl create rolebinding default-view --clusterrole=view --serviceaccount=my-namespace:default --namespace=my-namespace

另外,许多系统级Add Ons 都需要在 kube system 命名空间中运行,要让这些 Add Ons 能够使用超级用户权限,则可以把 cluster admin 权限赋予 kube system 命名空间中名为 default 的Service Account ,这一操作意味着 kube system 命名空间包含了 通向 API超级用户的捷径。

kubectl create clusterrolebinding add-ons-add-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default

3 )为命名空间中所有 Service Account 都授予一个角色

如果希望在一个命名空间中,任何Service Account 应用都具有一个角色,则可以为这一命名空间的 Service Account 群组进行授权

kubectl create rolebinding serviceaccounts-view --clusterrole=view --group=system:serviceaccounts:my-namespace --namespace=my-namespace

4 )为集群范围内所有 Service Account 都授予一个低权限角色

如果不想为每个命名空间管理授权,则可以把一个集群级别的角色赋给所有Service Account 。

kubectl create clusterrolebinding serviceaccounts-view --clusterrole=view --group=system:serviceaccounts

5 )为所有 Service Account 授予超级用户权限

kubectl create clusterrolebinding serviceaccounts-view --clusterrole=cluster-admin
--group=system:serviceaccounts

3.8 使用 kubectl 命令行工具创建资源对象

1)在命名空间 rbac 中为用户 es 授权 admin ClusterRole:

kubectl create rolebinding bob-admin-binding --clusterrole=admin --user=es --namespace=rbac

2)在命名空间 rbac 中为名为 myapp 的 Service Account 授予 view ClusterRole:

kubctl create rolebinding myapp-role-binding --clusterrole=view --serviceaccount=rbac:myapp --namespace=rbac

3)在全集群范围内为用户 root 授予 cluster-admin ClusterRole:

kubectl create clusterrolebinding cluster-binding --clusterrole=cluster-admin --user=root

4)在全集群范围内为名为 myapp 的 Service Account 授予 view ClusterRole:

kubectl create clusterrolebinding service-account-binding --clusterrole=view --serviceaccount=myapp

yaml 文件进行 rbac 授权: https://kubernetes.io/zh/docs/reference/access-authn-authz/rbac/

3.9 限制不同的用户操作 k8s 集群

1)创建角色

cat <<EOF> rbac-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: dev
name: test-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","watch","list"]
EOF

kubectl apply -f rbac-role.yaml
kubectl get role -n dev

image-20211101123336059

2)绑定用户

cat <<EOF> rbac-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-rolebinding
namespace: dev
roleRef:
kind: Role
name: test-role
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: User
name: mywei
apiGroup: rbac.authorization.k8s.io
EOF

kubectl apply -f rbac-rolebinding.yaml
kubectl get rolebinding -n dev

image-20211101124310931

3)创建证书

mkdir -p /usr/local/kubernetes/TLS/user && cd /usr/local/kubernetes/TLS/user

cat <<EOF> /usr/local/kubernetes/TLS/user/mywei.json
{
 "CN": "mywei",
 "hosts": [],
 "key": {
   "algo": "rsa",
   "size": 2048
},
 "names": [
  {
     "C": "CN",
     "L": "BeiJing",
     "ST": "BeiJing",
  }
]
}
EOF

cfssl gencert -ca=../k8s/ca.pem -ca-key=../k8s/ca-key.pem -config=../k8s/ca-config.json -profile=kubernetes mywei.json | cfssljson -bare mywei

4)设置集群、用户、上下文信息

kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=../k8s/ca.pem --server=https://192.168.5.3:6443 --kubeconfig=mywei.kubeconfig

kubectl config set-credentials mywei --embed-certs=true --client-certificate=mywei.pem --client-key=mywei-key.pem --kubeconfig=mywei.kubeconfig

kubectl config set-context mywei --cluster=kubernetes  --user=mywei --kubeconfig=mywei.kubeconfig

5)移动config文件

cp mywei.kubeconfig /root/.kube/config

6)查看当前用户

# 查看当前用户
kubectl config get-contexts

image-20211101130112840

7)切换账户到mywei

kubectl config use-context mywei

# 如果想要切换会管理员用户,只需要删除/root/.kube/config该文件

image-20211101130126541

8)查看权限

kubectl get pods -n dev

 

posted @ 2021-09-15 16:22  孤独的小人物  阅读(482)  评论(0编辑  收藏  举报