在Kubernetes Pod中使用Service Account访问API Server
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
在Kubernetes Pod中使用Service Account訪(fǎng)問(wèn)API Server 博客分類(lèi): Kubernetes ?Kubernetes API Server是整個(gè)Kubernetes集群的核心,我們不僅有從集群外部訪(fǎng)問(wèn)API Server的需求,有時(shí),我們還需要從Pod的內(nèi)部訪(fǎng)問(wèn)API Server。
然而,在生產(chǎn)環(huán)境中,Kubernetes API Server都是“設(shè)防”的。在《Kubernetes集群的安全配置》一文中,我提到過(guò):Kubernetes通過(guò)client cert、static token、basic auth等方法對(duì)客戶(hù)端請(qǐng)求進(jìn)行身份驗(yàn)證。對(duì)于運(yùn)行于Pod中的Process而言,有些時(shí)候這些方法是適合的,但有些時(shí)候,像client cert、static token或basic auth這些信息是不便于暴露給Pod中的Process的。并且通過(guò)這些方法通過(guò)API Server驗(yàn)證后的請(qǐng)求是具有全部授權(quán)的,可以任意操作Kubernetes cluster,這顯然是不能滿(mǎn)足安全要求的。為此,Kubernetes更推薦大家使用service account這種方案的。本文就帶大家詳細(xì)說(shuō)說(shuō)如何通過(guò)service account從一個(gè)Pod中訪(fǎng)問(wèn)API Server的。
零、試驗(yàn)環(huán)境
本文的試驗(yàn)環(huán)境是Kubernetes 1.3.7 cluster,雙節(jié)點(diǎn),master承載負(fù)荷。cluster通過(guò)kube-up.sh搭建的,具體的搭建方法見(jiàn)《一篇文章帶你了解Kubernetes安裝》。
一、什么是service account?
什么是service account? 顧名思義,相對(duì)于user account(比如:kubectl訪(fǎng)問(wèn)APIServer時(shí)用的就是user account),service account就是Pod中的Process用于訪(fǎng)問(wèn)Kubernetes API的account,它為Pod中的Process提供了一種身份標(biāo)識(shí)。相比于user account的全局性權(quán)限,service account更適合一些輕量級(jí)的task,更聚焦于授權(quán)給某些特定Pod中的Process所使用。
service account作為一種resource存在于Kubernetes cluster中,我們可以通過(guò)kubectl獲取當(dāng)前cluster中的service acount列表:
# kubectl get serviceaccount --all-namespaces NAMESPACE NAME SECRETS AGE default default 1 140d kube-system default 1 140d我們查看一下kube-system namespace下名為”default”的service account的詳細(xì)信息:
# kubectl describe serviceaccount/default -n kube-system Name: default Namespace: kube-system Labels: <none>Image pull secrets: <none>Mountable secrets: default-token-hpni0Tokens: default-token-hpni0我們看到service account并不復(fù)雜,只是關(guān)聯(lián)了一個(gè)secret資源作為token,該token也叫service-account-token,該token才是真正在API Server驗(yàn)證(authentication)環(huán)節(jié)起作用的:
# kubectl get secret -n kube-system NAME TYPE DATA AGE default-token-hpni0 kubernetes.io/service-account-token 3 140d# kubectl get secret default-token-hpni0 -o yaml -n kube-system apiVersion: v1 data:ca.crt: {base64 encoding of ca.crt data}namespace: a3ViZS1zeXN0ZW0=token: {base64 encoding of bearer token}kind: Secret metadata:annotations:kubernetes.io/service-account.name: defaultkubernetes.io/service-account.uid: 90ded7ff-9120-11e6-a0a6-00163e1625a9creationTimestamp: 2016-10-13T08:39:33Zname: default-token-hpni0namespace: kube-systemresourceVersion: "2864"selfLink: /api/v1/namespaces/kube-system/secrets/default-token-hpni0uid: 90e71909-9120-11e6-a0a6-00163e1625a9 type: kubernetes.io/service-account-token我們看到這個(gè)類(lèi)型為service-account-token的secret資源包含的數(shù)據(jù)有三部分:ca.crt、namespace和token。
-  ca.crt 
 這個(gè)是API Server的CA公鑰證書(shū),用于Pod中的Process對(duì)API Server的服務(wù)端數(shù)字證書(shū)進(jìn)行校驗(yàn)時(shí)使用的;
-  namespace 
 這個(gè)就是Secret所在namespace的值的base64編碼:# echo -n “kube-system”|base64 => “a3ViZS1zeXN0ZW0=”
