Kubernetes安全

安全永远是一个重大的话题,特别是云计算平台,更需要设计出一套完善的安全方案,以应对复杂的场景。 Kubernetes主要使用Docker作为应用承载环境,Kubernetes首先设计出一套API和敏感信息处理方案,当然也基于Docker提供容器安全控制。以下是Kubernetes的安全设计原则:

1. 保证容器与其运行的宿主机之间有明确的隔离

2. 限制容器对基础设施或者其它容器造成不良影响的能力

3. 最小特权原则——限定每个组件只被赋予了执行操作所必需的最小特权,由此确保可能产生的损失达到最小

4. 允许系统用户明确区别于管理员

5. 允许赋予管理权限给用户

6. 允许应用能够从公开数据中提取敏感信息(keys, certs, passwords)

一、 Kubernetes API Server简介

Kubernetes API Server通过一个名为kube-apiserver的进程提供服务,该进程运行在Master节点上。在默认情况下,kube-apiserver进程在本机的8080端口(--insecure-port)提供REST服务。我们可以同时启动HTTPS安全端口(--secure=6443)来启动安全机制,加强REST API访问的安全性。

1、REST调用

通常我们使用kubectl来与Kubernetes API Server交互,它们之间的接口是REST调用。也可以使用curl命令行工具进行快速验证。

2、编程的方式调用

另外是通过编程的方式调用Kubernetes API Server 具体又细分为以下两种场景:

1.     运行在POD里的进程调用Server API. Pod中的进程如何指定API Server的访问地址呢?答案很简单,因为Kubernetes API Server本身也是一个Service,它的名字是“kubernetes”,IP地址是ClusterIP地址池里面的第一个地址。服务端口是HTTPS端口443.

2.       开发基于Kubernetes的管理平台,比如调用Kubernetes API来完成Pod,Service,RC等资源对象的图形化创建和管理界面。可采用社区中相关的Client Library.

正常情况下,为了确保Kubernetes集群的安全,API Server都会对客户端进行身份认证,认证失败则无法调用API。此外,Pod中访问Kubernetes API Server服务的时候,是以Service方式访问服务名为kubernetes的这个服务,而kubernetes服务又只在HTTPS 443上提供服务,那么如何进行身份认证呢? 答案是 Service Account Token.

二、 apiServer的 Authentication & Authorization

Kubernetes集群中所有资源的访问和变更都是通过Kubernetes API Server的REST API来实现的,所以集群安全的关键点在于识别认证客户端身份(Authentication)以及访问权限的授权(Authorization)。

  • Authentication
    支持Client certificate authentication 、Token authentication 、Basic authentication集中方式。
  • Authorization
    在Authentication的基础上,Authorization可以对HTTP请求设置AlwaysDeny、AlwaysAllow、ABAC三种模式模式,其中ABAC可以设置不同用户的访问权限。

API Server认证 Authentication

Kubernetes提供管理三种级别的客户端身份认证方式:

  1. 最严格的HTTPS证书认证:基于CA根证书签名的双向数字证书认证方式;
  2. HTTP Token认证:通过一个Token来识别合法用户;
  3. HTTP Base认证:通过用户名+密码的方式认证;

HTTPS证书认证:

  1. HTTPS通信双方的务器端向CA机构申请证书,CA机构是可信的第三方机构,它可以是一个公认的权威的企业,也可以是企业自身。 企业内部系统一般都使用企业自身的认证系统。CA机构下发根证书、服务端证书及私钥给申请者
  2. HTTPS通信双方的客户端向CA机构申请证书,CA机构下发根证书、客户端证书及私钥个申请者;
  3. 客户端向服务器端发起请求,服务端下发服务端证书给客户端。客户端接收到证书后,通过私钥解密证书,并利用服务器端证书中的公钥认证证书信息比较证书里的消息,例如域名和公钥与服务器刚刚发送的相关消息是否一致,如果一致,则客户端认为这个服务器的合法身份;
  4. 客户端发送客户端证书给服务器端,服务端接收到证书后,通过私钥解密证书,获得客户端的证书公钥,并用该公钥认证证书信息,确认客户端是否合法;
  5. 客户端通过随机秘钥加密信息,并发送加密后的信息给服务端。服务器端和客户端协商好加密方案后,客户端会产生一个随机的秘钥,客户端通过协商好的加密方案,加密该随机秘钥,并发送该随机秘钥到服务器端。服务器端接收这个秘钥后,双方通信的所有内容都都通过该随机秘钥加密;

