在CoreDNS一节中,虽然我安装 coredns的尝试失败了,但是我们仍然可以看到 dns 组件是如何安装的
安装过程中有一个错误
failed with No API token found for service account “coredns”
我们选择禁用 ServiceAccount 简单粗暴的规避了这个错误
将:KUBE_ADMISSION_CONTROL=”–admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota”
改为:KUBE_ADMISSION_CONTROL=”–admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota”
所以这一节我打算研究一下 ServiceAccount
当你从集群外部访问 apiserver 的时候,使用的是 kubectl 命令行,此时是不需要service account 的,但是当我们从一个pod内部访问它,这种情况下往往没有 kubectl 可用,因此,想要从一个pod内部访问 api server ,就需要 service account
如果你查看当前集群中所有的 service 你可以看到一定会有一个叫做 kubernetes 的 service ,类型是 clusterIP 实际上这个 service 就是 api server
为了测试上面的内容,我要创建一个 ubuntu pod ,然后用它尝试连接 api server
apiVersion: apps/v1
kind: Deployment
metadata:
name: ub2
labels:
app: ub2
spec:
replicas: 1
selector:
matchLabels:
app: ub2
template:
metadata:
labels:
app: ub2
spec:
containers:
- name: ub2
image: libaibai/ub2:latest
command: ["/bin/bash","-c","sleep 3600"]
ports:
- containerPort: 80
然后我们使用这个pod来尝试访问 apiserver
api server 的 cert 存放在 secret 中
这个文件会被映射到每个pod 的 /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
但是你不能直接使用这个 cert 来通过验证,下面出现的401 和 上面出现的 401 一样都是 客户端 忽略 或 信任了 服务器端之后的结果
但是服务器并没有授权客户端
如果客户端不信任服务器端是这样的
需要得到 api server 的授权,要使用
/var/run/secrets/kubernetes.io/serviceaccount/token
curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Ikxsc0ZlMElUY3FLanNONGRoYzMtTGJDWXZjZWE2WXVkR2pOajdtNXNHTTAifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tZzZzdzYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjQ1NzY1NzdkLTNkNGYtNDUyMS1iNDdkLWY5MmJhOGUxNjg3MyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.SAdvtBm1v4-YzD7qTC4KOdt6PDY4vAyptGzQkGNP17BqAqDNi9-dbrfJdYEFgof7nyMZH_TCMhi1FXMZJwQ5zOKXeS_YKruJuvJ1iXLwW2MoVy-conJmkoMU-SRcsy8tjv5KkLEZa9adIRG_8jHGc4zSRvs-5YkApsIYYOMFcUbhIVjyMt_rXIeb900hj1e5AhcaSQ19gy2paQkcCbaFnxq7dsgSbpsy011QDe-FzaWv7yY8xI3PJj-JIRgrDxV4WbtalJ5V5IrNcFhHyB7hxawZKvexIJ_ndPewacA42vIUoemAYCQYXm3Bio_ynd-gTQJQzo0YBGxSxfrHnIaHsQ" https://10.43.0.1:443
返回状态码变成了403,这是因为我们的集群使用了 RBAC
Kubernetes 将连接到 api server 的客户端分为两种
真实的人
pod 中的应用 ( service account )
正常用户 和 service account 都可以属于一个或者多个组
常用组:
system:unauthenticated 用于所有认证插件都不会认证认证客户端身份的请求
system:authenticated 组会自动分配给一个成功通过认证的用户
system:serviceaccounts 包含所有在系统中的 ServiceAccount
system:serviceaccounts:<namespace> 组包含了所有在特定命名空间中的 ServiceAccount
下面来做实验
首先是失败实验
我们在 lizhe namespace 下面创建一个 ubuntu 实例,
然后尝试在没有 授予权限的情况下访问 api server
果然得到了403
下面是正确的实验
给定权限
kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --group=system:serviceaccounts:lizhe
删除的话:
kubectl delete clusterrolebindings permissive-binding
再调用一次 curl
ServiceAccount 和 pod、secret、configmap 一样都是资源,资源的话一定存在于某个 namespace 中
我们尝试新建一个 namespace,可以看到,新的namespace ( lizhe2 ) 自动持有了一个 service account
每个pod 都会与一个 serviceaccount 关联,但是多个pod可以使用同一个serviceaccount
每个pod会被分配一个在这个pod namespace中的单一 serviceaccount
在pod的描述文件中,可以将一个service account 赋给一个pod,如果没有显示地指定 service account,pod会使用所在 namespace 的默认 service account
创建一个新的namespace lizhe10
在其下创建 ubuntu10
实验一
当 ubuntu10 使用默认的 service account ( 由 lizhe10 提供的 ) 时,得到了403 ,无法访问 api server
实验二
给 pod 赋值其他 namespace 下的 service account -> 失败
pod ubuntu10 在 namespace lizhe10 下
sa lizhesa 在 namespace lizhe 下
给 ubuntu10 赋 lizhesa 失败
实验三
在 lizhe10 这个 namespace 下创建一个 sa , 叫做 lizhesa10
把这个 新建的 sa lizhesa10 赋给 ubuntu10
此时,如果你尝试使用 lizhe10 这个 sa 去访问 api server,会得到 403
然后我们为 lizhesa10 赋权限
语法是这样的,之前我们用的是 group
$ clusterrolebinding NAME --clusterrole=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]
这次我们使用 service account
kubectl create clusterrolebinding permissive-binding-lizhesa10 --clusterrole=cluster-admin --serviceaccount=lizhe10:lizhesa10
生效之后你就可以得到正确的 response了
下面是一些题外话
如果使用 describe 命令,查看这个 sa ,可以看到 它携带了一个 token
kubectl describe sa lizhesa10 -n lizhe10
这个token实际上就是你在 pod 中得到的那个 token
RBAC 授权插件将用户角色作为决定用户是否能执行操作的关键因素。
主体 ( 人、sa 或者 group ) 和 一个或者多个 role 关联,每个 role 被允许在特定的资源上执行特定的 动作
如果一个用户有多个角色,他们可以做任何角色允许的动作。
RBAC 通过创建 四种 特定的 Kubernetes 资源来完成
Role 和 ClusterRole
它们指定了在资源上可以执行哪些动作
RoleBinding 和 ClusterRoleBinding
它们将上述角色绑定到特定的 用户、组 或者 sa 上
之前我们使用过
kubectl create clusterrolebinding permissive-binding --clusterrole=cluster-admin --group=system:serviceaccounts:lizhe
意思是 创建了一个 名为 permissive-binding 的 类型是 clusterrolebinding 的绑定 到 clusterrole ,绑定的对象是一个组 该组作用域为 lizhe namespace
RoleBinding与ClusterRoleBinding
RoleBinding
RoleBinding可以将同一namespace中的subject(用户)绑定到某个具有特定权限的Role下,则此subject即具有该Role定义的权限。
ClusterRoleBinding
ClusterRoleBinding在整个集群级别和所有namespaces将特定的subject与ClusterRole绑定,授予权限。
Role与ClusterRole
Role
Role对象只能用于授予对某一namespace中资源的访问权限。
ClusterRole
ClusterRole对象可以授予整个集群范围内资源访问权限, 也可以对以下几种资源的授予访问权限:
- 集群范围资源(例如节点,即node)
- 非资源类型endpoint(例如”/healthz”)
- 跨所有namespaces的范围资源(例如pod,需要运行命令
kubectl get pods --all-namespaces
来查询集群中所有的pod)