前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kubernetes集群的身份验证

Kubernetes集群的身份验证

作者头像
mazhen
发布2023-11-24 15:35:20
2690
发布2023-11-24 15:35:20
举报
文章被收录于专栏:mazhen.techmazhen.tech

用户在访问Kubernetes集群的API server时,访问请求需要经过身份验证、授权和准入控制这三个阶段的检查,才能真正到达API服务,如下图所示:

access-control-overview
access-control-overview

Kubernetes中的用户有两种类型:service accountsnormal usersservice accountsKubernetes管理,它是Pod中的进程用于访问API服务的account,为Pod中的进程提供了一种身份标识。normal users是由外部系统管理,在Kubernetes中并没有对应的 user 对象,它为人类用户使用kubectl之类的工具访问API服务时提供身份标识。所有用户,不管是使用 kubectl、客户端lib、还是直接发起REST请求访问API server,都需要经过上述三个步骤的检查。

本文将介绍Kubernetes集群的身份验证,即Kubernetes如何确认来访者的身份。

Kubernetes支持多种方式的身份验证:客户端证书,Password, Plain Tokens,JWT(JSON Web Token),HTTP basic auth等。你可以同时启用多种认证,一般建议至少使用两种:

  • 为验证normal users身份的客户端证书方式
  • 为验证Service accounts身份的 JWT Tokens方式

使用客户端证书进行身份验证

理解数字证书

非对称加密算法是证书的基础。数字签名、数字证书等一系列概念有点绕,但只要记住:公钥用来加密私钥用来签名 就可以了。

怎么理解呢?公钥可以随意分发,谁都可以持有,如果你用私钥加密,任何持有对应公钥的人都可以解密,这样做和没加密一样,没什么意义。因此,我们需要用公钥加密,只有持有私钥的那个人才能解密。私钥之所以称为私钥,一定会私密保存,不会向其他人泄漏。同时,用私钥加密虽然没有意义,但如果别人用公钥解开了私钥加密的信息,就能够证明信息是由私钥持有者发出的,验证了信息发送者的身份,这就是数字签名。

每个人制作好自己的公钥和私钥,然后把公钥发布出去。两个人如果都有对方的公钥,就可以用对方的公钥给对方发送加密信息,同时附上用私钥加密的信息摘要作为数字签名,证明消息发送者的身份。

通过加密防止了窃听风险,通过数字签名防止了冒充风险,数字签名内的消息摘要防止了篡改风险,一起看似很完美。

等等,这里有个很重要的问题被忽略了:如何安全的将公钥发布出去?如果双方希望安全通信,最好当面交换公钥,以免被别人冒充,并且要保护好自己的电脑,避免公钥被别有用心的人替换。现实中不可能这样分发公钥,效率太低,几乎无法大规模实行。于是出现了CA(certificate authority),为公钥做认证。CA用自己的私钥,对申请用户的公钥和一些身份信息加密,生成"数字证书"(Digital Certificate)。你现在可以用任何方式将内含公钥的数字证书发布出去,例如有客户发起请求,希望以HTTPS的方式访问你的WEB服务,你可以在第一次回复客户的响应中带上数字证书。客户拿到你的数字证书,用CA的公钥解开数字证书,安全的获得你的公钥。有了CA为你的数字证书背书,客户可以确定你的身份,不是有人在冒充你。

那么CA的公钥如何安全的分发呢?首先,证书的签发是“链”式结构,给你签发证书的CA,它的证书可能还是由上一级CA机构签发的,这样一直往上追溯,最终会到某个“根证书”。如果“根证书”是被我们信任的,那么整条“链”上的证书都可信。

certificates in a chain
certificates in a chain

其次,操作系统都内置了“受信任的根证书”。我们拿到某个证书,如果它的根证书在系统的“受信任的根证书”列表中,那么这个证书就是可信的。例如知乎的证书:

zhihu crt
zhihu crt

可以看到,它的根证书是DigiCert Global Root CA,在操作系统的“受信任的根证书”列表中能找到它:

root ca
root ca

