k8s安全认证-service account
1 k8s的认证:
API Server作为Kubernetes网关,是访问和管理资源对象的唯一入口,其各种集群组件访问资源都需要经过网关才能进行正常访问和管理。每一次的访问请求都需要进行合法性的检验,其中包括身份验证、操作权限验证以及操作规范验证等,需要通过一系列验证通过之后才能访问或者存储数据到etcd当中
与API server通信的客户端大致有两类:
1.集群客户端工具(kubectl、kubeadm、kubelet等)
2.集群内pod.
1.1 客户端访问k8sAPI时的过程:
第一步:对客户端访问进行认证操作,确认是否具有访问k8s权限
token(共享秘钥)
SSL(双向SSL认证)
....通过任何一个认证即表示认证通过,进入下一步
第二步:授权检查,确认是否对资源具有相关的权限
ABAC(基于属性的访问控制)
RBAC(基于角色的访问控制)
NODE(基于节点的访问控制)
WEB HOOK(自定义HTTP回调方法的访问控制)
第三步:准入控制(对操作资源相关联的其他资源是否有权限操作)
1.2 Kubernetes只对以下的API请求属性进行检查:
user - username,uid
group - user group
"extra"- 额外信息
API - API资源的对象
Request path - 请求资源的路径(k8s使用resultful风格接口的API)
http://Node_IPaddr:6443/apis/apps/v1/namespaces/namespaces_name/resource_name/
HTTP 请求动作 - HTTP verbs get,post,put,和delete用于非资源请求
HTTP 请求动作映射到 API资源操作- get,list,create,update,patch,watch,proxy,redirect,delete,和deletecollection用于请求resource
Resource -被访问(仅用于resource 请求)的resource 的ID或名字- *对于使用resource 的请求get,update,patch,和delete,必须提供resource 名称。
Subresource - 正在访问的subresource (仅用于请求resource )
Namespace - 正在访问对象的命名空间(仅针对命名空间的请求资源)
API group - 正在访问的API组(仅用于请求资源)。空字符串指定核心API组。
1.3 什么是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/
1.4 验证service account
当创建 pod 的时候,如果没有指定一个 service account,系统会自动在与该pod 相同的 namespace 下为其指派一个default service account。而pod和apiserver之间进行通信的账号,称为serviceAccountName。如下:
[root@k8s-master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-demo-b9997455b-5mxjm 1/1 Running 0 2d17h
[root@k8s-master ~]# kubectl get pod -o yaml| grep serviceAccount
serviceAccount: default
serviceAccountName: default
[root@k8s-master ~]# kubectl describe pods myapp-demo-b9997455b-5mxjm
……
Volumes:
mysql:
Type: Secret (a volume populated by a Secret)
SecretName: test
Optional: false
default-token-wldf4:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-wldf4
Optional: false
……..
从上面可以看到每个Pod无论定义与否都会有个存储卷,这个存储卷为default-token-*** token令牌,这就是pod和serviceaccount认证信息。通过secret进行定义,由于认证信息属于敏感信息,所以需要保存在secret资源当中,并以存储卷的方式挂载到Pod当中。从而让Pod内运行的应用通过对应的secret中的信息来连接apiserver,并完成认证。每个 namespace 中都有一个默认的叫做 default 的 service account 资源。进行查看名称空间内的secret,也可以看到对应的default-token。让当前名称空间中所有的pod在连接apiserver时可以使用的预制认证信息,从而保证pod之间的通信。
[root@k8s-master ~]# kubectl get secrets | grep service-account-token
default-token-wldf4 kubernetes.io/service-account-token 3 11d
nfs-client-provisioner-token-mz6dc kubernetes.io/service-account-token 3 3d20h
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl get sa
NAME SECRETS AGE
default 1 50d
[root@k8s-master ~]# kubectl get sa -n ingress-nginx #前期创建的ingress-nginx名称空间也存在这样的serviceaccount
NAME SECRETS AGE
default 1 11d
nginx-ingress-serviceaccount 1 11d
[root@k8s-master ~]# kubectl get secret
NAME TYPE DATA AGE
default-token-j5pf5 kubernetes.io/service-account-token 3 50d
mysecret Opaque 2 1d
tomcat-ingress-secret kubernetes.io/tls 2 10d
[root@k8s-master ~]# kubectl get secret -n ingress-nginx
NAME TYPE DATA AGE
default-token-zl49j kubernetes.io/service-account-token 3 11d
nginx-ingress-serviceaccount-token-mcsf4 kubernetes.io/service-account-token 3 11d
2 service account实例
2.1 创建service account
[root@k8s-master ~]# kubectl create serviceaccount admin
serviceaccount/admin created
[root@k8s-master ~]# kubectl get sa
NAME SECRETS AGE
admin 1 5s
default 1 11d
nfs-client-provisioner 1 3d20h
[root@k8s-master ~]# kubectl describe sa admin #查看名称为admin的sa的信息,系统会自动创建一个token信息
Name: admin
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: admin-token-bt2n9
Tokens: admin-token-bt2n9
Events: <none>
[root@k8s-master ~]# kubectl get secret #会自动创建一个secret(admin-token-rxtrc),用于当前sa连接至当前API server时使用的认证信息
NAME TYPE DATA AGE
admin-token-bt2n9 kubernetes.io/service-account-token 3 27s
db-user-pass Opaque 2 2d19h
default-token-wldf4 kubernetes.io/service-account-token 3 11d
myapp-ingress-secret kubernetes.io/tls 2 6d19h
myregistrykey kubernetes.io/dockerconfigjson 1 2d19h
mysecret Opaque 2 2d19h
nfs-client-provisioner-token-mz6dc kubernetes.io/service-account-token 3 3d20h
nginx-ingress-secret kubernetes.io/tls 2 6d19h
test Opaque 1 2d18h
tomcat-ingress-secret kubernetes.io/tls 2 6d20h
2.2 创建一个pod应用刚刚创建的sa
# cat myapp-deploy.yaml
apiVersion: v1
kind: Pod
metadata:
name: sa-demo
labels:
app: myapp
release: wx
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v2
ports:
- name: httpd
containerPort: 80
serviceAccountName: admin #此处指令为指定sa的名称
[root@k8s-master myapp]# kubectl create -f myapp-deploy.yaml
pod/sa-demo created
[root@k8s-master myapp]# kubectl get pod
NAME READY STATUS RESTARTS AGE
sa-demo 1/1 Running 0 8s
[root@k8s-master myapp]# kubectl describe pod sa-demo
….
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from admin-token-bt2n9 (ro)
Volumes:
admin-token-bt2n9:
Type: Secret (a volume populated by a Secret)
SecretName: admin-token-bt2n9
Optional: false
3 Kubeconfig证书认证
集群交互的时候少不了的是身份认证,使用 kubeconfig(即证书) 和 token 两种认证方式是最简单也最通用的认证方式,下面我使用kubeconfing来进行认证
使用kubeconfig文件来组织关于集群,用户,名称空间和身份验证机制的信息。使用 kubectl命令行工具对kubeconfig文件来查找选择群集并与群集的API服务器进行通信所需的信息。
默认情况下 kubectl使用的配置文件名称是在$HOME/.kube目录下 config文件,可以通过设置环境变量KUBECONFIG或者--kubeconfig指定其他的配置文件
3.1 系统的kubeconfig
# kubectl config view
apiVersion: v1
clusters: #集群列表
- cluster:
certificate-authority-data: REDACTED #认证集群的方式
server: https://172.16.150.212:6443 #访问服务的APIserver的路径
name: kubernetes #集群的名称
contexts: #上下文列表
- context:
cluster: kubernetes #访问kubernetes这个集群
user: kubernetes-admin #使用 kubernetes-admin账号
name: kubernetes-admin@kubernetes #给定一个名称
current-context: kubernetes-admin@kubernetes #当前上下文,表示使用哪个账号访问哪个集群
kind: Config
preferences: {}
users: #用户列表
- name: kubernetes-admin #用户名称
user:
client-certificate-data: REDACTED #客户端证书,用于与apiserver进行认证
client-key-data: REDACTED #客户端私钥
在上面的配置文件当中,定义了集群、上下文以及用户。其中Config也是K8S的标准资源之一,在该配置文件当中定义了一个集群列表,指定的集群可以有多个;用户列表也可以有多个,指明集群中的用户;而在上下文列表当中,是进行定义可以使用哪个用户对哪个集群进行访问,以及当前使用的上下文是什么。如图:定义了用户kubernetes-admin可以对kubernetes该集群的访问,用户kubernetes-user1对Clluster1集群的访问
3.2 自建证书和账号进行访问apiserver
#生成证书
[root@k8s-master pki]# (umask 077;openssl genrsa -out wx.key 2048)
Generating RSA private key, 2048 bit long modulus
..............................................................................................................................+++
.......................+++
e is 65537 (0x10001)
[root@k8s-master pki]#
#使用ca.crt进行签署
[root@k8s-master pki]# openssl req -new -key wx.key -out wx.csr -subj "/CN=wx" #是后面我们创建的用户名称,需要保持一致
[root@k8s-master pki]# ls wx.*
wx.csr wx.key
[root@k8s-master pki]# openssl x509 -req -in wx.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out wx.crt -days 365
Signature ok
subject=/CN=wx
Getting CA Private Key
[root@k8s-master pki]#
#创建一个当前集群用户
[root@k8s-master pki]# kubectl config set-credentials wx --client-certificate=./wx.crt --client-key=./wx.key --embed-certs=true
User "wx" set.
#为wx用户用户创建一个context
[root@k8s-master pki]# kubectl config set-context wx@kubernetes --cluster=kubernetes --user=wx
Context "wx@kubernetes" created.
[root@k8s-master pki]#
[root@k8s-master pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://10.6.76.25:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context:
cluster: kubernetes
user: wx
name: wx@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: wx
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
#切换serviceaccount
root@k8s-master pki]# kubectl config use-context wx@kubernetes
Switched to context "wx@kubernetes".
[root@k8s-master pki]#
[root@k8s-master pki]# kubectl get pod
Error from server (Forbidden): pods is forbidden: User "wx" cannot list resource "pods" in API group "" in the namespace "default"
[root@k8s-master pki]#
从上面的演示,当切换成wx用户进行访问集群时,由于该账户没有管理集群的权限,所以在获取pods资源信息时,会提示Forrbidde这就需要授权了,例如RBAC授权