Api server 认证机制

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)
Send a Message