根证书是通过预装的方式完成的分发,因此安装来源不明的操作系统有风险,可能潜伏了非法的根证书。一旦被植入了非法的根证书,一整套的安全体系瞬间土崩瓦解。同时,不能随意向系统中添加可信任的根证书,你很难验证根证书的真伪,它已经是root,没人能为它做背书了。12306网站早期的根证书就不在操作系统的“受信任根证书”列表中,需要用户手工安装,在网上引起轩然大波。最终12306在17年底的时候换成了Digicert的证书。

简单总结一下基于非对称加密算法的公钥/私钥体系,公钥用来加密私钥用来签名引入CA保证公钥的安全分发。你可以找CA签发数字证书,那么你的客户就可以根据本地“受信任的根证书”验证你的数字证书,从而确认你的身份,然后用证书内包含的公钥给你发加密的信息。同样,你也可以要求对方的数字证书,以便确认对方的身份,并给他回加密的信息。

理解了数字证书的基本原理,我们再看看Kubernetes中如何使用客户端证书进行身份验证。

数字证书在Kubernetes中的应用

Kubernetes各组件之间的通信都是基于TLS,实现服务的加密访问,同时支持基于证书的双向认证。

我们在搭建私有Kubernetes集群时,一般是自建root CA,因为参与认证的所有集群节点,包括远程访问集群的客户端桌面都完全由自己控制,我们可以安全的将根证书分发到所有节点。有了CA,我们再用CA的私钥/公钥为各个组件签发所需的证书。

CA的创建,以及一系列客户端、服务端证书的签发,实际上是建立了Kubernetes集群的PKI(Public key infrastructure)

Kubernetes中的组件比较多,所以需要的证书会非常多,这篇文档做了介绍。我按证书的用途归类总结一下:

  • CA证书
  • 服务端证书
    • API server
    • etcd
    • kubelet
  • 访问API server时进行身份验证的客户端证书
    • kubelet      -> API server
    • controller-manager -> API server
    • kube-scheduler   -> API server
    • admin用户     -> API server
  • API server 访问其他组件时进行身份验证的客户端证书
    • API server -> etcd
    • API server -> kubelet
    • API server -> aggregated API server
  • etcd 相关功能
    • etcd 集群中节点互相通信使用的客户端证书
    • 如果etcd是以Pod方式运行,针对etcd的 Liveness 需要的客户端证书
  • Service accounts 私钥/公钥对,用于生成Service accounts身份验证的 JWT Tokens

最后一个不是证书,不过也在Kubernetes PKI的管理范围。关于Service accounts 私钥/公钥对的作用,后面会讲到。

理论上CA根证书可以只使用一个,不过为了安全和方便管理,官方强调在不同的上下文最好使用不同的CA

Warning: Do not reuse a CA that is used in a different context unless you understand the risks and the mechanisms to protect the CA’s usage.

可以看出,API server是核心组件,其他组件、包括admin用户对它的访问都需要TLS双向认证,所以会有API server的服务端证书和各个组件的客户端证书。API server作为客户端需要访问etcdkubeletaggregated API server,所以也会有相应的服务端、客户端证书。

当我们使用kubeadm安装Kubernetes时,kubeadm会为我们生成上述的一系列私钥和证书,放在/etc/kubernetes/目录下:

代码语言:javascript
复制
# tree --dirsfirst /etc/kubernetes/
/etc/kubernetes/
├── manifests                         组件的配置文件,以Pod方式运行在集群中
│   ├── etcd.yaml
│   ├── kube-apiserver.yaml
│   ├── kube-controller-manager.yaml  
│   └── kube-scheduler.yaml           
├── pki                               
│   ├── etcd                          
│   │   ├── ca.crt                    etcd 集群CA证书
│   │   ├── ca.key                    etcd 集群CA私钥
│   │   ├── healthcheck-client.crt    Liveness 健康检查使用的客户端证书
│   │   ├── healthcheck-client.key
│   │   ├── peer.crt                  etcd节点间通信使用的客户端证书
│   │   ├── peer.key                  
│   │   ├── server.crt                etcd服务端证书
│   │   └── server.key
│   ├── apiserver.crt                 API Server 服务端证书
│   ├── apiserver.key
│   ├── apiserver-etcd-client.crt     API server -> etcd
│   ├── apiserver-etcd-client.key
│   ├── apiserver-kubelet-client.crt  API server -> kubelet
│   ├── apiserver-kubelet-client.key
│   ├── ca.crt                        CA证书
│   ├── ca.key                        CA私钥
│   ├── front-proxy-ca.crt            aggregation 相关功能CA证书
│   ├── front-proxy-ca.key            aggregation 相关功能CA私钥
│   ├── front-proxy-client.crt        API server -> aggregated API server
│   ├── front-proxy-client.key
│   ├── sa.key                        Service accounts 私钥
│   └── sa.pub                        Service accounts 公钥
├── admin.conf                        admin              -> API server 
├── controller-manager.conf           controller-manager -> API server 
├── kubelet.conf                      kubelet        -> API server 
└── scheduler.conf                    kube-scheduler     -> API server 