CA认证流程图:

上述是双向SSL协议的具体通信过程,这种情况要求服务器和用户双方都有证书。单向认证SSL协议不需要客户拥有CA证书,对应上面的步骤,只需将服务器端验证客户端证书的过程去掉,以及在协商对称密码方案和对称通话秘钥时,服务器端发送给客户端的是没有加过密的(这并不影响SSL过程的安全性)密码方案。

HTTP Token原理:

HTTP Token的认证是用一个很长的特殊编码方式的并且难以被模仿的字符串——Token来表明客户身份的一种方式。在通常情况下,Token是一个复杂的字符串,比如我们用私钥签名一个字符串的数据就可以作为一个Token,此外每个Token对应一个用户名,存储在API Server能访问的一个文件中。当客户端发起API调用请求时,需要在HTTP Header里放入Token,这样一来API Server就能够识别合法用户和非法用户了。

HTTP Base:

常见的客户端账号登录程序,这种认证方式是把“用户名+冒号+密码”用BASE64算法进行编码后的字符串放在HTTP REQUEST中的Header Authorization域里发送给服务端,服务端收到后进行解码,获取用户名及密码,然后进行用户身份的鉴权过程。

现在使用Basic authentication + ABAC model设置API server,

首先配置Basic authentication,设置用户密码,格式为每行password, user name, user id,

basic_auth.csv:

admin_passwd,admin,admin
test_passwd,test,test                       

然后配置ABAC访问策略, 设置admin具有任何权限,test用户只能访问pods,

policy_file.jsonl:

{"user":"admin"}
{"user":"test", "resource": "pods", "readonly": true}

访问策略配置详情参考:

https://github.com/kubernetes/ ... rithm

然后启动API Server:

$kube-apiserver
...
--basic-auth-file=basic_auth.csv \
--authorization-mode=ABAC --authorization-policy-file=policy_file.jsonl

访问API,可以看到test用户无法访问Pod之外的资源:

$ curl --basic -u admin:admin_passwd https://192.168.3.146:6443/api/v1/pods -k
[
...
]

$ curl --basic -u test:test_passwd https://192.168.3.146:6443/api/v1/pods -k
[
...
]

$ curl --basic -u test:test_passwd https://192.168.3.146:6443/api/v1/nodes -k
Forbidden: "/api/v1/nodes"

API Server授权Authorization

对合法用户进行授权(Authorization)并且随后在用户访问时进行鉴权,是权限与安全系统的重要一环。授权就是授予不同用户不同访问权限,API Server目前支持一下集中授权策略:

  • AlwaysDeny:拒绝所有请求,该配置一般用于测试;
  • AlwaysAllow:接收所有请求,如果集群不需要授权流程,可以采用该策略,此为Kubernetes默认的策略;
  • ABAC:(Attribute-Base Access Control)为基于属性的访问控制,表示使用用户配置的授权规则去匹配用户的请求;

为了简化授权的复杂度,对于ABAC模式的授权策略,Kubernetes仅有下面四个基本属性:

  1. 用户名(代表一个已经被认证的用户的字符型用户名)
  2. 是否是只读请求(REST的GET操作是只读的)
  3. 被访问的是哪一类资源,例如Pod资源/api/v1/namespaces/default/pods
  4. 被访问对象所属的Namespace

当API Server启用ABAC模式时,需要指定授权文件的路径和名字(--authorization_policy_file=SOME_FILENAME),授权策略文件里的每一行都是一个Map类型的JOSN对象,被称为访问策略对象,我们可以通过设置“访问策略对象”中的如下属性来确定具体的授权行为:

  • user:字符串类型,来源于Token文件或基本认证文件中的用户名字段的值;
  • readonly:true时表示该策略允许GET请求通过;
  • resource:来自于URL的资源,例如“Pod”;
  • namespace:表明该策略允许访问某个namespace的资源;

