1、概述

  在 Kubernetes 官方手册中给出了 “用户” 的概念,Kubernetes 集群中存在的用户包括 “普通用户” 与 “ServiceAccount”, 但是 Kubernetes 没有普通用户的管理方式,通常只是将使用集群根证书签署的有效证书的用户都被视为合法用户。

  那么对于使得 Kubernetes 集群有一个真正的用户系统,就可以根据上面给出的概念将 Kubernetes 用户分为“内部用户”与“外部用户”。如何理解内部与外部用户呢?实际上就是由 Kubernetes 管理的用户,即在 kubernetes 定义用户的数据模型这种为 “内部用户” ,正如 ServiceAccount;反之,非 Kubernetes 托管的用户则为 “外部用户”, 这种概念也更好的对 kubernetes 用户的阐述。

  对于外部用户来说,实际上 Kubernetes 给出了多种用户概念,例如:

  • 拥有 kubernetes 集群证书的用户
  • 拥有 Kubernetes 集群 token 的用户(--token-auth-file指定的静态 token)
  • 用户来自外部用户系统,例如 OpenID,LDAP,QQ connect, google identity platform 等

本文不过多介绍Kubernetes外部用户认证,主要讲解Kubernetes内部用户ServiceAccount的认证方式,即大部分Pod默认的认证方式(Pod和APIServer之间如果没有配置基于CA根证书签名的双向数字证书方式进行认证的话,则默认通过Token方式进行认证)。

注意:在之前博文中讲解过拥有kubernetes集群证书的用户的认证方式,详情见《Kubernetes客户端认证——基于CA证书的双向认证方式》。

2、基于ServiceAccount的JWTToken认证

2.1 ServiceAccount定义

ServiceAccount(服务帐户)与Namespace绑定,关联一套凭证,Pod创建时挂载Token,从而允许与API Server之间调用。ServiceAccount同样是Kubernetes中的资源,与Pod、ConfigMap类似,且作用于独立的命名空间,也就是ServiceAccount是属于命名空间级别的,创建命名空间时会自动创建一个名为default的ServiceAccount。

使用下面命令可以查看ServiceAccount。

[root@node1 ~]# kubectl get sa
NAME SECRETS AGE
default 1 356d

同时Kubernetes还会为ServiceAccount自动创建一个Token,使用下面命令可以查看到。

[root@node1 ~]# kubectl describe sa default
Name: default
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: default-token-p4l9w
Tokens: default-token-p4l9w
Events: <none>

在Pod的定义文件中,可以用指定帐户名称的方式将一个ServiceAccount赋值给一个Pod,如果不指定就会使用默认的ServiceAccount。当API Server接收到一个带有认证Token的请求时,API Server会用这个Token来验证发送请求的客户端所关联的ServiceAccount是否允许执行请求的操作。

注意:

  • 1.21以前版本的集群中,Pod中获取Token的形式是通过挂载ServiceAccount的Secret来获取Token,这种方式获得的Token是永久的。该方式在1.21及以上的版本中不再推荐使用,并且根据社区版本迭代策略,在1.25及以上版本的集群中,ServiceAccount将不会自动创建对应的Secret。

    1.21及以上版本的集群中,直接使用TokenRequest API获得Token,并使用投射卷(Projected Volume)挂载到Pod中。使用这种方法获得的Token具有固定的生命周期,并且当挂载的Pod被删除时这些Token将自动失效。详情请参见Token安全性提升说明

  • 如果您在业务中需要一个永不过期的Token,您也可以选择手动管理ServiceAccount的Secret。尽管存在手动创建永久ServiceAccount Token的机制,但还是推荐使用TokenRequest的方式使用短期的Token,以提高安全性。

2.2 创建ServiceAccount

使用如下命令就可以创建ServiceAccount:

[root@node1 ~]# kubectl create serviceaccount sa-example
serviceaccount/sa-example created
[root@node1 ~]# kubectl get sa
NAME SECRETS AGE
default 1 356d
sa-example 1 6s

可以看到已经创建了与ServiceAccount相关联的Token。

[root@node1 ~]# kubectl describe sa sa-example
Name: sa-example
Namespace: default
Labels: <none>
Annotations: <none>
Image pull secrets: <none>
Mountable secrets: sa-example-token-42nbt
Tokens: sa-example-token-42nbt
Events: <none>

查看Secret的内容,可以发现ca.crt、namespace和token三个数据。

