欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Kubernetes中的service account

程序员文章站 2022-03-07 13:29:12
...

service account,顾名思义,主要是给service使用的一个账号。

具体一点,就是为了让Pod中的进程、服务能访问k8s集群而提出的一个概念,基于service account,pod中的进程、服务能获取到一个username和令牌Token,从而调用kubernetes集群的api server。

kubernetes中,每个命名空间默认会有一个名为“default”的service accout,如:

#其中k8s-example1是之前手工创建的一个service account
$kubectl get serviceAccount --namespace=default
NAME           SECRETS   AGE
default        1         23h
k8s-example1   1         31m

service account中最主要的内容是一个secret资源,其中包含了认证所需的token、根CA等。

$kubectl get serviceAccount default --output=yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2019-02-14T10:03:21Z"
  name: default
  namespace: default
  resourceVersion: "325"
  selfLink: /api/v1/namespaces/default/serviceaccounts/default
  uid: c2b7b49b-303f-11e9-91a6-0800274138bb
secrets:
- name: default-token-bwq8p


#default-token-bwq8p 中的内容如下
$kubectl get secret default-token-bwq8p --output=yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwdGFXNXAKYTNWaVpVTkJNQjRYRFRFNU1ESXhNekE0TlRNd01sb1hEVEk1TURJeE1UQTROVE13TWxvd0ZURVRNQkVHQTFVRQpBeE1LYldsdWFXdDFZbVZEUVRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTlRnCnNhTzk3bVk0ekpmU3dZcSs0eG94L0pRZ3dyMm9hSkNiMkg5dG9EcVRLcXNLb1FJMWpnQ3IwU0NvYlZXN2VHR2cKUTVRU2w5MFBNbmxiUGFldjUvZkM5b0xHcVFZTlgzSTJjUGxINFo2ODVCZ1hDMGdseDFqRVgyNlBINEFtQjk4WQpTZXpSWitoc2pPclNJQnFvSHRLZDJPdzdzcTFCYjBBZlBLZVJPSFZRK2UyUDZIK0VJVkZXSmxXbUhPeGIxbFJ0CmVrV3pPYlVCVlVQNlltYTZqWEw1VmNndlUwSWRGQkNPRFJ2K0N3TWhaOFRoemxwVWhaTW1nZlNKbUJyT3VJcTIKOGw0RFV1TE5ZU0diTkhnTG9GTTA2c1AybVNrN01NdmN4c1hRVzBENmJXcU9UdlZhNGhodXJrbExjOXpRa1dNcgpra1I0WFBEeVpIZmlZanJoWi9jQ0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUIwR0ExVWRKUVFXCk1CUUdDQ3NHQVFVRkJ3TUNCZ2dyQmdFRkJRY0RBVEFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFEUEtZMkxDSzR6S0loRmtLWkpwY1UrZ0o3NzVSYWxDSzFnSWN1NnZBdWpmV3V0RWRTeApJZ2I3VmgyWEVYR0JOQ2VuRGpTUVNvRVREVG5tNS9sVWV6WFZERzlPVlo1Tng5RGllbG9XQmE3M1FtTldPTFdtCktsY083YWRkMDNocFFNY0dnamNoTjJxSEhkaVdxOEZPVUErK1ZGWG9VN2JpbXV0aFhsRGRTSW9uMStjS0V3b1oKanFIb1UxL1I4dkdWVjRvYWRIbDZudkt1Tk4xNHNlUmdLeS9QVlg4disyZXlEdjJNZXJ5SVdrQ3J4UFhqenBCUwpwSkhIZitlUU9VZXIwYmxwL2dhT1VRdGhqalVMQnk1U3lQT1lsa29ybG9rcE1zN2JUeFJkM2tEcXVWMWxnL2FzCk9XU2VhcnNPNkI3ejlZT1lWeVgzVGtrbHBwQlpoVXhSeTFEVAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
  namespace: ZGVmYXVsdA==
  token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklpSjkuZXlKcGMzTWlPaUpyZFdKbGNtNWxkR1Z6TDNObGNuWnBZMlZoWTJOdmRXNTBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5dVlXMWxjM0JoWTJVaU9pSmtaV1poZFd4MElpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WldOeVpYUXVibUZ0WlNJNkltUmxabUYxYkhRdGRHOXJaVzR0WW5keE9IQWlMQ0pyZFdKbGNtNWxkR1Z6TG1sdkwzTmxjblpwWTJWaFkyTnZkVzUwTDNObGNuWnBZMlV0WVdOamIzVnVkQzV1WVcxbElqb2laR1ZtWVhWc2RDSXNJbXQxWW1WeWJtVjBaWE11YVc4dmMyVnlkbWxqWldGalkyOTFiblF2YzJWeWRtbGpaUzFoWTJOdmRXNTBMblZwWkNJNkltTXlZamRpTkRsaUxUTXdNMll0TVRGbE9TMDVNV0UyTFRBNE1EQXlOelF4TXpoaVlpSXNJbk4xWWlJNkluTjVjM1JsYlRwelpYSjJhV05sWVdOamIzVnVkRHBrWldaaGRXeDBPbVJsWm1GMWJIUWlmUS5ua0tMTGItemhlYldibjcxVWJ3WkhjWnJTRHN4eFc2UjRVUTJCMHZCQTZrSWJWeVJWaHpOSkZNaFc0UGxNZkdPUTJJSEswR3Z3RjFfb1RkRFJFX2d4aW93d0VUQUtwZXZZcWFKcGtpV2tzanJVMjdOejNTOW56LVBUS2RlbHI3UFpJVF9rS2dJVGwwbmlQT1pJYXV4eWlidTlneFBkRlBYbGdXN3hTQW9KWURsTnVZdXNGcmo5d0lMaDQxYjVTbFl5VjNlQlhudGJfTVdVeFFXcVdzbmxiOHpVWmZvaER0dGRnNTN3SjFFZGUyaEZDZGxETmtfZGlGcW5jZVpNa1FmNHhBUEhFc3VKVjVzU3dRTGE5MEhwY0lXQXpJcDJmcmx3SnRVWTF6V25wUnc5VXRxLXI1RC10SVZlQ2pMNUFCYlFybTFlcU9ZVzB2V2JjOG8tVklRSVE=
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: default
    kubernetes.io/service-account.uid: c2b7b49b-303f-11e9-91a6-0800274138bb
  creationTimestamp: "2019-02-14T10:03:21Z"
  name: default-token-bwq8p
  namespace: default
  resourceVersion: "322"
  selfLink: /api/v1/namespaces/default/secrets/default-token-bwq8p
  uid: c2be7873-303f-11e9-91a6-0800274138bb