eg:

  • {"user":"alice"}
  • {"user":"kubelet","resource":"Pods","readonly":true}
  • {"user":"kubelet","resource":"events"}
  • {"user":"bob","resource":"Pods","readonly":true,"ns":"myNamespace"}

三、Admission Controllers

在认证和授权之外,Admission Controller也可以对Kubernetes API Server的访问控制,任何请求在访问API Server时需要经过一系列的验证,任何一环拒绝了请求,则会返回错误。

实际上Admission Controller是作为Kubernetes API Serve的一部分,并以插件代码的形式存在,在API Server启动的时候,可以配置需要哪些Admission Controller,以及它们的顺序,如:

--admission_control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota

Admission Controller支持的插件如下:
  • AlwaysAdmit:允许所有请求;
  • AlwaysPullmages:在启动容器之前总去下载镜像,相当于在每个容器的配置项imagePullPolicy=Always
  • AlwaysDeny:禁止所有请求,一般用于测试;
  • DenyExecOnPrivileged:它会拦截所有想在Privileged Container上执行命令的请求,如果你的集群支持Privileged Container,你又希望限制用户在这些Privileged Container上执行命令,强烈推荐你使用它;
  • Service Account:这个plug-in将ServiceAccount实现了自动化,默认启用,如果你想使用ServiceAccount对象,那么强烈你推荐使用它;
  • SecurityContextDeny:这个插件将使用SecurityContext的Pod中的定义全部失效。SecurityContext在Container中定义了操作系统级别的安全设定(uid,gid,capabilityes,SELinux等)
  • ResourceQuota:用于配额管理目的,作用于namespace上,它会观察所有请求,确保在namespace上的配额不会超标。推荐在Admission Control参数列表中这个插件排最后一个;
  • LimitRanger:用于配额管理,作用于Pod与Container,确保Pod与Container上的配额不会超标;
  • NamespaceExists(已过时):对所有请求校验namespace是否已存在,如果不存在则拒绝请求,已合并至NamespaceLifecycle。
  •  NamespaceAutoProvision(已过时):对所有请求校验namespace,如果不存在则自动创建该namespace,推荐使用NamespaceLifecycle。
  • NamespaceLifecycle:如果尝试在一个不存在的namespace中创建资源对象,则该创建请求将被拒绝。当删除一个namespace时,系统将会删除该namespace中所有对象,保存Pod,Service等。

在API Server上设置--admission-control参数,即可定制我们需要的准入控制链,如果启用多种准入控制选项,则建议的设置如下:

  • --admission-control=NamespaceLifecycle,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota

下面着重介绍三个准入控制器:

SecurityContextDeny

Security Context时运用于容器的操作系统安全设置(uid、gid、capabilities、SELinux role等),Admission Control的SecurityContextDeny插件的作用是,禁止创建设置了Security Context的Pod,例如包含以下配置项的Pod:

  • spec.containers.securityContext.seLinuxOptions
  • spec.containers.securityContext.runAsUser

ResourceQuota

ResourceQuota不仅能够限制某个Namespace中创建资源的数量,而且能够限制某个namespace中被Pod所请求的资源总量。该准入控制器和资源对象ResourceQuota一起实现了资源的配额管理;

LimitRanger

准入控制器LimitRanger的作用类似于上面的ResourceQuota控制器,这对Namespace资源的每个个体的资源配额。该插件和资源对象LimitRange一起实现资源限制管理。

四、ServiceAccount

4.1、什么是service account?

什么是service account? 顾名思义,相对于user account(比如:kubectl访问APIServer时用的就是user account),service account就是Pod中的Process用于访问Kubernetes API的account,它为Pod中的Process提供了一种身份标识。相比于user account的全局性权限,service account更适合一些轻量级的task,更聚焦于授权给某些特定Pod中的Process所使用。

Service Account概念的引入是基于这样的使用场景: 运行在pod里的进程需要调用Kubernetes API以及非Kubernetes API的其它服务(如image repository/被mount到pod上的NFS volumes中的file等) 。我们使用Service Account来为pod提供id。