注意,最后四个*.confkubeconfig file,内容包含了集群、用户、namespace等信息,还有用来认证的CA证书、客户端证书和私钥。例如admin.conf就是kubectl访问集群用到的kubeconfig file,缺省情况下kubectl会使用$HOME/.kube/config,你也可以通过KUBECONFIG环境变量,或kubectl--kubeconfig 参数进行设置。

kubelet运行在每个工作节点,无法提前预知 nodeIP 信息,所以 kubelet 一般不会明确指定服务端证书, 而是只指定 CA 根证书, 让 kubelet 根据本机信息自动生成服务端证书,保存到配置参数指定的–cert-dir目录中。cert-dir的缺省值是/var/lib/kubelet/pki

代码语言:javascript
复制
# tree /var/lib/kubelet/pki

/var/lib/kubelet/pki
├── kubelet-client-2019-04-28-10-48-13.pem
├── kubelet-client-current.pem -> /var/lib/kubelet/pki/kubelet-client-2019-04-28-10-48-13.pem
├── kubelet.crt   kubelet服务端证书
└── kubelet.key   kubelet服务端私钥

另外,API server有很多认证相关的启动参数,参数名称让人容易混淆,有人还专门提了issue这个回答根据用途对这些参数进行了分类,说明的非常清晰。

API server 如何用客户端证书进行身份验证

前面提到,当用户使用kubectl访问API server时,需要以某种方式进行身份验证,最常用的方式就是使用客户端证书。Kubernetes是没有 user 这种 API 对象,kubectl的用户身份信息就包含在客户端证书中。API server验证了客户端证书,也就可以从证书中获得用户名和所属的group

我们以/etc/kubernetes/admin.conf 为例,看看客户端证书中提供了那些信息。

先查看admin.conf文件的内容:

代码语言:javascript
复制
$ kubectl --kubeconfig /etc/kubernetes/admin.conf  config view

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://172.18.100.90:6443
  name: test
contexts:
- context:
    cluster: test
    user: kubernetes-admin
  name: kubernetes-admin@test
current-context: kubernetes-admin@test
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

这个文件提供了API server的地址,以及身份验证用到的证书:

  • certificate-authority-data :CA证书
  • client-certificate-data :客户端证书
  • client-key-data: 客户端私钥

客户端证书是以base64编码的方式保存在client-certificate-data字段中,我们将证书提取出来:

代码语言:javascript
复制
# cat /etc/kubernetes/admin.conf | grep client-certificate-data | cut -d " " -f 6 | base64 -d > admin.crt
# cat admin.crt

-----BEGIN CERTIFICATE-----
MIIC8jCCAdqgAwIBAgIIaBuxevPYGaswDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0xOTA0MjgwMjQwMDBaFw0yMDA0MjcwMjQwMDNaMDQx
FzAVBgNVBAoTDnN5c3RlbTptYXN0ZXJzMRkwFwYDVQQDExBrdWJlcm5ldGVzLWFk
bWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvRTIQ4YEMh0mUWKP
17pLdUocgZMLVCK6tYmj0DJIihRk+wKvNzYSStfxsug9nnEqVVzmbW5/UxER776H
844y/1NGk/8LsDIkFGspf3cEmQ8OE8TlLNW7h9gWIGymLQ/K1qhYfNOPDYoJXPix
eUWTJgn0+neJNbJ3JoJk2WRlDFwbE0uXgYYczuDcJablSdbb8Oc+E4qJ1U7u9YMN
Bo/JBY68wYtdjXHl6Mg28aCioVZrs5eZWkNzNpXMVjQwFdZAdWbnS3OJGN1b6IrV
gWk9PMoCE2TtFv5NdlHSYFtEAaBEwfl3/D3rGHKb4ZH/fgKWsepy8ffxxibM6pND
pLnmAwIDAQABoycwJTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH
AwIwDQYJKoZIhvcNAQELBQADggEBALPYorv2mlXyu6jpX/6gE1kTvpPGK4vylfSY
9jl4PtQZgRaXvmVsUKpyIdtVhdMZp9EFaYNC4AYkqaVEOoAbU96SYhdO/6h7Rn8T
0Ae+f1Vwt+8GxErEN3xp4noHfXM0eSEuFLPXt43BBJInYRyx1J0urAjYtNCvc9wX
uQFVmNKsqgmjvHQsRkvKcb8HEzcaD1TqqnTpq3usGjNggVZFTChB58R909yGPEXL
n7VsilmN86gom3fgqwCn2C00iKcuzCOwYN2T+Mi8KI2DraDDoVeRMSaYQNUfKNIX
Ngeod/C4piq+OAdyrPPFEINdLi404EYHyod0CgiD6uhoX5W06O4=
-----END CERTIFICATE-----

