API 访问控制
如上图所示,用户(User和Service Account)在调用API时会经过三个步骤:认证、鉴权和准入控制。
认证
如上图步骤 1 所示,建立 TLS 后, HTTP 请求将进入认证(Authentication)步骤。 集群创建脚本或者集群管理员配置 API 服务器,使之运行一个或多个身份认证组件。
认证步骤输入的是整个 HTTP 请求,但是组件通常只检查头部和客户端证书。
认证模块包含客户端证书、密码、普通令牌、引导令牌和 JSON Web 令牌(JWT,用于服务账户)。
可以指定多个认证模块,在这种情况下,服务器依次尝试每个验证模块,直到其中一个成功。
如果请求认证不通过,服务器将以 HTTP 状态码 401 拒绝该请求。 反之,该用户被认证为特定的 username
,并且该用户名可用于后续步骤以在其决策中使用。 部分验证器还提供用户的组成员身份,其他则不提供。
鉴权
如上图的步骤 2 所示,将请求验证为来自特定的用户后,请求必须被鉴权。
请求必须包含请求者的用户名、请求的行为以及受该操作影响的对象。 如果现有策略声明用户有权完成请求的操作,那么该请求被鉴权通过。
Kubernetes 支持多种鉴权模块,例如 ABAC 模式、RBAC 模式和 Webhook 模式等。 管理员创建集群时,他们配置应在 API 服务器中使用的鉴权模块。 如果配置了多个鉴权模块,则 Kubernetes 会检查每个模块,任意一个模块鉴权该请求,请求即可继续; 如果所有模块拒绝了该请求,请求将会被拒绝(HTTP 状态码 403)。
准入控制
准入控制模块是可以修改或拒绝请求的软件模块。 除鉴权模块可用的属性外,准入控制模块还可以访问正在创建或修改的对象的内容。
准入控制器对创建、修改、删除或(通过代理)连接对象的请求进行操作。 准入控制器不会对仅读取对象的请求起作用。 有多个准入控制器被配置时,服务器将依次调用它们。
这一操作如上图的步骤 3 所示。
与身份认证和鉴权模块不同,如果任何准入控制器模块拒绝某请求,则该请求将立即被拒绝。
除了拒绝对象之外,准入控制器还可以为字段设置复杂的默认值。
请求通过所有准入控制器后,将使用检验例程检查对应的 API 对象,然后将其写入对象存储(如步骤 4 所示)。
k8s认证详解
k8s用户
所有 Kubernetes 集群都有两类用户:普通用户和由 Kubernetes 管理的服务账号。
Kubernetes 并不包含用来代表普通用户账号的对象。 普通用户的信息无法通过 API 调用添加到集群中。
但是Kubernetes 仍然认为能够提供由集群的证书机构签名的合法证书的用户是通过身份认证的用户。基于这样的配置,Kubernetes 使用证书中的 'subject' 的通用名称(Common Name)字段(例如,"/CN=bob")来确定用户名。然后,基于角色访问控制(RBAC)子系统会确定用户是否有权针对 某资源执行特定的操作。
与普通用户不同,服务账号是 Kubernetes API 所管理的用户。它们被绑定到特定的名字空间, 或者由 API 服务器自动创建,或者通过 API 调用创建。服务账号与一组以 Secret 保存的凭据相关,这些凭据会被挂载到 Pod 中,从而允许集群内的进程访问 Kubernetes API。
身份认证策略
Kubernetes 使用身份认证插件利用客户端证书、持有者令牌(Bearer Token)、身份认证代理(Proxy) 或者 HTTP 基本认证机制来认证 API 请求的身份。HTTP 请求发给 API 服务器时, 插件会将以下属性关联到请求本身:
- 用户名:用来辩识最终用户的字符串。常见的值可以是
kube-admin
或jane@example.com
。 - 用户 ID:用来辩识最终用户的字符串,旨在比用户名有更好的一致性和唯一性。
- 用户组:取值为一组字符串,其中各个字符串用来标明用户是某个命名的用户逻辑集合的成员。 常见的值可能是
system:masters
或者devops-team
等。 - 附加字段:一组额外的键-值映射,键是字符串,值是一组字符串;用来保存一些鉴权组件可能 觉得有用的额外信息。
你可以同时启用多种身份认证方法,并且你通常会至少使用两种方法:
- 针对服务账号使用服务账号令牌
- 至少另外一种方法对用户的身份进行认证
当集群中启用了多个身份认证模块时,第一个成功地对请求完成身份认证的模块会 直接做出评估决定。API 服务器并不保证身份认证模块的运行顺序。
X509证书
要启动客户端证书身份认证,需要配置apiserver, 传入参数--client-ca-file=SOMEFILE
,其中ca要与集群的ca一致。集群使用的ca可以通过以下命令查看
#其中certificate-authority对应的就是集群使用的ca
kubectl config view
如果客户端的证书认证通过,则 subject 中的公共名称(Common Name)就被 作为请求的用户名。 自 Kubernetes 1.4 开始,客户端证书还可以通过证书的 organization 字段标明用户的组成员信息。 要包含用户的多个组成员信息,可以在证书种包含多个 organization 字段。
静态令牌文件
当 API server的命令行设置了 --token-auth-file=SOMEFILE
选项时,会从文件中读取持有者令牌。目前,令牌会长期有效,并且在不重启 API server的情况下 无法更改令牌列表。
令牌文件是一个 CSV 文件,包含至少 3 个列:令牌、用户名和用户的 UID。 其余列被视为可选的组名。
说明:
如果要设置的组名不止一个,则对应的列必须用双引号括起来,例如
token,user,uid,"group1,group2,group3"
服务账号令牌
服务账号(Service Account)是一种自动被启用的用户认证机制,使用经过签名的 持有者令牌来验证请求。
当服务账号创建后,k8s会自动生成对应的secret,存有可以用来认证的token。
[root@localhost .minikube]# kubectl get sa
NAME SECRETS AGE
default 1 6h34m
#由于只有一个sa 所以下面的secret就是上面sa名称为default的secret
[root@localhost .minikube]# kubectl get secret
NAME TYPE DATA AGE
default-token-fprt2 kubernetes.io/service-account-token 3 6h34m
#查看token
[root@localhost .minikube]# kubectl describe secret default-token-fprt2
Name: default-token-fprt2
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: default
kubernetes.io/service-account.uid: c6424baa-ce36-48ac-98bf-4a7c3d45f323
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1111 bytes
namespace: 7 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6Ii1uQW5QTVRxMXBhMHNPelE0c054Z1pzZjZnVTBSYUVaZEt0aXlGT3p6NkUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tZnBydDIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImM2NDI0YmFhLWNlMzYtNDhhYy05OGJmLTRhN2MzZDQ1ZjMyMyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.AnsoZKssbccnWuQnBNXx3U14EFHvIg9bdI1c7G1ATIBjIvNlud1CHZ2zEwqj7ef8mOew9x76DHagDQQ1WgL2qhDZ7snNfSetrvZ0nwKh7EWA_-uwEMJEorOCBJcvTbw_PD-BiiF2M54vwN3Wc_fN3LRe2KloG8abgYm8It4ftNuFGN63NmvNSd1LEzZVzeXD93my1HoAfhlhyIh7OQqiT7o0mDL5HzYudgGFZUWWrciIaSdp8t3GMCsmMRgtgcRaLOpbpeUlw45LtewFqSb2w4joqnTVwaY502QaF_WdSuT37rCFDjgs74PmbXkDuoUaBypha7UWMX1d7ZZgBMWXhg
上面的token就可以用来认证。
所有使用token进行认证的请求,都要加上 Authorization
的 HTTP请求头,其值格式为 Bearer TOKEN
。
例如:如果持有者令牌为 31ada4fd-adec-460c-809a-9e56ceb75269
,则其 出现在 HTTP 头部时如下所示:
Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269
使用代理进行认证
使用这种认证方式,apiserver将从请求头中获取用户信息,认证过程如图所示。
使用这种认证方式需要对apiserver进行如下配置:
-
--requestheader-username-headers
必需字段,大小写不敏感。用来设置要获得用户身份所要检查的头部字段名称列表(有序)。第一个包含数值的字段会被用来提取用户名。 -
--requestheader-group-headers
可选字段,在 Kubernetes 1.6 版本以后支持,大小写不敏感。 建议设置为 "X-Remote-Group"。用来指定一组头部字段名称列表,以供检查用户所属的组名称。 所找到的全部头部字段的取值都会被用作用户组名。 -
--requestheader-extra-headers-prefix
可选字段,在 Kubernetes 1.6 版本以后支持,大小写不敏感。 建议设置为 "X-Remote-Extra-"。用来设置一个头部字段的前缀字符串,API 服务器会基于所给 前缀来查找与用户有关的一些额外信息。这些额外信息通常用于所配置的鉴权插件。 API 服务器会将与所给前缀匹配的头部字段过滤出来,去掉其前缀部分,将剩余部分 转换为小写字符串并在必要时执行百分号解码后,构造新的附加信息字段键名。原来的头部字段值直接作为附加信息字段的值。默认是允许所有的CN。
例子:
假设apiserver配置如下
--requestheader-username-headers=X-Remote-User
--requestheader-group-headers=X-Remote-Group
--requestheader-extra-headers-prefix=X-Remote-Extra-
收到的请求头如下
GET / HTTP/1.1
X-Remote-User: fido
X-Remote-Group: dogs
X-Remote-Group: dachshunds
X-Remote-Extra-Acme.com%2Fproject: some-project
X-Remote-Extra-Scopes: openid
X-Remote-Extra-Scopes: profile
会生成如下的用户信息用于鉴权
name: fido
groups:
- dogs
- dachshunds
extra:
acme.com/project:
- some-project
scopes:
- openid
- profile
RBAC
Role和ClusterRole
Role 总是用来在某个namespace内设置访问权限;在你创建 Role 时,你必须指定该 Role 所属的namespace。
与之相对,ClusterRole 则是一个集群作用域的资源。这两种资源的名字不同(Role 和 ClusterRole)是因为 Kubernetes 对象要么是namespace作用域的,要么是集群作用域的, 不可两者兼具。
ClusterRole 有若干用法。你可以用它来:
- 定义对某namespace域对象的访问权限,并将在各个namespace内完成授权;
- 为namespace作用域的对象设置访问权限,并跨所有namespace执行授权;
- 为集群作用域的资源定义访问权限。
如果你希望在namespace内定义角色,应该使用 Role; 如果你希望定义集群范围的角色,应该使用 ClusterRole。
Role例子
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" 标明 core API 组
resources: ["pods"]
verbs: ["get", "watch", "list"]
ClusterRole例子
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
name: secret-reader
rules:
- apiGroups: [""]
# 在 HTTP 层面,用来访问 Secret 对象的资源的名称为 "secrets"
resources: ["secrets"]
verbs: ["get", "watch", "list"]
RoleBinding和ClusterRoleBinding
角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。 它包含若干 主体(用户、组或服务账户)的列表和对这些主体所获得的角色的引用。 RoleBinding 在指定的名字空间中执行授权,而 ClusterRoleBinding 在集群范围执行授权。
一个 RoleBinding 可以引用同一的名字空间中的任何 Role。 或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的名字空间。 如果你希望将某 ClusterRole 绑定到集群中所有名字空间,你要使用 ClusterRoleBinding。
RoleBinding例子
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pods
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
name: jane # "name" 是不区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
# "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
apiGroup: rbac.authorization.k8s.io
ClusterRoleBinding例子
apiVersion: rbac.authorization.k8s.io/v1
# 此集群角色绑定允许 “manager” 组中的任何人访问任何名字空间中的 secrets
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager # 'name' 是不区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
以上就是RBAC鉴权的一个概述,总结下就是Role定义了角色有哪些权限,RoleBinding则将角色和用户关联起来。这里的权限指的是对哪些资源有哪些操作的权限,用户则包括了普通用户和服务账号。
更多的关于RBAC的描述可以看下官网,包括了k8s内置的一些默认角色。
API调用示例
这里测试使用的k8s集群是通过kubeadm安装的,这种安装方式会将k8s中的组件如kube-apiserver、kube-scheduler等作为static pod的形式运行。因此可以通过kubectl get pod
命令来查看对应组件的配置。
[root@k8s-244 ~]# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-7f89b7bc75-4zlcg 1/1 Running 0 44h
kube-system coredns-7f89b7bc75-mgxg2 1/1 Running 0 44h
kube-system etcd-k8s-244 1/1 Running 0 44h
kube-system kube-apiserver-k8s-244 1/1 Running 43 43h
kube-system kube-controller-manager-k8s-244 1/1 Running 3 44h
kube-system kube-proxy-l5779 1/1 Running 0 44h
kube-system kube-proxy-nhgb9 1/1 Running 0 44h
kube-system kube-scheduler-k8s-244 1/1 Running 3 44h
kube-system weave-net-569jg 2/2 Running 1 44h
kube-system weave-net-x956f 2/2 Running 1 44h
X509
#查看apiserver配置,确定使用的ca文件
[root@k8s-244 ~]# kubectl get pod kube-apiserver-k8s-244 -n kube-system -o yaml
#截取了部分内容显示
spec:
containers:
- command:
- kube-apiserver
- --advertise-address=10.190.181.244
- --allow-privileged=true
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --enable-admission-plugins=NodeRestriction
- --enable-bootstrap-token-auth=true
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
- --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
- --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
- --etcd-servers=https://127.0.0.1:2379
- --insecure-port=0
- --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
- --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
- --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
- --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
- --requestheader-extra-headers-prefix=X-Remote-Extra-
- --requestheader-group-headers=X-Remote-Group
- --requestheader-username-headers=X-Remote-User
- --secure-port=6443
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
- --service-cluster-ip-range=10.1.0.0/16
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
image: registry.aliyuncs.com/google_containers/kube-apiserver:v1.20.0
imagePullPolicy: IfNotPresent
从上面的结果可以看到使用的ca是/etc/kubernetes/pki/ca.crt
,接下来开始生成客户端的证书。
#切换目录
cd /etc/kubernetes/pki
#生成key
openssl genrsa -out test.key 2048
#生成证书请求
openssl req -new -key test.key -out test.csr -subj "/CN=test"
#使用ca签名生成证书
openssl x509 -req -in test.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out test.crt -days 365
这样就生成了一个用户名为test的客户端证书,接下来用这个证书去调k8s的api。
[root@k8s-244 pki]# curl --cert /etc/kubernetes/pki/test.crt --key /etc/kubernetes/pki/test.key https://10.190.181.244:6443/api/v1/namespaces/kube-system/pods --insecure
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "pods is forbidden: User \"test\" cannot list resource \"pods\" in API group \"\" in the namespace \"kube-system\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
这代表我们认证通过了,但是鉴权没有通过。接下来给test授权。
先创建一个角色(role.yaml),拥有kube-system namespace下读取pod的权限,使用命令kubectl apply -f role.yaml
来让他生效。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: kube-system
name: pod-reader
rules:
- apiGroups: [""] # "" 标明 core API 组
resources: ["pods"]
verbs: ["get", "watch", "list"]
接下来创建一个RoleBinding,将刚刚创建的角色绑定到test上,并使用命令kubectl apply -f bind.yaml
来让他生效
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: kube-system
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
name: test # "name" 是不区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
# "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
apiGroup: rbac.authorization.k8s.io
生效后再次使用curl调用api,一切正常。
服务账号令牌
先创建一个kube-system下的服务账号,命令如下
[root@k8s-244 pki]# kubectl create sa test -n kube-system
查看有没有生效
[root@k8s-244 pki]# kubectl get sa -n kube-system
NAME SECRETS AGE
attachdetach-controller 1 44h
bootstrap-signer 1 44h
certificate-controller 1 44h
clusterrole-aggregation-controller 1 44h
coredns 1 44h
cronjob-controller 1 44h
daemon-set-controller 1 44h
default 1 44h
deployment-controller 1 44h
disruption-controller 1 44h
endpoint-controller 1 44h
endpointslice-controller 1 44h
endpointslicemirroring-controller 1 44h
expand-controller 1 44h
generic-garbage-collector 1 44h
horizontal-pod-autoscaler 1 44h
job-controller 1 44h
kube-proxy 1 44h
namespace-controller 1 44h
node-controller 1 44h
persistent-volume-binder 1 44h
pod-garbage-collector 1 44h
pv-protection-controller 1 44h
pvc-protection-controller 1 44h
replicaset-controller 1 44h
replication-controller 1 44h
resourcequota-controller 1 44h
root-ca-cert-publisher 1 44h
service-account-controller 1 44h
service-controller 1 44h
statefulset-controller 1 44h
test 1 50s
token-cleaner 1 44h
ttl-controller 1 44h
weave-net 1 44h
可以看到名称为test的sa(service account)已经创建了。接下来查看他对应的secret来获得token。
#查看对应的secret
[root@k8s-244 pki]# kubectl get sa test -n kube-system -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2021-02-07T02:23:54Z"
name: test
namespace: kube-system
resourceVersion: "20350"
uid: ccb4d96d-cfa1-403c-b6b2-71f89dc9a7f4
secrets:
- name: test-token-m9qzv
#查看token
[root@k8s-244 pki]# kubectl describe secret test-token-m9qzv -n kube-system
Name: test-token-m9qzv
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name: test
kubernetes.io/service-account.uid: ccb4d96d-cfa1-403c-b6b2-71f89dc9a7f4
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1066 bytes
namespace: 11 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IlpEWm1ISTlYaS1DRmZRVTA0OFR1SlpxWE5fUDdFNmx6OFR1ODFsdTF2YmcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJ0ZXN0LXRva2VuLW05cXp2Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InRlc3QiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJjY2I0ZDk2ZC1jZmExLTQwM2MtYjZiMi03MWY4OWRjOWE3ZjQiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06dGVzdCJ9.mS4Xu4r0nDbBcBpIu5EGMxA77nnf00S51oG9VxIkll8tBMq76Br-jl8vrR2XMAcvQkat_WKHjwQnHRz_jgvOoLSaDQdJSO2jsuYO-4OBUG-WxZ1w9ofcRHvIJxFlYvx5eKgNxX84T1ED3mojb3GD7vPVw1RPrwX_sKukuOQpnKCN1g4A0QhJVO-QLLuaxhVY1bKlp9jIdFwbS2fmn6HetirvQsNKHnCSHBFDRBBZUjNm-p7480FvBGAniNLllJen2VwyfRzTvEyY4Xj-aFrlXvHnVwGgKLTEKnOzgp274pPEMdQcJeYX_i_rv9I2Vr9dQPW7engnWLtd1LTawvzjXg
使用token调用k8s的api
#设置token变量
TOKEN='eyJhbGciOiJSUzI1NiIsImtpZCI6IlpEWm1ISTlYaS1DRmZRVTA0OFR1SlpxWE5fUDdFNmx6OFR1ODFsdTF2YmcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJ0ZXN0LXRva2VuLW05cXp2Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InRlc3QiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJjY2I0ZDk2ZC1jZmExLTQwM2MtYjZiMi03MWY4OWRjOWE3ZjQiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06dGVzdCJ9.mS4Xu4r0nDbBcBpIu5EGMxA77nnf00S51oG9VxIkll8tBMq76Br-jl8vrR2XMAcvQkat_WKHjwQnHRz_jgvOoLSaDQdJSO2jsuYO-4OBUG-WxZ1w9ofcRHvIJxFlYvx5eKgNxX84T1ED3mojb3GD7vPVw1RPrwX_sKukuOQpnKCN1g4A0QhJVO-QLLuaxhVY1bKlp9jIdFwbS2fmn6HetirvQsNKHnCSHBFDRBBZUjNm-p7480FvBGAniNLllJen2VwyfRzTvEyY4Xj-aFrlXvHnVwGgKLTEKnOzgp274pPEMdQcJeYX_i_rv9I2Vr9dQPW7engnWLtd1LTawvzjXg'
#发起请求
curl --location --request GET 'https://10.190.181.244:6443/api/v1/namespaces/kube-system/pods' --header "Authorization: Bearer ${TOKEN}" -k
#结果
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:kube-system:test\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
从结果可以确认认证通过了,现在给sa授权,修改bind.yaml,修改后内容如下
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: kube-system
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
name: test # "name" 是不区分大小写的
apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
name: test # "name" 是不区分大小写的
namespace: kube-system
roleRef:
# "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
apiGroup: rbac.authorization.k8s.io
使用命令kubectl apply -f bind.yaml
生效后,再次调用api,这时就不会返回403了。
使用代理认证
之前查看apiserver的配置时,看到以下配置,说明apiserver是开启了代理认证的,并且指明了使用的ca。
--requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
接下来根据ca生成代理所使用的证书,注意这个ca一般与X509所使用的ca不一致。
并且使用这种方法调用api时,不同的用户只需更改对应的请求头即可,证书不用变更,而如果使用X509的方法,则不同的用户需要使用不同的证书。
#切换目录
cd /etc/kubernetes/pki
#生成key
openssl genrsa -out proxy.key 2048
#生成证书请求
openssl req -new -key proxy.key -out proxy.csr -subj "/CN=proxy"
#使用ca签名生成证书
openssl x509 -req -in proxy.csr -CA front-proxy-ca.crt -CAkey front-proxy-ca.key -CAcreateserial -out proxy.crt -days 365
调用api
curl --cert /etc/kubernetes/pki/proxy.crt --key /etc/kubernetes/pki/proxy.key https://10.190.181.244:6443/api/v1/namespaces/kube-system/pods --insecure --header "X-Remote-User: test"
这里由于使用的请求头表明了当前的用户是test,并且之前已经给test授权过了,所以没有返回403。
接下来更改用户名为jojo,再次调用api
curl --cert /etc/kubernetes/pki/proxy.crt --key /etc/kubernetes/pki/proxy.key https://10.190.181.244:6443/api/v1/namespaces/kube-system/pods --insecure --header "X-Remote-User: jojo"
返回结果如下
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "pods is forbidden: User \"jojo\" cannot list resource \"pods\" in API group \"\" in the namespace \"kube-system\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
API 参考
这里是官方的API参考文档,说明了有哪些api以及对应的使用方式。