Kubernetes之ServiceAccount

ServiceAccount

Service Account为Pod中的进程提供身份信息。
当用户访问集群(例如使用kubectl命令)时,apiserver会将用户认证为一个特定的User Account(目前通常是admin,除非系统管理员自定义了集群配置)。Pod 容器中的进程也可以与apiserver联系,当它们在联系apiserver的时候,它们会被认证为一个特定的Service Account(例如default)。

  • User account是为人设计的,而service account则是为Pod中的进程调用Kubernetes API而设计;
  • User account是跨namespace的,而service account则是仅局限它所在的namespace;
  • 每个namespace都会自动创建一个default service account
  • Token controller检测service account的创建,并为它们创建secret
  • 开启ServiceAccount Admission Controller
    • 每个Pod在创建后都会自动设置spec.serviceAccountdefault(除非指定了其他ServiceAccout)
    • 验证Pod引用的service account已经存在,否则拒绝创建
    • 如果Pod没有指定ImagePullSecrets,则把service account的ImagePullSecrets加到Pod中
    • 每个container启动后都会挂载该Service Accounttokenca.crt
      /var/run/secrets/kubernetes.io/serviceaccount/

使用默认的 Service Account 访问 API server

当创建 pod 的时候,如果没有指定一个 service account,系统会自动得在与该pod 相同的 namespace 下为其指派一个default service account。如果获取刚创建的 pod 的原始 json 或 yaml 信息(例如使用kubectl get pods podename -o yaml命令),将看到spec.serviceAccountName字段已经被设置为 default。

1
2
3
4
5
6
7
8
9
10
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
filebeat-ds-hxgdx 1/1 Running 1 34d
filebeat-ds-s466l 1/1 Running 2 34d
myapp-0 1/1 Running 0 3h
myapp-1 1/1 Running 0 3h
myapp-2 1/1 Running 0 4h
myapp-3 1/1 Running 0 4h
pod-vol-demo 2/2 Running 0 2d
redis-5b5d6fbbbd-q8ppz 1/1 Running 1 2d
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master ~]# kubectl get pods/myapp-0 -o yaml |grep "serviceAccountName"
serviceAccountName: default

[root@k8s-master ~]# kubectl describe pods myapp-0
Name: myapp-0
Namespace: default
......
Volumes:
......
default-token-j5pf5:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-j5pf5
Optional: false

从上面可以看到每个Pod无论定义与否都会有个存储卷,这个存储卷为default-token-*** token令牌,这就是service account是为Pod中的进程与apiserver联系提供身份认证信息。通过secret进行定义,由于认证信息属于敏感信息,所以需要保存在secret资源当中,并以存储卷的方式挂载到Pod当中。从而让Pod内运行的应用通过对应的secret中的service account来连接apiserver,并完成认证。每个 namespace 中都有一个默认的叫做 default 的 service account资源。可以使用kubectl get secret命令当前名称空间内的secret,也可以看到对应的default-token。可以使用的预制认证信息让当前名称空间中所有的pod连接至apiserver,从而保证pod与apiserver之间的通信。

1
2
3
[root@k8s-master ~]# kubectl get sa
NAME SECRETS AGE
default 1 50d
1
2
3
4
[root@k8s-master ~]# kubectl get sa -n ingress-nginx  #前期创建的ingress-nginx名称空间也存在这样的serviceaccount
NAME SECRETS AGE
default 1 11d
nginx-ingress-serviceaccount 1 11d
1
2
3
4
5
[root@k8s-master ~]# kubectl get secret
NAME TYPE DATA AGE
default-token-j5pf5 kubernetes.io/service-account-token 3 50d
mysecret Opaque 2 1d
tomcat-ingress-secret kubernetes.io/tls 2 10d
1
2
3
4
[root@k8s-master ~]# kubectl get secret -n ingress-nginx
NAME TYPE DATA AGE
default-token-zl49j kubernetes.io/service-account-token 3 11d
nginx-ingress-serviceaccount-token-mcsf4 kubernetes.io/service-account-token 3 11d

而默认的service account 仅仅只能获取当前Pod自身的相关属性,无法观察到其他名称空间Pod的相关属性信息。如果想要扩展Pod,假设有一个Pod需要用于管理其他Pod或者是其他资源对象(例如dashboard),是无法通过自身的名称空间的default service account进行获取其他Pod的相关属性信息的,此时就需要进行手动创建一个serviceaccount,并在创建Pod时进行定义。那么serviceaccount该如何进行定义呢???实际上,service accout也属于一个k8s资源,如下查看service account的定义方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
[root@k8s-master ~]# kubectl explain sa
KIND: ServiceAccount
VERSION: v1