[root@node1 ~]# kubectl describe secret sa-example-token-42nbt
Name: sa-example-token-42nbt
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: sa-example
kubernetes.io/service-account.uid: 5c67e9c7-0b12-44ae-a97e-f2ee4cd061b0 Type: kubernetes.io/service-account-token Data
====
ca.crt: 1066 bytes
namespace: 7 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6InpKM2o1WXg2b1pwQ0lyTjNWVU4wUjUzMTZuamt0LVZEQlNqbG5HLWNxdUUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InNhLWV4YW1wbGUtdG9rZW4tNDJuYnQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic2EtZXhhbXBsZSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjVjNjdlOWM3LTBiMTItNDRhZS1hOTdlLWYyZWU0Y2QwNjFiMCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnNhLWV4YW1wbGUifQ.FlL0EAeNYOqNpCmBG5QU0qAbGIVHjTP3hVMOL8nmiawmZsitSDupKrdbpIjFgS3VOTR8GZfZCnCnVI7fE0ZkZzt6kW7ILTRIiNbmedScI4w_FiSbGI-MX48HJAIgF0hrdJ3_Rc30-Or-fMxlligcO08OpSQrBT20J4LR6NM4B-r_s83b7Rwm7F95GWc5rmYZje1uRJfRuzqBwV4PLT5Ph7u_XDn8WS1XXWagq5qioySFV1Xg9Lb9nHXVNmTL2g0E2_RDqUFj-tsns8Xj3B9Yvm4CH5uS6PbV0UsdFlm-mCOF4vinDHSP4mH6CSBWyzRnl9vF7hbfNzW96rIKKSJ9CA 

注意:只有在1.23及之前版本的集群中,ServiceAccount才会自动创建Secret。

2.3 在Pod中使用ServiceAccount

Pod中使用ServiceAccount非常方便,只需要指定ServiceAccount的名称即可。

apiVersion: v1
kind: Pod
metadata:
name: sa-example
spec:
serviceAccountName: sa-example
containers:
- image: nginx:alpine
name: container-0
resources:
limits:
cpu: 100m
memory: 200Mi
requests:
cpu: 50m
memory: 100Mi

创建并查看这个Pod,可以看到Pod挂载了sa-example-token-c7bqx,即Pod使用这个Token来做认证。

[root@node1]# kubectl apply -f test-sa.yaml
pod/sa-example created [root@node1 test]# kubectl get pods
NAME READY STATUS RESTARTS AGE
sa-example 1/1 Running 0 32s [root@node1]# kubectl describe pod sa-example
...
Containers:
sa-example:
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from sa-example-token-42nbt (ro)

注意: 通过这个方式,您可以了解Pod的认证机制,但在实际使用中,出于安全性考虑,1.21及以上版本的集群中Pod中默认挂载的Token是临时的。

进入Pod内部,还可以看到对应的文件,如下所示:

[root@node1 ~]# kubectl exec -it sa-example /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # cd /run/secrets/kubernetes.io/serviceaccount
/run/secrets/kubernetes.io/serviceaccount # ls
ca.crt namespace token

如上,在容器应用中,就可以使用ca.crt和Token来访问APIServer。

2.4 基于token访问APIServer

下面来验证一下认证是否能生效。在Kubernetes集群中,默认为API Server创建了一个名为kubernetes的Service,通过这个Service可以访问API Server。

[root@node1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 356d

进入Pod,使用curl命令直接访问会得到如下返回信息,表示并没有权限。

[root@node1 ~]# kubectl exec -it sa-example /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # curl https://kubernetes
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
/ #

使用ca.crt和Token做认证,先将ca.crt放到CURL_CA_BUNDLE这个环境变量中,curl命令使用CURL_CA_BUNDLE指定证书;再将Token的内容放到TOKEN中,然后带上TOKEN访问API Server。 

/ # export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
/ # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
/ # curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/default/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": { },
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:default:sa-example\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}/ #

可以看到,已经能够通过认证了,但是API Server返回的是cannot get path \"/\"",表示没有权限访问,这说明还需要得到授权后才能访问,接下来为default命名空间下的ServiceAccount  sa-example关联Role使其能够获取Pod资源。

首先创建Role,Role的定义非常简单,指定namespace,然后就是rules规则。如下面示例中的规则就是允许对default命名空间下的Pod进行GET、LIST操作。

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default # 命名空间
name: role-example
rules:
- apiGroups: [""]
resources: ["pods"] # 可以访问pod
verbs: ["get", "list"] # 可以执行GET、LIST操作

有了Role之后,就可以将Role与具体的用户绑定起来,实现这个的就是RoleBinding了。如下所示:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rolebinding-example
namespace: default
subjects: # 指定用户
- kind: ServiceAccount # ServiceAccount
name: sa-example
namespace: default
roleRef: # 指定角色
kind: Role
name: role-example
apiGroup: rbac.authorization.k8s.io

在Kubernetes集群apply Role和Rolebind文件,现在再进入到sa-example这个Pod,使用curl命令通过API Server访问资源来验证权限是否生效。