-  token 
這是一段用API Server私鑰簽發(fā)(sign)的bearer tokens的base64編碼,在API Server authenticating環(huán)節(jié),它將派上用場(chǎng)。
二、API Server的service account authentication(身份驗(yàn)證)
前面說(shuō)過(guò),service account為Pod中的Process提供了一種身份標(biāo)識(shí),在Kubernetes的身份校驗(yàn)(authenticating)環(huán)節(jié),以某個(gè)service account提供身份的Pod的用戶(hù)名為:
system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT)以上面那個(gè)kube-system namespace下的“default” service account為例,使用它的Pod的username全稱(chēng)為:
system:serviceaccount:kube-system:default有了username,那么credentials呢?就是上面提到的service-account-token中的token。在《Kubernetes集群的安全配置》一文中我們談到過(guò),API Server的authenticating環(huán)節(jié)支持多種身份校驗(yàn)方式:client cert、bearer token、static password auth等,這些方式中有一種方式通過(guò)authenticating(Kubernetes API Server會(huì)逐個(gè)方式嘗試),那么身份校驗(yàn)就會(huì)通過(guò)。一旦API Server發(fā)現(xiàn)client發(fā)起的request使用的是service account token的方式,API Server就會(huì)自動(dòng)采用signed bearer token方式進(jìn)行身份校驗(yàn)。而request就會(huì)使用攜帶的service account token參與驗(yàn)證。該token是API Server在創(chuàng)建service account時(shí)用API server啟動(dòng)參數(shù):–service-account-key-file的值簽署(sign)生成的。如果–service-account-key-file未傳入任何值,那么將默認(rèn)使用–tls-private-key-file的值,即API Server的私鑰(server.key)。
通過(guò)authenticating后,API Server將根據(jù)Pod username所在的group:system:serviceaccounts和system:serviceaccounts:(NAMESPACE)的權(quán)限對(duì)其進(jìn)行authority?和admission control兩個(gè)環(huán)節(jié)的處理。在這兩個(gè)環(huán)節(jié)中,cluster管理員可以對(duì)service account的權(quán)限進(jìn)行細(xì)化設(shè)置。
三、默認(rèn)的service account
Kubernetes會(huì)為每個(gè)cluster中的namespace自動(dòng)創(chuàng)建一個(gè)默認(rèn)的service account資源,并命名為”default”:
# kubectl get serviceaccount --all-namespaces NAMESPACE NAME SECRETS AGE default default 1 140d kube-system default 1 140d如果Pod中沒(méi)有顯式指定spec.serviceAccount字段值,那么Kubernetes會(huì)將該namespace下的”default” service account自動(dòng)mount到在這個(gè)namespace中創(chuàng)建的Pod里。我們以namespace “default”為例,我們查看一下其中的一個(gè)Pod的信息:
# kubectl describe pod/index-api-2822468404-4oofr Name: index-api-2822468404-4oofr Namespace: default ... ...Containers:index-api:... ...Volume Mounts:/var/run/secrets/kubernetes.io/serviceaccount from default-token-40z0x (ro)Environment Variables: <none> ... ... Volumes: ... ...default-token-40z0x:Type: Secret (a volume populated by a Secret)SecretName: default-token-40z0xQoS Class: BestEffort Tolerations: <none> No events.可以看到,kubernetes將default namespace中的service account “default”的service account token掛載(mount)到了Pod中容器的/var/run/secrets/kubernetes.io/serviceaccount路徑下。
深入容器內(nèi)部,查看mount的serviceaccount路徑下的結(jié)構(gòu):
# docker exec 3d11ee06e0f8 ls /var/run/secrets/kubernetes.io/serviceaccount ca.crt namespace token這三個(gè)文件與上面提到的service account的token中的數(shù)據(jù)是一一對(duì)應(yīng)的。
四、default service account doesn’t work
上面提到過(guò),每個(gè)Pod都會(huì)被自動(dòng)掛載一個(gè)其所在namespace的default service account,該service account用于該P(yáng)od中的Process訪(fǎng)問(wèn)API Server時(shí)使用。Pod中的Process該怎么用這個(gè)service account呢?Kubernetes官方提供了一個(gè)client-go項(xiàng)目可以為你演示如何使用service account訪(fǎng)問(wèn)API Server。這里我們就基于client-go項(xiàng)目中的examples/in-cluster/main.go來(lái)測(cè)試一下是否能成功訪(fǎng)問(wèn)API Server。
先下載client-go源碼:
# go get k8s.io/client-go# ls -F CHANGELOG.md dynamic/ Godeps/ INSTALL.md LICENSE OWNERS plugin/ rest/ third_party/ transport/ vendor/ discovery/ examples/ informers/ kubernetes/ listers/ pkg/ README.md testing/ tools/ util/我們改造一下examples/in-cluster/main.go,考慮到panic會(huì)導(dǎo)致不便于觀察Pod日志,我們將panic改為輸出到“標(biāo)準(zhǔn)輸出”,并且不return,讓Pod周期性的輸出相關(guān)日志,即便fail:
// k8s.io/client-go/examples/in-cluster/main.go ... ... func main() {// creates the in-cluster configconfig, err := rest.InClusterConfig()if err != nil {fmt.Println(err)}// creates the clientsetclientset, err := kubernetes.NewForConfig(config)if err != nil {fmt.Println(err)}for {pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})if err != nil {fmt.Println(err)} else {fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))}time.Sleep(10 * time.Second)} }基于該main.go的go build默認(rèn)輸出,創(chuàng)建一個(gè)簡(jiǎn)單的Dockerfile:
From ubuntu:14.04 MAINTAINER Tony Bai <bigwhite.cn@gmail.com>COPY main /root/main RUN chmod +x /root/main WORKDIR /root ENTRYPOINT ["/root/main"]構(gòu)建一個(gè)測(cè)試用docker image:
# docker build -t k8s/example1:latest . ... ...# docker images|grep k8s k8s/example1 latest ceb3efdb2f91 14 hours ago 264.4 MB創(chuàng)建一份deployment manifest:
//main.yamlapiVersion: extensions/v1beta1 kind: Deployment metadata:name: k8s-example1 spec:replicas: 1template:metadata:labels:run: k8s-example1spec:containers:- name: k8s-example1image: k8s/example1:latestimagePullPolicy: IfNotPresent我們來(lái)創(chuàng)建該deployment(kubectl create -f main.yaml -n kube-system),觀察Pod中的main程序能否成功訪(fǎng)問(wèn)到API Server:
# kubectl logs k8s-example1-1569038391-jfxhx the server has asked for the client to provide credentials (get pods) the server has asked for the client to provide credentials (get pods)API Server log(/var/log/upstart/kube-apiserver.log):E0302 15:45:40.944496 12902 handlers.go:54] Unable to authenticate the request due to an error: crypto/rsa: verification error E0302 15:45:50.946598 12902 handlers.go:54] Unable to authenticate the request due to an error: crypto/rsa: verification error E0302 15:46:00.948398 12902 handlers.go:54] Unable to authenticate the request due to an error: crypto/rsa: verification error出錯(cuò)了!kube-system namespace下的”default” service account似乎不好用啊!(注意:這是在kubernetes 1.3.7環(huán)境)。
五、創(chuàng)建一個(gè)新的自用的service account
在kubernetes github issues中,有好多issue是關(guān)于”default” service account不好用的問(wèn)題,給出的解決方法似乎都是創(chuàng)建一個(gè)新的service account。
service account的創(chuàng)建非常簡(jiǎn)單,我們創(chuàng)建一個(gè)serviceaccount.yaml:
//serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata:name: k8s-example1創(chuàng)建該service account:
# kubectl create -f serviceaccount.yaml serviceaccount "k8s-example1" created# kubectl get serviceaccount NAME SECRETS AGE default 1 139d k8s-example1 1 12s修改main.yaml,讓Pod顯示使用這個(gè)新的service account:
//main.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata:name: k8s-example1 spec:replicas: 1template:metadata:labels:run: k8s-example1spec:serviceAccount: k8s-example1containers:- name: k8s-example1image: k8s/example1:latestimagePullPolicy: IfNotPresent好了,我們重新創(chuàng)建該deployment,查看Pod日志:
# kubectl logs k8s-example1-456041623-rqj87 There are 14 pods in the cluster There are 14 pods in the cluster ... ...我們看到main程序使用新的service account成功通過(guò)了API Server的身份驗(yàn)證環(huán)節(jié),并獲得了cluster的相關(guān)信息。
六、尾聲
在我的另外一個(gè)使用kubeadm安裝的k8s 1.5.1環(huán)境中,我重復(fù)做了上面這個(gè)簡(jiǎn)單測(cè)試,不同的是這次我直接使用了default service account。在k8s 1.5.1下,pod的執(zhí)行結(jié)果是ok的,也就是說(shuō)通過(guò)default serviceaccount,我們的client-go in-cluster example程序可以順利通過(guò)API Server的身份驗(yàn)證,獲取到相關(guān)的Pods元信息。
七、參考資料
- Kubernetes authentication
- Service Accounts
- Accessing the cluster
- Service Accounts Admin
?
http://tonybai.com/2017/03/03/access-api-server-from-a-pod-through-serviceaccount/
轉(zhuǎn)載于:https://my.oschina.net/xiaominmin/blog/1598578
總結(jié)
以上是生活随笔為你收集整理的在Kubernetes Pod中使用Service Account访问API Server的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: Kubernetes应用部署模型解析(原
- 下一篇: org.xml.sax.SAXParse