type: kubernetes.io/service-account-token

其中data字段下包含三部分内容,都是base64编码后的内容。

ca.crt: 集群api server使用的根CA,基于该CA会签发一系列的服务端证书、客户端证书等。

namespace: service account的名称,base64 解码之后,可以看到就是 “default”

token: 认证用的令牌Token

认证用的用户名默认为:

system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT)

 

大致机制介绍完了,很自然会有一个问题:

Pod中的进程、服务从什么地方去获取service account中包含的secret数据????

 

这个是kubernetes在启动一个Pod的过程中,“自动”注入到Pod下的所有容器中的。

pod的manifest文件和service account的manifest文件中都有一个配置字段:

automountServiceAccountToken: false/true

来控制是否自动注入。

注入的具体位置可以查看一个pod的manifest文件,比如:

$kubectl get pod security-context-demo --output=yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"security-context-demo","namespace":"default"},"spec":{"containers":[{"image":"gcr.io/google-samples/node-hello:1.0","name":"sec-ctx-demo","securityContext":{"allowPrivilegeEscalation":false},"volumeMounts":[{"mountPath":"/data/demo","name":"sec-ctx-vol"}]}],"securityContext":{"fsGroup":20000,"runAsUser":8000},"volumes":[{"emptyDir":{},"name":"sec-ctx-vol"}]}}
  creationTimestamp: "2019-02-15T08:37:10Z"
  name: security-context-demo
  namespace: default
  resourceVersion: "23058"
  selfLink: /api/v1/namespaces/default/pods/security-context-demo
  uid: e28423a0-30fc-11e9-91a6-0800274138bb
spec:
  containers:
  - image: gcr.io/google-samples/node-hello:1.0
    imagePullPolicy: IfNotPresent
    name: sec-ctx-demo
    resources: {}
    securityContext:
      allowPrivilegeEscalation: false
      procMount: Default
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /data/demo
      name: sec-ctx-vol
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-bwq8p
      readOnly: true

最后的mountPath中:mountPath: /var/run/secrets/kubernetes.io/serviceaccount

可以登陆到该container中验证具体注入的文件。

 

这块儿没理解的一点是:为什么会有这种需求??为什么pod中的进程、服务要访问kubernetes集群??

一般理解,pod中承载的都是一些业务需求,不应该理会平台层的东西。

 

走到这一步,可能都想试一下,怎么在pod中访问kubernetes集群的服务,这个可以参考 client-go,

mac上安装golang语言后,拉一下代码

go get k8s.io/client-go

 

具体的代码位置:go/src/k8s.io/client-go/examples/in-cluster-client-configuration,同目录下自带了一个Dockerfile文件,方便打包image

 

// Note: the example only works with the code within the same release/branch.
package main

import (
	"fmt"
	"time"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	//
	// Uncomment to load all auth plugins
	// _ "k8s.io/client-go/plugin/pkg/client/auth
	//
	// Or uncomment to load specific auth plugins
	// _ "k8s.io/client-go/plugin/pkg/client/auth/azure"
	// _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
	// _ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
	// _ "k8s.io/client-go/plugin/pkg/client/auth/openstack"
)

func main() {
	// creates the in-cluster config
	config, err := rest.InClusterConfig()
	if err != nil {
		panic(err.Error())
	}
	// creates the clientset
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}
	for {
		pods, err := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
		if err != nil {
			panic(err.Error())
		}
		fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))

		// Examples for error handling:
		// - Use helper functions like e.g. errors.IsNotFound()
		// - And/or cast to StatusError and use its properties like e.g. ErrStatus.Message
		_, err = clientset.CoreV1().Pods("default").Get("example-xxxxx", metav1.GetOptions{})
		if errors.IsNotFound(err) {
			fmt.Printf("Pod not found\n")
		} else if statusError, isStatus := err.(*errors.StatusError); isStatus {
			fmt.Printf("Error getting pod %v\n", statusError.ErrStatus.Message)
		} else if err != nil {
			panic(err.Error())
		} else {
			fmt.Printf("Found pod\n")
		}

		time.Sleep(10 * time.Second)
	}
}

 

相关标签: kubernetes