k8s-3.1 认证授权

172 阅读6分钟

认证主体

User

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

[root@k8s-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

实战

生成证书
# (umask 077;openssl genrsa -out magedu.key 2048)
使用ca.crt进行签署
#openssl req -new -key magedu.key -out magedu.csr -subj "/CN=magedu"  #证书签署请求
# openssl x509 -req -in magedu.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out magedu.crt -days 365  #证书签署
添加到用户认证
# kubectl config set-credentials magedu --client-certificate=./magedu.crt --client-key=./magedu.key --embed-certs=true
# kubectl config set-context magedu@kubernetes --cluster=kubernetes --user=magedu
# kubectl config use-context magedu@kubernetes

service account

Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。它与User account不同

  • User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;

  • User account是跨namespace的,而service account则是仅局限它所在的namespace;

  • 每个namespace都会自动创建一个default service account

  • Token controller检测service account的创建,并为它们创建secret

  • 开启ServiceAccount Admission Controller后

    • 每个Pod在创建后都会自动设置spec.serviceAccount为default(除非指定了其他ServiceAccout)
    • 验证Pod引用的service account已经存在,否则拒绝创建
    • 如果Pod没有指定ImagePullSecrets,则把service account的ImagePullSecrets加到Pod中
    • 每个container启动后都会挂载该service account的token和ca.crt到/var/run/secrets/kubernetes.io/serviceaccount/

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

    每个 namespace 中都有一个默认的叫做 default 的 service account 资源。进行查看名称空间内的secret,也可以看到对应的default-token。让当前名称空间中所有的pod在连接apiserver时可以使用的预制认证信息,从而保证pod之间的通信。而默认的service account 仅仅只能获取当前Pod自身的相关属性,无法观察到其他名称空间Pod的相关属性信息。

    如果想要扩展Pod,假设有一个Pod需要用于管理其他Pod或者是其他资源对象,是无法通过自身的名称空间的serviceaccount进行获取其他Pod的相关属性信息的,需要赋予sa权限,或者进行手动创建一个serviceaccount,并在创建Pod时进行定义。如下:

$ kubectl get po -n model-deployment kuai-online-69b87775dc-x6cdn -o yaml |grep serviceAccountName
  serviceAccountName: default
$ kubectl get po -n model-deployment kuai-online-69b87775dc-x6cdn -o yaml |grep secretName
  secretName: default-token-tsjrk

实战

kubectl create serviceaccount mysa -o yaml --dry-run > serviceaccount.yaml 
#看到有一个 token 已经被自动创建,并被 service account 引用。设置非默认的 service account,只需要在 pod 的spec.serviceAccountName 字段中将name设置为您想要用的 service account 名字即可。
kubectl apply -f serviceaccount.yaml 

使用sa避免设置imagePullSecrets

kubectl --namespace kube-system \ create secret docker-registry regcred \ --docker-server=<your-registry-server> \ --docker-username=<your-name> \ --docker-password=<your-pword> \ --docker-email=<your-email>
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "regcred"}]}'

角色认证

  • 一个Role对象只能用于授予对某一单一命名空间中资源的访问权限

  • RoleBinding可以引用在同一命名空间内定义的Role对象。

  • ClusterRole对象可以授予与Role对象相同的权限,但由于它们属于集群范围对象, 也可以使用它们授予对以下几种资源的访问权限:集群范围资源(例如节点,即node)非资源类型endpoint(例如”/healthz”)跨所有命名空间的命名空间范围资源(例如pod,需要运行命令kubectl get pods --all-namespaces来查询集群中所有的pod)

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

    RoleBinding对象也可以引用一个ClusterRole对象用于在RoleBinding所在的命名空间内授予用户对所引用的ClusterRole中 定义的命名空间资源的访问权限。这一点允许管理员在整个集群范围内首先定义一组通用的角色,然后再在不同的命名空间中复用这些角色。

默认角色与角色绑定

API Server会创建一组默认的ClusterRole和ClusterRoleBinding对象。 这些默认对象中有许多包含system:前缀,表明这些资源由Kubernetes基础组件”拥有”。 对这些资源的修改可能导致非功能性集群(non-functional cluster)。一个例子是system:node ClusterRole对象。 这个角色定义了kubelets的权限。如果这个角色被修改,可能会导致kubelets无法正常工作。所有默认的ClusterRole和ClusterRoleBinding对象都会被标记为kubernetes.io/bootstrapping=rbac-defaults。 系统默认查看

实战user->rolebinding->role

用户具有当前namespace的权限

# 使用kubectl create进行创建角色,指定角色名称,--verb指定权限,--resource指定资源或者资源组,--dry-run单跑模式并不会创建
kubectl create role pods-reader --verb=get,list,watch --resource=pods --dry-run -o yaml #干跑模式查看role的定义

# 使用kubectl create进行创建角色绑定,指定角色绑定的名称,--role|--clusterrole指定绑定哪个角色,--user指定哪个用户
kubectl create rolebinding magedu-read-pods --role=pods-reader --user=magedu --dry-run -o yaml > rolebinding-demo.yaml
kubectl config use-context magedu@kubernetes #切换magedu这个用户,并使用get获取pods资源信息

实战user->clusterrolebinding->clusterrole

用户具有整个集群的权限

kubectl create clusterrole cluster-read --verb=get,list,watch --resource=pods -o yaml > clusterrole-demo.yaml
kubectl create clusterrolebinding magedu-read-all-pods --clusterrole=cluster-read --user=magedu --dry-run -o yaml > clusterrolebinding-demo.yaml

实战user->rolebinding->clusterrole

用户具有当前namespace的权限,但不需要在当前namespace创建role

kubectl create rolebinding magedu-read-pods --clusterrole=cluster-read --user=magedu --dry-run -o yaml > rolebinding-clusterrole-demo.yaml
kubectl auth can-i create deployments --namespace dev

kubectl 认证

# your server name goes here
server=https://localhost:8443
# the name of the secret containing the service account token goes here
name=default-token-sg96k

ca=$(kubectl get secret/$name -o jsonpath='{.data.ca\.crt}')
token=$(kubectl get secret/$name -o jsonpath='{.data.token}' | base64 --decode)
namespace=$(kubectl get secret/$name -o jsonpath='{.data.namespace}' | base64 --decode)

echo "
apiVersion: v1
kind: Config
clusters:
- name: default-cluster
  cluster:
    certificate-authority-data: ${ca}
    server: ${server}
contexts:
- name: default-context
  context:
    cluster: default-cluster
    namespace: default
    user: default-user
current-context: default-context
users:
- name: default-user
  user:
    token: ${token}
" > sa.kubeconfig