DESCRIPTION:
ServiceAccount binds together: * a name, understood by users, and perhaps
by peripheral systems, for an identity * a principal that can be
authenticated and authorized * a set of secrets

FIELDS:
apiVersion <string>
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#resources

automountServiceAccountToken <boolean>
AutomountServiceAccountToken indicates whether pods running as this service
account should have an API token automatically mounted. Can be overridden
at the pod level.

imagePullSecrets <[]Object>
ImagePullSecrets is a list of references to secrets in the same namespace
to use for pulling any images in pods that reference this ServiceAccount.
ImagePullSecrets are distinct from Secrets because Secrets can be mounted
in the pod, but ImagePullSecrets are only accessed by the kubelet. More
info:
https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod

kind <string>
Kind is a string value representing the REST resource this object
represents. Servers may infer this from the endpoint the client submits
requests to. Cannot be updated. In CamelCase. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds

metadata <Object>
Standard object's metadata. More info:
https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata

secrets <[]Object>
Secrets is the list of secrets allowed to be used by pods running using
this ServiceAccount. More info:
https://kubernetes.io/docs/concepts/configuration/secret

service account的创建

1
2
3
4
5
6
[root@master-1 app]# vim serviceaccount.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin
namespace: default
1
2
[root@master-1 app]# kubectl apply -f serviceaccount.yaml 
serviceaccount/admin created
1
2
3
4
5
[root@master-1 app]# kubectl get sa
NAME SECRETS AGE
admin 1 31s
default 1 20d
nfs-provisioner 1 18d
1
2
3
4
5
6
[root@master-1 app]# kubectl get secret
NAME TYPE DATA AGE
admin-token-j7n8j kubernetes.io/service-account-token 3 27m
default-token-zmv4x kubernetes.io/service-account-token 3 20d
mysecret Opaque 2 19d
nfs-provisioner-token-xjn7p kubernetes.io/service-account-token 3 18d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@master-1 app]# kubectl get sa admin -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"admin","namespace":"default"}}
creationTimestamp: "2019-02-12T03:07:07Z"
name: admin
namespace: default
resourceVersion: "2606053"
selfLink: /api/v1/namespaces/default/serviceaccounts/admin
uid: 48250903-2e73-11e9-a8c7-d8490b8af3ae
secrets:
- name: admin-token-j7n8j

看到有一个 token 已经被自动创建,只需要在 pod 的spec.serviceAccountName 字段中将name设置为您想要用的 service account 名字即可。在 pod 创建之初 service account 就必须已经存在,否则创建将被拒绝。需要注意的是不能更新已创建的 pod 的 service account。

serviceaccount的自定义使用

这里在default名称空间创建了一个serviceaccount为admin,可以看到已经自动生成了一个Tokens:admin-token-j7n8j,下面展示如何使用自定义的serviceaccount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@master-1 app]# vim pod-sa-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-sa-demo
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
serviceAccountName: admin
1
2
[root@master-1 app]# kubectl apply -f pod-sa-demo.yaml 
pod/pod-sa-demo created
1
2
3
4
5
6
7
8
[root@master-1 app]# kubectl describe pods pod-sa-demo
......
Volumes:
admin-token-j7n8j:
Type: Secret (a volume populated by a Secret)
SecretName: admin-token-j7n8j
Optional: false
......

User Account的定义及使用:

在K8S集群当中,每一个用户对资源的访问都是需要通过apiserver进行通信认证才能进行访问的,那么在此机制当中,对资源的访问可以是token,也可以是通过配置文件的方式进行保存和使用认证信息,kubectl命令行工具使用kubeconfig文件来查找选择群集并与群集的APIserver进行通信。可以通过kubectl config进行查看编辑kubeconfig配置文件,配置文件路径$HOME/.kube/config文件,eg:/root/.kube/config 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@k8s-master mainfests]# kubectl config view
apiVersion: v1
clusters: #集群列表
- cluster:
certificate-authority-data: REDACTED
server: https://192.168.56.11:6443
name: kubernetes
contexts: #上下文列表
- context: #定义哪个集群被哪个用户访问
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes #当前上下文
kind: Config
preferences: {}
users: #用户列表
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED

在上面的配置文件当中,定义了集群、上下文以及用户。其中Config也是K8S的标准资源之一,在该配置文件当中定义了一个集群列表,指定的集群可以有多个;用户列表也可以有多个,指明集群中的用户;而在上下文列表当中,是进行定义可以使用哪个用户对哪个集群进行访问,以及当前使用的上下文是什么。如图:定义了用户kubernetes-admin可以对kubernetes该集群的访问,用户kubernetes-user1对Cluster1集群的访问。

serviceaccount-1

自建证书和账号进行访问apiserver演示

注意:此步骤在/etc/kubernetes/pki路径下执行,因为需要用到Kubernetes CA证书。