使用openssl查看证书内容:

代码语言:javascript
复制
# openssl x509 -in ./admin.crt -text

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 7501784745950845355 (0x681bb17af3d819ab)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes
        Validity
            Not Before: Apr 28 02:40:00 2019 GMT
            Not After : Apr 27 02:40:03 2020 GMT
        Subject: O=system:masters, CN=kubernetes-admin
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
......

注意这一行:

代码语言:javascript
复制
Subject: O=system:masters, CN=kubernetes-admin

API server会将证书中CN(Common Name)作为用户名,O(Organization)作为用户所属的groupAPI server从这个证书得到的信息是:admin用户所属的group是system:masters。至此,身份验证阶段完成。

下一步是授权检查,也就是检查用户有没有权限执行这个操作。这是另外一个话题,本文不做详细讨论,只是简单介绍一下。根据官方文档Kubernetes提供了缺省的 ClusterRole - group 绑定关系,已经将system:masters group 和 角色 cluster-admin绑定到了一起:

代码语言:javascript
复制
# kubectl get clusterrolebindings  cluster-admin -o yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2019-04-28T02:40:17Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: cluster-admin
  resourceVersion: "98"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterrolebindings/cluster-admin
  uid: f58a87a7-695e-11e9-91ca-005056ac1c1c
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:masters

这个绑定关系的意思是,属于system:mastersgroup的用户,都拥有cluster-admin角色包含的权限。我们再看看角色cluster-admin的具体权限信息:

代码语言:javascript
复制
# kubectl get clusterrole cluster-admin -o yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2019-04-28T02:40:17Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: cluster-admin
  resourceVersion: "44"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/cluster-admin
  uid: f5523c21-695e-11e9-91ca-005056ac1c1c
rules:
- apiGroups:
  - '*'
  resources:
  - '*'
  verbs:
  - '*'
- nonResourceURLs:
  - '*'
  verbs:
  - '*'

rules列表可以看出,cluster-admin这个角色对所有资源都有无限制的操作权限。因此,使用了这个kubeconfig filekubectl的请求就有了操控和管理整个集群的权限。

使用JWT Tokens进行身份验证

运行在Pod中的进程需要访问API server时,同样需要进行身份验证和授权检查。如何让Pod具有用户身份呢?通过给Pod指定service account来实现。service accountKubernetes内置的一种 “服务账户”,它为Pod中的进程提供了一种身份标识。如果Pod没有显式的指定service account,系统会自动为其关联default service account

我们自己创建service account对象非常简单:

代码语言:javascript
复制
//serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-example

# kubectl apply -f serviceaccount.yaml
serviceaccount/nginx-example created

查看刚刚创建的service account

代码语言:javascript
复制
# kubectl describe serviceaccounts nginx-example