Service Account和User account可能会带来一定程度上的混淆,User account可以认为是与Kubernetes交互的个体,通常可以认为是human, 目前并不作为一个代码中的类型单独出现,比如第一节中配置的用户,它们的区别如下。

Kubernetes有User Account和Service Account两套独立的账号系统:

1.User Account是给人用的,Service Account 是给Pod 里的进程使用的,面向的对象不同。

2.User Account是全局性的,即跨namespace使用。 Service Account 是属于某个具体的Namespace,即仅在所属的namespace下使用。

3.User Account是与后端的用户数据库同步的。创建一个新的user account通常需要较高的特权并且需要经过比较复杂的business process(即对于集群的访问权限的创建),而service account则不然。

如果kubernetes开启了ServiceAccount(–admission_control=…,ServiceAccount,… )那么会在每个namespace下面都会创建一个默认的default的ServiceAccount。即service account作为一种resource存在于Kubernetes cluster中,我们可以通过kubectl获取

1、当前cluster中的service acount列表:

kubectl get serviceaccount --all-namespaces

2、service account的详细信息

我们查看一下kube-system namespace下名为”default”的service account的详细信息:

kubectl describe serviceaccount/default -n kube-system

我们看到service account并不复杂,只是关联了一个secret资源作为token,该token也叫service-account-token,该token才是真正在API Server验证(authentication)环节起作用的。

3、查看系统的secret 的token列表:

[root@k8s-master k8s-kube-scheduler]# kubectl get secret  -n kube-system

NAME                  TYPE                                  DATA      AGE

coredns-token-cdn9x   kubernetes.io/service-account-token   2         1h

default-token-lht2v   kubernetes.io/service-account-token   2         1h

[root@k8s-master k8s-kube-scheduler]# kubectl get secret

NAME                  TYPE                                  DATA      AGE

db-user-pass          Opaque                                0         18d

default-token-k7jfg   kubernetes.io/service-account-token   2         1h

registry-key-secret   kubernetes.io/dockerconfigjson        1         18d

4、查看系统的secret  详细:

我们看到这个类型为service-account-token的secret资源包含的数据有三部分:namespace和token。

  • namespace:这个就是Secret所在namespace的值的base64编码:# echo -n “kube-system”|base64 => “a3ViZS1zeXN0ZW0=”

  • token:这是一段用API Server私钥签发(sign)的bearer tokens的base64编码,在API Server authenticating环节,它将派上用场。

5、获取原始token:

获取对应sa的secret从中获取token。并进行base64解码。

kubectl get secret default-token-lht2v  -n kube-system  -o jsonpath={".data.token"} | base64 -d

6、使用token 请求apiserver:

获取对应sa的secret从中获取token。并进行base64解码。

curl -k -H 'Authorization: Bearer token' https://111.111.111.111:6443

curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkZWZhdWx0LXRva2VuLWxodDJ2Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImRlZmF1bHQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI2MDg2MmMxMS04ZTgzLTExZTktYjY2YS0wMDUwNTZiMTIzYjEiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06ZGVmYXVsdCJ9.SCn9sq6i4t4fLPW7kuTe3VfoQUO_iXY6M6vKjR40wqPDFJll5-F9n92iY0DqpBAs-vTWeZDmUuevjSJYeRzJlQmMzw5tZj4CIXZ_LHdiiW4kwmAWiproDE-nAXjF4vKHKkWsGLwpeHOQ2F2pCMIibQkk60ZudlJb_qszoTQvt2NgkUmh-DxwEy6uj6pc-j14s--qNSrValkPIoZV7u2zmPEXzC9sFjADKnqUJ4GCtSS3VIVfqUZvSecWB95f-VIBnQwKJAcOvN7Nspk8Vjp0zW3CAWTmiPm_1AHqIuM0daxl6JLpUBZvfQnCAm_s928DbSyyNrTR9V3ra0M3pHcPdw' https://192.168.10.50:6443/api
{
  "kind": "APIVersions",
  "versions": [
    "v1"
  ],
  "serverAddressByClientCIDRs": [
    {
      "clientCIDR": "0.0.0.0/0",
      "serverAddress": "192.168.10.50:6443"
    },
    {
      "clientCIDR": "192.168.0.0/16",
      "serverAddress": "192.168.0.1:443"
    }
  ]
}

