对于一个系统来说,认证和授权不可或缺的部分,最常见的方式要数账号密码,管理员和普通用户这种认证方式,也就是常说的ABAC。但是每次修改权限都需要重启,或者修改记录,会有些不方便,于是基于角色的访问控制–RBAC就出现了,同时k8s分离了认证,授权和准入的过程,方便第三方开发相关插件。
下图大致描述了k8s认证的流程图,描述了一个请求在经过APIServer的时候都经历了哪些鉴权的过程。如下图所示:需要访问API的有人类,也就是Ops,通过kubectl以及Kubeconfig配置文件和API-Server交互。还有就是Pod,也就是应用,对API资源进行CURD。然后依次经过了身份认证(authentication)、授权(authorization)和准入控制(admission control)。下面就来详细介绍下认证和授权
认证
- Authentication:即身份验证,这个环节它面对的输入是整个http request,它负责对来自client的请求进行身份校验,支持的方法包括:
- client证书验证(https双向验证)
- basic auth
- 普通token
- jwt token(用于serviceaccount)
APIServer启动时,可以指定一种Authentication方法,也可以指定多种方法。如果指定了多种方法,那么APIServer将会逐个使用这些方法对客户端请求进行验证,只要请求数据通过其中一种方法的验证,APIServer就会认为Authentication成功;在较新版本kubeadm引导启动的k8s集群的apiserver初始配置中,默认支持client证书验证和serviceaccount两种身份验证方式。在这个环节,apiserver会通过client证书或http header中的字段(比如serviceaccount的jwt token)来识别出请求的“用户身份”,包括”user”、”group”等,这些信息将在后面的authorization环节用到。
Client 证书
首先我们看一下kubectl的默认配置文件~/.kube/config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: REDACTED
server: https://172.16.66.101: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
这有两个重要的信息 client-certificate-data, client-key-data,首先把data提取出来
# 生成client-certificate-data
grep 'client-certificate-data' ~/.kube/config | head -n 1 | awk '{print $2}' | base64 -d >> kubecfg.crt
# 生成client-key-data
grep 'client-key-data' ~/.kube/config | head -n 1 | awk '{print $2}' | base64 -d >> kubecfg.key
openssl x509 -noout -text -in kubecfg.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 6675913985209031083 (0x5ca59c66277259ab)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=kubernetes
Validity
Not Before: Apr 13 10:22:37 2019 GMT
Not After : Apr 12 10:22:38 2020 GMT
Subject: O=system:masters, CN=kubernetes-admin #此证书是签发给system:masters的,
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
.....
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Client Authentication # 此证书可以作为TLS的客户端证书
Signature Algorithm: sha256WithRSAEncryption
为什么是这个用户呢?在集群中可以看到这样一条记录,k8s默认把system:masters用户绑定上了clsuter-admin的角色,也就是整个集群的管理员,所以当我们有了这个客户端证书之后,就可以管理集群的任何资源。
kubectl -n kube-system describe clusterrolebindings cluster-admin
Name: cluster-admin
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate=true
Role:
Kind: ClusterRole
Name: cluster-admin
Subjects:
Kind Name Namespace
下面我们来手动访问下API Server:
MASTER=192.168.1.1
# 因为是自签名证书 用-k 忽略证书校验
# 默认的request是system:anonymous用户 没有权限访问
curl -k https://$MASTER:6443/api
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/api\"",
"reason": "Forbidden",
"details": {
},
"code": 403
}
# 使用客户端证书进行认证
curl -v --cacert /etc/kubernetes/pki/ca.crt --key ./kubecfg.key --cert ./kubecfg.crt https://$MASTER:6443/api
# 同理访问kubelet的metrics接口
curl -k --cacert /etc/kubernetes/pki/ca.crt --cert /etc/kubernetes/pki/apiserver-kubelet-client.crt --key /etc/kubernetes/pki/apiserver-kubelet-client.key https://127.0.0.1:10250/metrics
# 也可以生成另一类p12证书
openssl pkcs12 -export -clcerts -inkey kubecfg.key -in kubecfg.crt -out kubecfg.p12 -name "kubernetes-client"
Basic Auth
API有一个启动参数–basic-auth-file,可以指定一个csv格式的文件作为Basic Auth
cat <<EOF > basicauth.csv
admin,admin,1,"demo"
EOF
cat <<EOF > kubectl apply -f -
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: ui-admin
rules:
- apiGroups:
- ""
resources:
- services
- services/proxy
verbs:
- '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ui-admin-binding
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ui-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: admin
EOF
Service Account
当创建一个Service Account会生成一个token,通过kubectl -n kube-system describe secrets ${Service account}
可以看到一个以eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9
开头的Token。可以在jwt.io上面解码一下,得到的结果如下所示:APIServer也就是通过这些字段进行鉴权的。
{
"iss": "kubernetes/serviceaccount",
"kubernetes.io/serviceaccount/namespace": "default",
"kubernetes.io/serviceaccount/secret.name": "default-token-ph2f5",
"kubernetes.io/serviceaccount/service-account.name": "default",
"kubernetes.io/serviceaccount/service-account.uid": "7ce56043-7dcc-11e9-9925-00163e132347",
"sub": "system:serviceaccount:default:default"
}
# 手动使用Token认证一下
TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d '\t')
MASTER=10.96.0.1
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -k -H "Authorization: Bearer $TOKEN" https://$MASTER:6443/api
授权
Authorization:授权。这个环节面对的输入是http request context中的各种属性,包括:user、group、request path(比如:/api/v1、/healthz、/version等)、request verb(比如:get、list、create等)。APIServer会将这些属性值与事先配置好的访问策略(access policy)相比较。APIServer支持多种authorization mode,包括Node、RBAC、Webhook等。
APIServer启动时,可以指定一种authorization mode,也可以指定多种authorization mode,如果是后者,只要Request通过了其中一种mode的授权,那么该环节的最终结果就是授权成功。在较新版本kubeadm引导启动的k8s集群的apiserver初始配置中,authorization-mode的默认配置是”Node,RBAC”。Node授权器主要用于各个node上的kubelet访问apiserver时使用的,其他一般均由RBAC授权器来授权。
RBAC实战
k8s 大约有以下几种角色
- role 和 clusterrole 规定了权限的内容,也就是某个人或者角色能干什么
- Service account 也就是具体的角色或者账户
- rolebinding 和 clusterrolebinding 就是将两者结合在一起,规定什么人有什么样的权限
下面我们来看一下例子
---
# ------------------- ClusterRole ------------------- #
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
---
# ------------------- ClusterRoleBinding ------------------- #
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: kube-system
---
# ------------------- ServiceAccount ------------------- #
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: kube-system
Ref
Kubernetes集群的安全配置
https://tonybai.com/2016/11/25/the-security-settings-for-kubernetes-cluster/
Kubernetes RBAC 详解 https://blog.qikqiak.com/post/use-rbac-in-k8s/
使用 RBAC 控制 kubectl 权限
https://mritd.me/2018/03/20/use-rbac-to-control-kubectl-permissions/