(1)生成证书

1
2
3
4
5
[root@k8s-master pki]# (umask 077;openssl genrsa -out magedu.key 2048)
Generating RSA private key, 2048 bit long modulus
............................................................................................+++
...................................................................................+++
e is 65537 (0x10001)
1
2
3
[root@k8s-master pki]# ll magedu.key 
-rw------- 1 root root 1675 Oct 12 23:52 magedu.key

(2)使用ca.crt进行签署

1
[root@k8s-master pki]# openssl req -new -key magedu.key -out magedu.csr -subj "/CN=magedu"  证书签署请求(CN表示用户名,O表示组)
1
2
3
4
[root@k8s-master pki]# openssl x509 -req -in magedu.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out magedu.crt -days 365  #证书签署
Signature ok
subject=/CN=magedu
Getting CA Private Key
1
[root@k8s-master pki]# openssl x509 -in magedu.crt -text -noout

(3)添加到用户认证

1
2
[root@k8s-master pki]# kubectl config set-credentials magedu --client-certificate=./magedu.crt --client-key=./magedu.key --embed-certs=true
User "magedu" set.
1
2
[root@k8s-master pki]# kubectl config set-context magedu@kubernetes --cluster=kubernetes --user=magedu
Context "magedu@kubernetes" created.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@k8s-master pki]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: REDACTED
server: https://192.168.56.11:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
- context:
cluster: kubernetes
user: magedu
name: magedu@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
- name: magedu
user:
client-certificate-data: REDACTED
client-key-data: REDACTED
1
2
[root@k8s-master pki]# kubectl config use-context magedu@kubernetes
Switched to context "magedu@kubernetes".
1
2
3
[root@k8s-master pki]# kubectl get pods
No resources found.
Error from server (Forbidden): pods is forbidden: User "magedu" cannot list pods in the namespace "default"

(4)删除用户

1
2
[root@k8s-master pki]#  kubectl config delete-context yedong@kubernetes
deleted context yedong@kubernetes from /root/.kube/config
1
2
[root@k8s-master pki]# kubectl config unset users.yedong
Property "users.yedong" unset.

从上面的演示,当切换成magedu用户进行访问集群时,由于magedu该账户没有管理集群的权限,所以在获取pods资源信息时,会提示Forrbidden。那么下面就再来了解一下怎么对账户进行授权!!!

kubernetes小技巧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
[root@master-1 pki]# kubectl create --help
Create a resource from a file or from stdin.

JSON and YAML formats are accepted.

Examples:
# Create a pod using the data in pod.json.
kubectl create -f ./pod.json

# Create a pod based on the JSON passed into stdin.
cat pod.json | kubectl create -f -

# Edit the data in docker-registry.yaml in JSON then create the resource using the edited data.
kubectl create -f docker-registry.yaml --edit -o json

Available Commands:
clusterrole Create a ClusterRole.
clusterrolebinding Create a ClusterRoleBinding for a particular ClusterRole
configmap Create a configmap from a local file, directory or literal value
deployment Create a deployment with the specified name.
job Create a job with the specified name.
namespace Create a namespace with the specified name
poddisruptionbudget Create a pod disruption budget with the specified name.
priorityclass Create a priorityclass with the specified name.
quota Create a quota with the specified name.
role Create a role with single rule.
rolebinding Create a RoleBinding for a particular Role or ClusterRole
secret Create a secret using specified subcommand
service Create a service using specified subcommand.
serviceaccount Create a service account with the specified name

Options:
--allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing in
the template. Only applies to golang and jsonpath output formats.
--dry-run=false: If true, only print the object that would be sent, without sending it.
--edit=false: Edit the API resource before creating
-f, --filename=[]: Filename, directory, or URL to files to use to create the resource
-o, --output='': Output format. One of:
json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
--raw='': Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.
--record=false: Record current kubectl command in the resource annotation. If set to false, do not record the
command. If set to true, record the command. If not set, default to updating the existing annotation value only if one
already exists.
-R, --recursive=false: Process the directory used in -f, --filename recursively. Useful when you want to manage
related manifests organized within the same directory.
--save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, the
annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
-l, --selector='': Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
--template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. The
template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
--validate=true: If true, use a schema to validate the input before sending it
--windows-line-endings=false: Only relevant if --edit=true. Defaults to the line ending native to your platform.

Usage:
kubectl create -f FILENAME [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).

注释:只要支持用kubectl create创建的资源都可以用 --dry-run(单跑模式)并不会真正的执行,只会测试是否能创建成功,可以使用 -o yaml 导出配置文件非常方便。


Kubernetes之ServiceAccount
https://system51.github.io/2019/08/26/Kubernetes-ServiceAccount/
作者
Mr.Ye
发布于
2019年8月26日
许可协议