4.2、默认的service account

1、开启ServiceAccount

如果K8S apiserver的启动参数中添加--admission_control=ServiceAccount

apiserver在启动的时候会自己创建一个key和crt(见/var/run/kubernetes/apiserver.crt和apiserver.key)

然后在启动./kube-controller-manager 时添加flag:

--service_account_private_key_file=/var/run/kubernetes/apiserver.key

那么k8s会在每个namespace下面都会创建一个默认的service account资源,并命名为”default”:

kubectl get serviceaccount --all-namespaces

如果Pod中没有显式指定spec.serviceAccount字段值,那么Kubernetes会将该namespace下的”default” service account自动mount到在这个namespace中创建的Pod里。

2、查看pod的service account资源,

当用户在namespace下创建pod时会默认使用默认的service account资源,。

我们以namespace “default”为例,我们查看一下其中的一个Pod的信息:

kubectl describe pod/webapp-nl754

可以看到,secret:default-token-k7jfg就是我们default这个serviceaccount下的secret。它被装载到容器内部 mountPath: /var/run/secrets/kubernetes.io/serviceaccount 目录中

Pod创建成功后,可以查询Pod的容器挂载/var/run/secrets/kubernetes.io/serviceaccount,实际上这个目录是ServiceAccount的Secret,里面包含了一个token,应用通过使用这个token便可以去访问Kubernetes API:

# kubectl exec  webapp-62xws ls /var/run/secrets/kubernetes.io/serviceaccount

namespace

token

3、查看pod的token的内容:

# kubectl exec  webapp-62xws cat /var/run/secrets/kubernetes.io/serviceaccount/token

也可以深入容器内部,查看mount的serviceaccount路径下的结构:

# docker exec 3d11ee06e0f8 ls  /var/run/secrets/kubernetes.io/serviceaccount
namespace
token

这token文件与上面提到的service account的token中的数据是一一对应的。

4.3、API Server的service account token原理

1、开启ServiceAccount

kubernetes  apiserver开启了ServiceAccount(–admission_control=…,ServiceAccount,… )那么会在每个namespace下面都会创建一个默认的default的ServiceAccount。即service account作为一种resource存在于Kubernetes cluster中。

每个ServiceAccount下面都会拥有一个加密过的secret作为Token. 该token也叫service-account-token

2、apiserver启动的时候,每个ServiceAccount自动生成token。

该token是APIServer在创建service account时用API server启动参数:–service-account-key-file的值签署(sign)生成的。如果–service-account-key-file未传入任何值,那么将默认使用–tls-private-key-file的值,即API Server的私钥(server.key)。

3、pod发起请求http请求携带signed bearer token

在HTTP Header中传递了一个Token字符串,这类似于之前提到的HTTP Token认证方式

类似这样:curl -k -H 'Authorization: Bearer token'  https://192.168.10.50:6443/api

即pod的Token是在指定路径下的一个文件(/run/secrets/kubernetes.io/serviceaccount/token),这token是动态生成的,确切的说,是由KubernetesController进程用API Server的私钥(--service-account-private-key-file指定的私钥)签名生成的一个JWT Secret。

4、apiserver验证token

apiserver的authenticating环节支持多种身份校验方式:client cert、bearer token、static password auth等。

apiserver发现client发起的request使用的是service account token的方式, apiserver 就会自动采用signed bearer token方式进行身份校验。而request就会使用携带的service account token参与验证。

apiserver收到这个Token以后,采用自己的私钥(实际是使用参数service-account-key-file)指定的私钥,如果此参数没有设置,则默认采用tls-private-key-file指定的参数,即自己的私钥,对token进行合法性验证。

5、通过authenticating后

API Server将根据Pod username所在的group:system:serviceaccounts和system:serviceaccounts:(NAMESPACE)的权限对其进行 authorityadmission control 两个环节的处理。在这两个环节中,cluster管理员可以对service account的权限进行细化设置。