/ # export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
/ # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
/ # curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/default/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/namespaces/default/pods",
"resourceVersion": "10377013"
},
"items": [
{
"metadata": {
"name": "sa-example",
......

返回结果正常,说明sa-example现在有LIST Pod的权限了。

注意 1:本示例中,sa-example Pod通过HTTPS单向认证方式与Kube-Apiserver服务端建立连接后,进入Kube-Apiserver认证过滤器链(默认支持CA认证和Token认证两种身份验证方式,因为客户端证书为空,所以不会执行CA认证过滤器逻辑),如果请求中包含Authorization头部,并且其值是以Bearer开头的Token,则进入Token认证过滤器逻辑,对JWT Token进行验证,如果Token未过期且签名有效,则认证成功,并从中获取Pod所使用的ServiceAccount的用户信息。认证成功后,进入Kube-Apiserver授权阶段,如果请求被授权,则继续处理;否则,Kube-Apiserver会返回HTTP 401未授权错误。

注意 2:本示例中,sa-example Pod和 API Server 之间建立了一个加密的 SSL/TLS 连接(HTTPS单向认证方式),所有的通信都会经过加密传输,包括客户端请求中的 token 信息和 Kube-Apiserver 的响应。这样可以确保通信过程中的安全性,同时防止任何未经授权的访问和攻击。HTTPS单向认证步骤如下:

  1. 客户端发起建立HTTPS连接请求,将SSL协议版本的信息发送给服务端。
  2. 服务端将自己的公钥证书(server.crt)发送给客户端。
  3. 客户端通过自己的根证书(ca.crt)验证服务端的公钥证书(server.crt)的合法性,取出服务端公钥。(如果验证公钥证书失败,则中断HTTPS连接)
  4. 客户端生成密钥R,用服务端公钥去加密它形成密文,发送给服务端。
  5. 服务端用自己的私钥(server.key)去解密这个密文,得到客户端的密钥R。
  6. 服务端和客户端使用密钥R进行通信。

注意 3: Kube-Apiserver tls客户端认证配置为RequestClientCert(客户端请求可以不发送客户端证书),即可以不使用SSL/TLS加密方式或仅使用SSL/TLS单向认证方式或使SSL/TLS双向认证方式与Kube-Apiserver服务端建立连接,所以不使用SSL/TLS加密方式方式认证与Kube-Apiserver服务端简历连接也是可以的。

/ # curl -k  https://kubernetes/api/v1/namespaces/default/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": { },
"status": "Failure",
"message": "pods is forbidden: User \"system:anonymous\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
/ # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
/ # curl -k -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/default/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/namespaces/default/pods",
"resourceVersion": "10377013"
},
"items": [
{
"metadata": {
"name": "sa-example",
......

注意 4:Kube-Apiserver服务端监听的是tls端口,如果使用http方式访问是不行的(对HTTPS服务发起HTTP请求会报请求方式错误,Client sent an HTTP request to an HTTPS server.)。

/ # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
/ # curl -k -H "Authorization: Bearer $TOKEN" http://kubernetes/api/v1/namespaces/default/pods
curl: (52) Empty reply from server

3、总结

在 Kubernetes 中,Pod客户端和Kube-Apiserver服务端进行交互时,使用 token 进行身份验证的请求会使用 SSL/TLS 加密进行保护。具体来说,使用 token 进行身份验证的请求流程如下:

  1. 客户端使用提前生成好的 token 发起请求,将 token 附加在请求的 Authorization 头部。

  2. 客户端会首先与 API Server 建立一个加密的 SSL/TLS 连接,以保护通信的安全性。

  3. Kube-Apiserver 收到请求后,会对 token 进行验证,如果验证通过,进入Kube-Apiserver授权阶段,如果请求被授权,则继续处理;否则,Kube-Apiserver会返回HTTP 401未授权错误。

在这个过程中,客户端和 API Server 之间建立了一个加密的 SSL/TLS 连接,所有的通信都会经过加密传输,包括客户端请求中的 token 信息和 API Server 的响应。这样可以确保通信过程中的安全性,同时防止任何未经授权的访问和攻击。

需要注意的是,虽然使用 token 进行身份验证的请求会经过 SSL/TLS 加密进行保护,但是 SSL/TLS 加密并不能完全防止所有的安全威胁,因此在实际使用中,仍然需要采取其他安全措施来保障 Kubernetes 环境的安全性。

参考:ServiceAccount

参考:深入理解 Kubernetes 中的用户与身份认证授权

Kubernetes客户端认证(二)—— 基于ServiceAccount的JWTToken认证的更多相关文章

  1. 基于Token的身份认证 与 基于服务器的身份认证

    基于Token的身份认证 与 基于服务器的身份认证 基于服务器的身份认证 在讨论基于Token的身份认证是如何工作的以及它的好处之前,我们先来看一下以前我们是怎么做的: HTTP协议是无状态的,也就是 ...

  2. 高级运维(二):搭建Nginx服务器、用户认证、基于域名的虚拟主机、SSL虚拟主机、Nginx反向代理

    一.搭建Nginx服务器 目标: 在IP地址为192.168.4.5的主机上安装部署Nginx服务,并可以将Nginx服务器,要求编译时启用如下功能: 1> SSL加密功能 2> 设置Ng ...

  3. .Net Core 认证系统之基于Identity Server4 Token的JwtToken认证源码解析

    介绍JwtToken认证之前,必须要掌握.Net Core认证系统的核心原理,如果你还不了解,请参考.Net Core 认证组件源码解析,且必须对jwt有基本的了解,如果不知道,请百度.最重要的是你还 ...

  4. 将 Shiro 作为应用的权限基础 二:基于SpringMVC实现的认证过程

    认证就是验证用户身份的过程.在认证过程中,用户需要提交实体信息(Principals)和凭据信息(Credentials)以检验用户是否合法.最常见的“实体/凭证”组合便是“用户名/密码”组合. 一. ...

  5. ASP.NET Core 基于JWT的认证(二)

    ASP.NET Core 基于JWT的认证(二) 上一节我们对 Jwt 的一些基础知识进行了一个简单的介绍,这一节我们将详细的讲解,本次我们将详细的介绍一下 Jwt在 .Net Core 上的实际运用 ...

  6. 在Kubernetes集群中安装Helm及证书认证

    安装Kubernetes 测试环境使用kubeadm安装kubernetes v1.6.3版本, 安装过程略过. 为Helm创建客户端认证 客户端认证是为了能够使用helm命令行调用Helm的服务端T ...

  7. 基于.NetCore3.1系列 ——认证授权方案之Swagger加锁

    一.前言 在之前的使用Swagger做Api文档中,我们已经使用Swagger进行开发接口文档,以及更加方便的使用.这一转换,让更多的接口可以以通俗易懂的方式展现给开发人员.而在后续的内容中,为了对a ...

  8. 理解ASP.NET Core - 基于JwtBearer的身份认证(Authentication)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 在开始之前,如果你还不了解基于Cookie的身份认证,那么建议你先阅读<基于Cookie ...

  9. jQuery.qrcode.js客户端生成二维码,支持中文并且可以生成LOGO

    描述: jquery.qrcode.js 是一个能够在客户端生成矩阵二维码QRCode 的jquery插件 ,使用它可以很方便的在页面上生成二维条码.此插件是能够独立使用的,体积也比较         ...

  10. WebService基于SoapHeader实现安全认证(一)

    本文转载:http://www.cnblogs.com/houleixx/archive/2009/08/22/webservice-soapheader-security.html WebServi ...

随机推荐

  1. dpkt 简单应用

    import dpktfrom dpkt.utils import mac_to_str,inet_to_strcap=f'D:/test_pacp/6.pcap'with open(cap,'rb' ...

  2. ubuntu安装软件报依赖关系错误

    1.环境 Distributor ID: UbuntuDescription: Ubuntu 20.04.1 LTSRelease: 20.04Codename: focal 2.安装 报错 3.解决 ...

  3. api接口基础Day2

    精华笔记: 正则表达式: 用于描述字符串的内容格式,使用它通常用于匹配一个字符串是否符合格式要求 正则表达式的语法:-------------了解.不用纠结.不用深入研究 1.[]:表示一个字符,该字 ...

  4. H5软键盘回车事件

    //软键盘回车事件 document.onkeydown = function (event) { var e = event || window.event; if (e.keyCode === 1 ...

  5. Vue+SSM+Element-Ui实现前后端分离(3)

    前言:经过博文(1)vue搭建,(2)ssm搭建,到这里就该真真切切的实现小功能了<-_-> 规划:实现登录,用户列表查询,访问日志aop; 开始先解决跨域:在目录config/index ...

  6. linux shell 目录

    linux shell 目录 目录 linux shell 目录 类型 unix支持三大主流shell linux支持的shell(可有四种) 部分相关命令 查询进程 ps pstree kill 查 ...

  7. bitmap_find_next_zero_area_off函数

    备注:

  8. VScode好用插件

    1.Anaconda Extension Pack 可以自动补全anaconda包中的属性名称 2.Code Spell Checker 单词拼写检查,非常推荐,有时候会拼错单词,这个不仅可以指出错误 ...

  9. junit单元测试踩过的坑

    1.测试方法不能直接获取到系统初始化的配置信息,需要专门读取 2.单元测试多线程子线程不执行,不会像主线程一样等待子线程退出而退出, 会直接退出. . https://blog.csdn.net/yu ...

  10. Centos 7 .Net core后台守护进程Supervisor教程

    ASP.NET Core应用程序发布linux在shell中运行是正常的.可一但shell关闭网站也就关闭了,所以要配置守护进程, 用的是Supervisor,本文主要记录配置的过程和过程遇到的问题 ...