通过用户认证和权限控制守护API服务器的安全
一、了解认证机制
发送到API服务器的请求会经过一个认证插件的列表,列表中的每个插件都可以检查这个请求和尝试确定谁在发送这个请求。列表中的第一个插件可以提取请求中客户端的用户名、用户ID和组信息,并返回给API服务器。API服务器会停止调用剩余的认证插件并继续进入授权阶段。插件可以使用下列方法获取客户端的身份认证:
客户端证书
传入在HTTP头中的认证token
基础的HTTP认证
其他
1.1 用户和组
用户:人、ServiceAccount
组:正常用户和ServiceAccount都可以属于一个或多个组,k8s的权限都是赋予组的,而不赋予用户
系统内置的一些组:
system:unauthenticated 组用于所有认证插件都不会认证客户端身份的请求。
system:authenticated 组会自动分配给一个成功通过认证的用户。
system:serviceaccounts 组包含所有在系统中的ServiceAccount。
system:serviceaccount 组包含了所有在特定命名空间中的ServiceAccount。
1.2 ServiceAccount
每个pod都会绑定一个ServiceAccount,它代表了运行在pod中应用程序的身份证明。
代表ServiceAccount的token存放在容器的/var/run/secrets/kubernetes.io/serviceaccount/token中的,pod发送请求时会带上这个token。这个文件通过加密卷(secret)挂载进每个容器的文件系统中。
ServiceAccount用户名的格式:
system.serviceaccount:<namespace>:<service account name>
ServiceAccount也是一种资源,可以被创建,每个namespace下有一个默认的default ServiceAccount,pod只能使用同一个命名空间中的ServiceAccount
创建serviceAccount:
kubectl create sa foo
自己创建的serviceAccount应及时授予相应的权限(比如对k8s资源元数据的读写),否则与default无异
显示指定serviceAccountName(不指定就用默认的):只能在创建时指定,不能修改
apiVersion: v1
kind: Pod
metadata:
name: hostpath-example
spec:
serviceAccountName: foo
containers:
- image: docker.io/library/busybox:latest
name: container1
创建完serviceAccount后,来看一下它的详情:
可挂载秘钥:正常来说,pod可以随意挂载secret,但如果sa中Mountable secrets指定了可以挂载的secret列表,那使用这个sa的pod就只能挂这些secret。
为了开启这个功能,ServiceAccount必须包含以下注解:kubernetes.io/enforce-mountable-secrets=″true″
镜像拉取秘钥:从私仓拉取镜像时,也要秘钥,这里可以配置这个列表,这个会自动放入pod,可以在创建sa时spec里指定
二、通过基于角色的权限控制加强集群安全
身份认证插件识别到请求“人”后,就来到了授权插件,授权插件检查这个“人”有没有权限做这个请求动作
2.1 RBAC插件
最常用的一个授权插件就是RBAC插件,它将用户角色作为决定用户能否执行操作的关键因素
授权规则是通过四种资源来进行配置的:
Role和ClusterRole、Rolebinding和ClusterRoleBinding
角色定义了可以做什么操作,而绑定定义了谁可以做这些操作
Role和RoleBinding都在命名空间中,ClusterRole和ClusterRoleBinding是集群级别的,不在命名空间中,但是可以看到RoleBinding可以绑定ClusterRole
2.2 使用Role和RoleBinding
首先需要开启RBAC功能
在命名空间foo和bar分别创建两个pod,那么这两个pod绑定的serviceAccount是各命名空间下默认的serviceAccount:default,这个serviceAccount是没有权限列出service的
创建一个角色:
bar命名空间下用命令行创建:
kubectl create role service-reader --verb=get --verb=list --resource=service -n bar
绑定到serviceAccount:
kubectl create rolebinding test --role=service-reader --serviceaccount=foo.default -n foo
看一下rolebinding的详细信息:一个rolebinding对应一个role,但是可以对应多个serviceAccount或user或group
使用edit命令修改rolebinding的yaml,在subjects中加了bar空间下的serviceAccount,这样bar下的serviceAccount也可以列出foo的service了
rolebinding属于某个namespace,但是可以跨namespace绑定用户
2.3 使用ClusterRole和ClusterRoleBinding
1、创建clusterRole
当要访问集群资源(PV、Node等)或每个命名空间下的资源时,可以用clusterRole角色来访问
kubectl create clusterrole pv-reader --verb=get,list --resource=persistentvolumes
=====》
2、必须始终使用ClusterRoleBinding来对集群级别的资源进行授权访问
kubectl create clusterrolebinding pv-test --clusterrole=pv-reader --serviceaccount=foo.default
3、非资源类URL的权限
除了对资源的权限控制外,API服务器还暴露了一些非资源类的URL,也需要权限才可以调用,通常,这个会通过system:discovery ClusterRole和相同命名的ClusterRoleBinding帮你自动完成
ClusterRoleBinding指向system:discovery ClusterRole。它绑定到了两个组,分别是 system:authenticated 和system:unauthenticated,这使得它和所有用户绑定在一起。这意味着每个人都绝对可以访问列在ClusterRole中的URL
4、clusterRole绑定Rolebinding
刚才说访问集群资源时,clusterRole必须绑定clusterRoleBinding,如果绑定的是Rolebinding的话,还是访问不了集群资源的
但当并不需要访问集群资源,只需要访问命名空间下的资源时,clusterRole是可以和RoleBinding绑定的,也就是第二张图的RoleBinding指向clusterRole那条线
尝试之前需要把刚才绑定的clusterRoleBinding删掉
操作的都是命名空间级别的资源
2.4 了解默认的ClustRole和ClusterRoleBinding
kubectl get clusterrolebindings
kubectl get clusterroles
view、edit、admin和cluster-admin ClusterRole是最重要的角色,它们应该绑定到用户定义pod中的ServiceAccount上
view:允许读取一个命名空间中的大多数资源,除了Role、RoleBinding和Secret。因为Secrets中的某一个可能包含一个认证token,它比定义在view ClusterRole中的资源有更大的权限,并且允许用户伪装成不同的用户来获取额外的权限(权限扩散)
edit:允许你修改一个命名空间中的资源,同时允许读取和修改Secret。但是,它也不允许查看或修改Role和RoleBinding,这是为了防止权限扩散
admin:一个命名空间中的资源的完全控制权是由admin ClusterRole赋予的。有这个ClusterRole的主体可以读取和修改命名空间中的任何资源,除了ResourceQuota和命名空间资源本身,与edit的区别在于role和rolebinding
cluster-admin:主体可以获得Kubernetes集群完全控制的权限
其他:以system开头的调度器、控制器等clusterRole和clusterRoleBinding