Name:                nginx-example
Namespace:           default
Labels:              <none>
Annotations:         kubectl.kubernetes.io/last-applied-configuration:
                       {"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"nginx-example","namespace":"default"}}
Image pull secrets:  <none>
Mountable secrets:   nginx-example-token-r2cv6
Tokens:              nginx-example-token-r2cv6
Events:              <none>

service account对象创建成功,controller-manager会发现这个新对象,然后为它生成tokentoken实际上是secret对象,内部包含了用来身份验证的tokenservice account对象的Tokens列引用的就是controller-manager为它创建的token

我们来看看token的内容:

代码语言:javascript
复制
# kubectl get secrets nginx-example-token-r2cv6 -o yaml

apiVersion: v1
data:
  ca.crt: (APISERVER'S CA BASE64 ENCODED)
  namespace: ZGVmYXVsdA==
  token: (BEARER TOKEN BASE64 ENCODED)
kind: Secret
metadata:
  ......
type: kubernetes.io/service-account-token

可以看到,这个secret对象的typeservice-account-token,包含了三部分数据:

  • ca.crtAPI ServerCA证书,用于Pod中的进程访问API Server时对服务端证书进行校验
  • namespacesecret所在namespace,使用了base64编码
  • tokenJWT Tokens

JWT Tokenscontroller-managerservice account私钥sa.key签发的,其中包含了用户的身份信息,API Server可以用sa.pub验证token,拿到用户身份信息,从而完成身份验证。

如果是使用kubeadm安装的Kubernetes,我们可以在/etc/kubernetes/manifests/目录中的配置文件确认sa.keysa.pub的作用:

代码语言:javascript
复制
# cat /etc/kubernetes/manifests/kube-controller-manager.yaml
...
spec:
  containers:
  - command:
    - kube-controller-manager
    ...
    - --service-account-private-key-file=/etc/kubernetes/pki/sa.key
...

# cat /etc/kubernetes/manifests/kube-apiserver.yaml
...
spec:
  containers:
  - command:
    - kube-apiserver
    ...
    - --service-account-key-file=/etc/kubernetes/pki/sa.pub
...

controller-manager用私钥sa.key签名,API Server用公钥sa.pub验签。

运行在Pod中的进程在向API server发起HTTP请求时,HTTP header中会携带tokenAPI serverheader中拿到token,进行身份验证:

代码语言:javascript
复制
Authorization: Bearer [token]

JWT Tokens的是由用.分割的三部分组成:

  • Header
  • Payload
  • Signature

因此,一个JWT Tokens看起来是这样的:

代码语言:javascript
复制
xxxxxxx.yyyyyyyy.zzzzzzz

HeaderPayload都是base64编码的JSON,以上面nginx-example关联的token为例,看看HeaderPayload的内容:

代码语言:javascript
复制
$ kubectl describe secrets nginx-example-token-r2cv6 | grep token: | cut -d " " -f 7
eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6Im5naW54LWV4YW1wbGUtdG9rZW4tcjJjdjYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoibmdpbngtZXhhbXBsZSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjBmZWRlOWM1LTc2YjUtMTFlOS05MWNhLTAwNTA1NmFjMWMxYyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0Om5naW54LWV4YW1wbGUifQ.VOjVQBr5PKg1WyZYtIW0Fos5fxFN4cYE3Mz9p1eWbQP6rQRQGDEiGX-LBuM6ECI9cpSL-F4nYQAL9vmIlA4vbAgS4OFgC4nwu8SzLu2FVeE7RDpguvsdAsj-4T_LxEGX1RPljGTpvlt8HRjTnp9K8W4dy7PyJQEB5XvCf-IVNAs3zESgmuJ7wJwO7mXQe5WdeqhI5vXjcZiXP97oH0VRYT1vTKVP-GooC5YfaNhU7rHoJ0gmR10xNqZjwKGsHKkq5maC5BOrXFLlHRqVRwm9-hRn-ZLgAoCwujCIpLvPaFUR8HaatzX4GQ_HWev2soJnk1qcav0smxfjC-fu540vZA

$ kubectl describe secrets nginx-example-token-r2cv6 | grep token: | cut -d " " -f 7 | cut -d "." -f 1 | base64 -d | python -mjson.tool
{
    "alg": "RS256",
    "kid": ""
}

$ kubectl describe secrets nginx-example-token-r2cv6 | grep token: | cut -d " " -f 7 | cut -d "." -f 2 | base64 -d | python -mjson.tool
{
    "iss": "kubernetes/serviceaccount",
    "kubernetes.io/serviceaccount/namespace": "default",
    "kubernetes.io/serviceaccount/secret.name": "nginx-example-token-r2cv6",
    "kubernetes.io/serviceaccount/service-account.name": "nginx-example",
    "kubernetes.io/serviceaccount/service-account.uid": "0fede9c5-76b5-11e9-91ca-005056ac1c1c",
    "sub": "system:serviceaccount:default:nginx-example"
}

Header中的alg指明了签名用到的加密算法,Payload 中包含了用户的身份信息,可以知道这个service account属于的namespacedefault,名称为nginx-example

第三部分Signature的构造方式如下,如果加密算法选择了PKCS SHA:

代码语言:javascript
复制
PKCSSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

controller-managersa.key签名,API Server用公钥sa.pub验签,进行身份验证。

如果先深入了解JWT(JSON Web Token),建议阅读这篇文档<JWT: The Complete Guide to JSON Web Tokens>

Pod中的进程如何获得这个token呢?Kubernetes在创建Pod时,会将service account token映射到Pod/var/run/secrets/kubernetes.io/serviceaccount 目录下。我们通过一个例子演示一下。

创建Pod

代码语言:javascript
复制
// simple.yaml
apiVersion: v1
kind: Pod
metadata:
    name: firstpod
spec:
    serviceAccountName: nginx-example
    containers:
    - image: nginx
      name: stan

$ kubectl apply -f simple.yaml
pod/firstpod created

查看Pod/var/run/secrets/kubernetes.io/serviceaccount目录的内容:

代码语言:javascript
复制
$ kubectl exec firstpod -- ls  /var/run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token

查看Pod内文件/var/run/secrets/kubernetes.io/serviceaccount/token的内容:

代码语言:javascript
复制
$ kubectl exec firstpod -- cat  /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d "." -f 2 | base64 -d | python -mjson.tool
{
    "iss": "kubernetes/serviceaccount",
    "kubernetes.io/serviceaccount/namespace": "default",
    "kubernetes.io/serviceaccount/secret.name": "nginx-example-token-r2cv6",
    "kubernetes.io/serviceaccount/service-account.name": "nginx-example",
    "kubernetes.io/serviceaccount/service-account.uid": "0fede9c5-76b5-11e9-91ca-005056ac1c1c",
    "sub": "system:serviceaccount:default:nginx-example"
}

可以看到,映射进Pod中的token,正是我们在配置中通过serviceAccountName指定的nginx-examplePod中的进程可以通过访问文件/var/run/secrets/kubernetes.io/serviceaccount/token拿到token

如何为service account授权?通过定义service accountrole的绑定完成。本文简单演示一下,详细的说明参加官方文档

创建role

代码语言:javascript
复制
// example-role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: example-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

$ kubectl apply -f example-role.yaml
role.rbac.authorization.k8s.io/example-role created

role可以理解为一组权限的集合,例如上面创建的example-roledefault Namesapce内的Podsgetwatchlist操作权限。

下一步就是将service accountrole进行绑定:

代码语言:javascript
复制
//example-rolebinding.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: example-rolebinding
  namespace: default
subjects:
- kind: ServiceAccount
  name: nginx-example
  namespace: default
roleRef:
  kind: Role
  name: example-role
  apiGroup: rbac.authorization.k8s.io

$ kubectl apply -f example-rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/example-rolebinding created

通过绑定的创建,service account就拥有了role定义的权限。

总结

用户对API server的访问需要通过身份验证、授权和准入控制这三个阶段的检查。

一般集群外部用户访问API Server使用客户端证书进行身份验证。Kubernetes各组件之间的通信都使用了TLS加密传输,同时支持基于证书的双向认证。因此Kubernetes的安装过程涉及很多证书的创建,本文分类介绍了这些证书的作用。

集群内Pod中的进程访问API server时,使用service account关联的token进行身份验证。

每个Pod都会关联一个service account,没有明确指定时使用default。当我们创建service account对象,controller-manager会为这个service account生成Secret,内部包含了用来身份验证的JWT TokensKubernetes会将token文件mountPod/var/run/secrets/kubernetes.io/serviceaccount/tokenPod内的进程在向API server发起的HTTP时,就可以在请求头中携带这个token

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-05-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用客户端证书进行身份验证
    • 理解数字证书
      • 数字证书在Kubernetes中的应用
        • API server 如何用客户端证书进行身份验证
        • 使用JWT Tokens进行身份验证
        • 总结
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档