五、Secrets

Kubernetes提供了Secret来处理敏感信息,目前Secret的类型有3种:

  • Opaque(default): 任意字符串
  • kubernetes.io/service-account-token: 作用于ServiceAccount
  • kubernetes.io/dockercfg: 作用于Docker registry

开发者可以任意定义Secret的格式和内容,现在创建一个假设Opaque Secret,比如应用要使用账号密码:

username: value-1
password: value-2

首先创建Secret,

secret.yaml:

apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
password: dmFsdWUtMg0K
username: dmFsdWUtMQ0K

注意:其中password和username的值是通过base64 加密。

$ kubectl create -f secret.yaml
$ kubectl describe secrets mysecret
Name:       mysecret
Namespace:  default
Labels:     <none>
Annotations:    <none>
Type:   Opaque

Data

password:   9 bytes username:   9 bytes

现在创建一个Pod使用该Secret

red-pod.json:

{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "mypod"
},
"spec": {
"containers": [{
  "name": "mypod",
  "image": "redis",
  "volumeMounts": [{
    "name": "foo",
    "mountPath": "/etc/foo",
    "readOnly": true
  }]
}],
"volumes": [{
  "name": "foo",
  "secret": {
    "secretName": "mysecret"
  }
}]
}
}

这里将Secret作为一个Volume挂载到Po中容器的/etc/foo下,实际上Secret中的值都会以文件生成到/etc/foo下(文件名是key,文件内容是value),待Pod运行后查看:

$ kubectl exec mypod ls /etc/foo
password
username
$ kubectl exec mypod cat /etc/foo/password
value-2
$ kubectl exec mypod cat /etc/foo/username
value-1

Secret用于 Docker Registry的安全认证,参考:

https://github.com/GoogleCloud ... a-pod

六、Security context

Security context是用以对容器进行限制,使得不同的运行容器之前能够实现较为明晰的隔离,以及降低其影响宿主机和其它容器的可能性。通俗而言,容器中的security context用于表征在创建及运行容器时,它能够使用及访问的资源参数。

securityContext目前只实现了capabilities和privileged ,

etcd-discovery-controller.yaml:

kind: ReplicationController
apiVersion: v1
metadata:
name: etcd-discovery
creationTimestamp: 
spec:
strategy:
type: Recreate
resources: {}
triggers:
- type: ConfigChange
replicas: 1
selector:
name: etcd-discovery
template:
metadata:
  creationTimestamp: 
  labels:
    name: etcd-discovery
spec:
  containers:
  - name: discovery
    image: openshift/etcd-20-centos7
    args:
    - etcd-discovery.sh
    ports:
    - containerPort: 2379
      protocol: TCP
    resources: {}
    terminationMessagePath: "/dev/termination-log"
    imagePullPolicy: IfNotPresent
    capabilities: {}
    securityContext:
      capabilities: {}
      privileged: false
  restartPolicy: Always
  dnsPolicy: ClusterFirst
  serviceAccount: ''
status: {}

===========================================

问题

kube-controller-manager日志出现:

E0711 18:59:01.092033   18548 leaderelection.go:234] error retrieving resource lock kube-system/kube-controller-manager: Get https://k8s-master:6443/api/v1/namespaces/kube-system/endpoints/kube-controller-manager: x509: certificate is valid for kubernetes, kubernetes.default, kubernetes.default.svc, kubernetes.default.svc.cluster.local, not k8s-master

说明 masterssl.cnf没有指定域名 k8s-master

Kubernetes 解决/var/run/secret/kubernetes.io/serviceaccount/token no such file or directory问题

kubectl get serviceaccount

NAME      SECRETS

default   0

如果没有则需要添加

在apiserver的启动参数中添加:

--admission_control=ServiceAccount

apiserver在启动的时候会自己创建一个key和crt(见/var/run/kubernetes/apiserver.crt和apiserver.key)

然后在启动./kube-controller-manager 时添加flag:

--service_account_private_key_file=/var/run/kubernetes/apiserver.key

kubectl get serviceaccount

NAME      SECRETS

default   1

相关文章