如果您的基础架构由相互交互的多个应用程序组成,则您可能会遇到保护服务之间的通信安全以防止未经身份验证的请求的问题。

想象一下,有两个应用程序:

  • API
  • datastore

您可能希望数datastore仅响应对API的请求,并拒绝来自其他任何地方的请求。

datastore将如何决定允许还是拒绝该请求?

一种流行的方法是请求身份令牌并将其传递给服务内的每个请求。

因此,与其直接向datastore发出请求,不如直接通过身份验证服务,检索令牌并使用该令牌对您对datastore的请求进行身份验证。

存在与令牌关联的特定上下文,该上下文允许datastore从API服务接受令牌并从其他地方拒绝令牌。

此上下文用于允许或拒绝该请求。

  1. 想象一下向API组件发出请求。
  1. API向datastore进行身份验证的唯一方法是,如果它具有有效的令牌。API使用其凭据从授权服务器请求令牌。
  1. API向datastore发出请求,并附加令牌作为有效身份的证明。
  1. 在回复请求之前,datastore会通过授权服务器验证令牌。

关于实现此身份验证机制,您有几种选择:

  • 您可以使用不会过期的静态令牌。在这种情况下,无需运行专用的身份验证服务器。
  • 您可以设置一个OAuth服务器。
  • 您可以推出身份验证和授权机制,例如相互TLS证书。

身份验证和授权服务器所需要做的就是:

  1. 验证请求者身份-请求者应该具有有效且可验证的身份。
  2. 生成具有有限范围,有效性和所需audience的令牌。
  3. 验证令牌-仅当令牌是所涉及的两个服务的合法令牌时,才允许服务到服务的通信。

允许您实施身份验证和授权基础结构的专用软件示例包括Keycloak或Dex等工具。

使用Keycloack时,首先需要:

  1. 使用您的电子邮件和密码登录-您的身份已通过验证。
  2. 为您的用户创建了一个有效的会话。该会话可能描述您属于哪些组。
  3. 每个请求都经过验证,无效时将要求您重新登录。

基础架构中的两个应用程序也是如此。

  1. 后端组件使用其API密钥和密钥向Keycloack发出请求,以生成会话令牌。
  2. 后端使用会话令牌向第二个应用程序发出请求。
  3. 第二个应用程序从请求中检索令牌,并使用Keycloak对其进行验证。
  4. 如果令牌有效,它将回复该请求。

您可能没有注意到,但是Kubernetes提供了与ServiceAccount,角色和RoleBindings一起实现身份验证和授权的原语。

Kubernetes作为身份验证和授权服务器

在Kubernetes中,您可以使用ServiceAccount分配身份 。

用户和Pod可以使用这些身份作为对API进行身份验证和发出请求的机制。

然后,将ServiceAccount链接到授予对资源的访问权限的角色。

例如,如果某个角色授予创建和删除Pod的权限,则您将无法修改Secrets或创建ConfigMap。

您可以使用ServiceAccount作为一种机制来验证集群中应用程序之间的请求吗?

如果Kubernetes API可用作身份验证和授权服务器怎么办?

让我们尝试一下。

创建集群

您将需要访问启用了 ServiceAccount卷投影功能 的Kubernetes集群。

如果您不知道什么是ServiceAccount卷,请不要担心-您将在本文后面的内容中进一步了解它。

ServiceAccount卷投影功能要求Kubernetes API服务器以特定的API标志运行。

对不同托管Kubernetes提供商的支持可能会有所不同。

但是,您可以使用以下方法在minikube中启用卷投影功能来启动本地集群:

minikube start --extra-config=apiserver.service-account-signing-key-file=/var/lib/minikube/certs/sa.key --extra-config=apiserver.service-account-key-file=/var/lib/minikube/certs/sa.pub --extra-config=apiserver.service-account-issuer=kubernetes/serviceaccount --extra-config=apiserver.service-account-api-audiences=api

您还应该克隆该 示例存储库 ,因为它包含本文中将引用的演示源代码。

现在,您将部署两项服务:

  • 您会将这些服务称为API服务和datastore。
  • 它们使用Go编程语言编写,并通过HTTP进行通信。
  • 每个服务都在其名称空间中运行,并使用专用的ServiceAccount标识。
  • datastore仅在调用者具有有效身份时才成功回复请求,否则它会拒绝并显示错误。

部署API组件

API服务是侦听端口8080的无头Web应用程序。

当您向它发出请求时,API组件:

  1. 向datastore发出其ServiceAccount标识的HTTP GET请求。
  2. 转发响应。

您可以使用以下方法在群集中部署应用程序并暴露服务:

kubectl apply -f service_accounts/api/deployment.yaml
namespace/api created
serviceaccount/api created
deployment.apps/app created
service/app created

您可以使用以下方法检索API服务的URL:

minikube --namespace api service app --url
http://192.168.99.101:31541

如果您向该应用发出请求,您将获得成功的答复吗?

让我们尝试一下:

curl http://192.168.99.101:31541
curl: (7) Failed to connect to 192.168.99.101 port 31541: Connection refused

由于您尚未部署datastore,因此将出现此错误。

保持终端打开。

打开一个新的终端以执行下一组步骤。

部署datastore

datastore服务是侦听端口8081的另一个无头Web应用程序。

当客户提出任何请求时,datastore:

  1. 在请求标头中查找令牌。如果没有,则返回HTTP 401错误响应。
  2. 使用Kubernetes API检查令牌的有效性。如果无效,它将以HTTP 403响应进行回复。
  3. 最后,当令牌有效时,它将回复原始请求。

您可以使用以下方法创建datastore:

kubectl apply -f service_accounts/data-store/deployment.yaml
namespace/data-store created
serviceaccount/data-store created
clusterrolebinding.rbac.authorization.k8s.io/role-tokenreview-binding created
deployment.apps/app created
service/app created

现在,使用curl再次向API服务发出请求:

curl http://192.168.99.101:31541
Hello from data store. You have been authenticated

datastore服务成功验证了令牌并回复到API。

API将请求转发给您。

如果直接向datastore发送请求怎么办?

使用以下方法检索datastore的URL:

minikube --namespace data-store service app --url
http://192.168.64.28:31690

让我们用它curl来请求:

curl http://192.168.64.28:31690
X-Client-Id not supplied

这没用。

但是您可以提供一个虚拟X-Client-Id标题

curl -H 'X-Client-Id: dummy' http://192.168.64.28:31690
Invalid token

优秀!

这没用!

您使用Kubernetes和ServiceAccount保护了datastore免受未经授权的访问。

只有拥有有效的令牌,您才能对此请求。

但是,所有这些工作如何进行?让我们找出答案。

Under the hood

ServiceAccount是一种将Kubernetes工作负载与身份相关联的方法。

您可以将ServiceAccount与角色和RoleBinding结合使用,以定义集群中哪些资源或哪些人可以访问哪些资源。

例如,当您想将“读取机密”仅限制为群集中的管理员用户时,可以使用ServiceAccount来进行。

  1. ServiceAccount是身份。身份既可以分配给用户,也可以分配给Pod。
  1. 角色是链接到名称空间的权限列表。ClusterRole是群集范围内可用权限的列表
  1. 身份没有任何权限,除非您将其链接到角色。您可以使用ClusterRoleBindings将身份链接到ClusterRole。
  1. 您可以使用RoleBindings将身份链接到角色。

不过,ServiceAccount不仅适用于用户。

您可以验证人员以及集群中的应用程序。

如果您希望您的应用程序列出集群中所有可用的Pod,则需要创建一个与对Pod API的只读访问权限相关联的ServiceAccount。

之前部署两个应用程序时,还创建了两个ServiceAccount:

kubectl get serviceaccount --namespace api
NAME      SECRETS   AGE
api       1         4m5s
default   1         4m5s
kubectl get serviceaccount --namespace data-store
NAME           SECRETS   AGE
default        1         6m4s
data-store   1         6m4s

这些ServiceAccount是与应用程序关联的身份,但它们并未定义授予的权限。

为此,您可能需要列出Role和ClusterRoles:

kubectl get rolebindings,clusterrolebindings --all-namespaces -o custom-columns='KIND:kind,ROLE:metadata.name,SERVICE_ACCOUNTS:subjects[?(@.kind=="ServiceAccount")].name'
KIND                 ROLE                       SERVICE_ACCOUNTS
RoleBinding          kube-proxy                 <none>
ClusterRoleBinding   cluster-admin              <none>
ClusterRoleBinding   kubeadm:get-nodes          <none>
ClusterRoleBinding   role-tokenreview-binding   data-store

上面的命令使用kubectl自定义列过滤的输出kubectl get。

该表显示了什么RoleBinding链接到角色(以及什么ClusterRoleBinding链接到ClusterRole)。

具有任何角色的唯一组件是datastore。

API没有角色或角色绑定。

为何没有角色和RoleBinding的ServiceAccount又如何?

API应用具有一个空的ServiceAccount,该帐户没有任何权限。

但是,您可以使用该ServiceAccount身份来验证对Kubernetes API的请求(但不能创建,更新,删除等资源)。

那么datastore呢?

它具有什么样的访问权限?

让我们回顾一下ClusterRoleBinding:

kubectl describe clusterrolebinding role-tokenreview-binding
Name:         role-tokenreview-binding
Labels:       <none>
Annotations:  <none>
Role:Kind:  ClusterRoleName:  system:auth-delegator
Subjects:Kind            Name        Namespace----            ----        ---------ServiceAccount  data-store  data-store

从上面的输出中,您可以知道ClusterRoleBinding将datastore ServiceAccount链接到system:auth-delegatorClusterRole。

哪些权限授予ClusterRole?

让我们找出:

kubectl describe clusterrole system:auth-delegator
Name:         system:auth-delegator
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:Resources                                  Non-Resource URLs  Resource Names  Verbs---------                                  -----------------  --------------  -----tokenreviews.authentication.k8s.io         []                 []              [create]subjectaccessreviews.authorization.k8s.io  []                 []              [create]

该system:auth-delegatorClusterRole有权限调用tokenreview API。

那是什么样的许可?

可以将kubectl与can-i子命令和模拟--as标志一起使用以测试权限:

kubectl auth can-i create deployments --as=data-store --namespace data-store
no
kubectl auth can-i list pods --as=data-store --namespace data-store
no
kubectl auth can-i delete services --as=data-store --namespace data-store
no

您可以继续查询所有Kubernetes资源,但是ServiceAccount只有一个权限。

kubectl auth can-i create tokenreviews --as=sa-test-1
yes

什么是TokenReview?

向Kubernetes API发出请求

Kubernetes API验证ServiceAccount身份。

特别是,有一个特定的组件负责验证和拒绝它们:Token Review API

令牌审查API接受令牌并返回它们是否有效-是的,就这么简单。

让我们根据令牌查看API手动验证API组件的身份。

它的令牌评论API,所以你可能需要一个令牌。

什么令牌,但是?

每次创建ServiceAccount时,Kubernetes都会创建一个secret。

机密持有ServiceAccount的令牌,您可以使用该令牌来调用Kubernetes API。

这是应该根据令牌审查API进行验证的令牌。

因此,让我们使用以下方法检索APIServiceAccount的令牌:

kubectl --namespace api describe serviceaccount api
Name:                api
Mountable secrets:   api-token-lxcb4
Tokens:              api-token-lxcb4

然后,要检查Secret对象,可以发出以下命令:

kubectl --namespace api describe secret api-token-lxcb4
Name:         api-token-lxcb4
Type:  kubernetes.io/service-account-tokenData
====
ca.crt:     1111 bytes
namespace:  3 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6…

token在数据对象是表示JSON网络令牌有效载荷base64编码对象。

现在是时候验证令牌了。

要验证令牌的有效性,您需要创建TokenReview资源:

kind: TokenReview
apiVersion: authentication.k8s.io/v1
metadata:name: test
spec:token: eyJhbGciOiJS…

您可以使用以下方法验证请求:

kubectl apply -o yaml -f token.yaml

请注意-o yaml显示kubectl apply命令输出的标志。

发出命令时,响应应如下所示:

apiVersion: authentication.k8s.io/v1
kind: TokenReview
metadata:name: test
spec:token: eyJhbGciOiJS…
status:audiences:- apiauthenticated: trueuser:groups:- system:serviceaccounts- system:serviceaccounts:api- system:authenticateduid: 7df3a132-c9fe-48d1-9fa5-b654c3156977username: system:serviceaccount:api:api

响应中的关键信息位于具有以下字段的状态对象中:

  • Authenticated:该字段设置为true,表示令牌已成功验证。
  • 在用户对象中,您可以找到以下属性:
  • 与Pod-使用的ServiceAccount相对应的用户名system:serviceaccount:test:sa-test-1。
  • 当前用户的系统用户标识的uid。
  • 组包括用户所属的组。
  • 目标对象包含令牌旨在使用的目标对象列表。在这种情况下,只有api才是有效的audience群体。 太好了,您刚刚验证了ServiceAccount令牌!

你懂的:

  • 令牌有效。
  • 调用者的身份(APIServiceAccount)。
  • 请求者者所属的组。

由于您可以验证和验证任何令牌,因此可以利用datastore组件中的机制对请求进行身份验证和授权!

让我们看一下如何使用Kubernetes Go客户端在应用程序中包含上述逻辑。

实现服务

以下是这两种服务与Kubernetes API相互交互的方式:

  1. 在启动时,API组件读取ServiceAccount令牌并将其保留在内存中。
  2. API组件调用将令牌作为HTTP标头(即)传递的datastoreX-Client-Id。
  3. datastore收到请求后,会从X-Client-Id标头中读取令牌,然后向令牌审阅API发出请求以检查其有效性。
  4. 如果对响应进行了身份验证,则datastore组件将以成功消息进行答复,否则为401错误。

下图表示上述调用流程:

  1. API组件已分配了ServiceAccount令牌。
  1. 当您向API发出请求时,令牌将在所有后续请求中传递。
  1. datastore将从请求中检索令牌。
  1. datastore使用令牌查看API验证身份。

首先,让我们看一下API服务的实现。

您可以在文件中找到应用程序代码service_accounts/api/main.go

ServiceAccount令牌会自动安装在其中/var/run/secrets/kubernetes.io/serviceaccount/token,您可以通过以下方式读取其值:

func readToken() {b, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")if err != nil {panic(err)}serviceToken = string(b)
}

然后,将服务令牌传递到X-Client-IdHTTP标头中对Secret store服务的调用:

func handleIndex(w http.ResponseWriter, r *http.Request) {
…
client := &http.Client{}
req, err := http.NewRequest("GET", serviceConnstring, nil)
if err != nil {panic(err)
}
req.Header.Add("X-Client-Id", serviceToken)
resp, err := client.Do(req)
…

一旦收到来自Secret Store的回复,然后将其作为响应发送回:

…
if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return
} else {defer resp.Body.Close()body, _ := ioutil.ReadAll(resp.Body)io.WriteString(w, string(body))
}

以下YAML清单用于部署API服务:

deployment.yaml
apiVersion: v1
kind: Namespace
metadata:name: api
---
apiVersion: v1
kind: ServiceAccount
metadata:name: apinamespace: api
---
apiVersion: apps/v1
kind: Deployment
metadata:name: appnamespace: api
spec:replicas: 1selector:matchLabels:app: apitemplate:metadata:labels:app: apispec:serviceAccount: apicontainers:- name: appimage: amitsaha/k8s-sa-volume-demo-api:sa-1env:- name: LISTEN_ADDRvalue: ":8080"- name: DATA_STORE_CONNSTRINGvalue: "http://app.data-store.svc.cluster.local"ports:- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:name: appnamespace: api
spec:type: NodePortselector:app: apiports:- port: 8080targetPort: 8080

您将注意到,除了具有与之关联的ServiceAccount之外,上面的部署清单没有什么特别的。

让我们进入datastore服务。

您可以在中找到完整的应用程序service_accounts/data-store/main.go

datastore服务执行两项关键操作:

  1. 它X-Client-Id从传入的请求中检索标头的值。
  2. 然后,它调用Kubernetes令牌查看API来检查令牌是否有效。

步骤(1)由以下代码执行:

clientId := r.Header.Get("X-Client-Id")
if len(clientId) == 0 {http.Error(w, "X-Client-Id not supplied", http.StatusUnauthorized)return
}

然后,使用Kubernetes Go客户端执行步骤(2)。

首先,我们创建一个ClientSet对象:

config, err := rest.InClusterConfig()
clientset, err := kubernetes.NewForConfig(config)

该InClusterConfig()功能自动读取Pod的ServiceAccount令牌,因此您不必手动指定路径。

然后,构造一个TokenReview对象,该对象在Token字段中指定要验证的令牌:

tr := authv1.TokenReview{Spec: authv1.TokenReviewSpec{Token: clientId,},
}

最后,您可以使用以下命令创建TokenReview请求:

result, err := clientset.AuthenticationV1().TokenReviews().Create(ctx, &tr, metav1.CreateOptions{})

以下YAML清单将创建datastore服务所需的各种资源:

apiVersion: v1
kind: Namespace
metadata:name: data-store
---
apiVersion: v1
kind: ServiceAccount
metadata:name: data-storenamespace: data-store
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: role-tokenreview-binding
roleRef:apiGroup: rbac.authorization.k8s.iokind: ClusterRolename: system:auth-delegator
subjects:
- kind: ServiceAccountname: data-storenamespace: data-store
---
apiVersion: apps/v1
kind: Deployment
metadata:name: appnamespace: data-store
spec:replicas: 1selector:matchLabels:app: data-storetemplate:metadata:labels:app: data-storespec:serviceAccount: data-storecontainers:- name: appimage: amitsaha/k8s-sa-volume-demo-ss:sa-1env:- name: LISTEN_ADDRvalue: ":8081"ports:- containerPort: 8081
---
apiVersion: v1
kind: Service
metadata:name: appnamespace: data-store
spec:selector:app: data-storeports:- protocol: TCPport: 80targetPort: 8081

与API服务相比,datastore服务需要创建ClusterRoleBinding资源,该资源将data-storeServiceAccount与system:auth-delegatorClusterRole关联。

返回到您在其中部署了datastore服务的终端会话,并检查日志:

kubectl --namepsace data-store logs <data-store-pod-id>
2020/08/21 09:09:10 v1.TokenReviewStatus{Authenticated:true,
User:v1.UserInfo{Username:"system:serviceaccount:data-store:data-store",
UID:"24ae6734-9ca1-44d8-af93-98b6e6f8da17", Groups:[]string{"system:serviceaccounts",
"system:serviceaccounts:api", "system:authenticated"}, Extra:map[string]v1.ExtraValue(nil)},
Audiences:[]string{"api"}, Error:""}

输出是您之前看到的JSON响应的Go结构版本。

因此,您将看到API组件如何读取ServiceAccount令牌并将其传递到datastore作为身份验证的一种方式。

datastore服务检索令牌并使用Kubernetes API对其进行检查。

有效时,datastore组件允许处理来自API服务的请求。

该实现效果很好,但是存在三个缺点:

每个serviceaccent一个secret

创建ServiceAccount时,Kubernetes会创建一个带有令牌的配套Secret对象。

您可以使用令牌通过Kubernetes API进行身份验证。

在此示例中,您可以检查ServiceAccount并使用以下命令找到令牌:

kubectl --namespace api describe serviceaccount api
Name:                api
Namespace:           api
Mountable secrets:   api-token-ttr8q
Tokens:              api-token-ttr8q

匹配命名空间中的Secret对象:

kubectl get secrets --namespace api
NAME                  TYPE
api-token-ttr8q       kubernetes.io/service-account-token
default-token-vppc9   kubernetes.io/service-account-token

但是,任何可以读取名称空间中的机密的工作负载也可以读取同一名称空间中的ServiceAccount令牌。

换句话说,您可以让任何其他Pod使用相同的ServiceAccount来针对Kubernetes API进行身份验证-有效地冒充其他人。

不幸的是,没有机制可以限制对命名空间中Secrets子集的访问。

该应用程序可以访问所有这些访问权限,或者没有访问权。

您可以为每个应用程序创建一个名称空间,并在其中存储一个ServiceAccount,但这通常会显得过分。

长期有效的服务账户令牌

与ServiceAccount关联的令牌是长期的,不会过期。

换句话说,一旦您可以访问其中之一,就可以永久使用它(或者直到管理员删除与令牌关联的密钥)。

您可以通过手动删除和重新分配ServiceAccount来手动旋转身份。

如果听起来需要做很多工作,那是因为确实如此。

没有对绑定token的audience

作为群集管理员,您不能将令牌与特定的audience相关联。

有权访问ServiceAccount令牌的任何人都可以使用Kubernetes API进行身份验证,并有权与集群中运行的任何其他服务进行通信。

目标服务没有任何方法可以验证与它一起提供的令牌是否完全是针对自己的。

例如,想象一下买一张从伦敦到纽约的机票。

如果您从英国航空公司购买机票,则无法使用该机票登上维珍航空的航班。

您的机票绑定到特定的观众(英国航空公司)。

但是对于Kubernetes,同一票证(令牌)可以用于任何航空公司(观众)。

您可以通过实施诸如双向TLS之类的解决方案,或将基于JWT的解决方案与中央授权服务器配合使用来解决这两个挑战。

但是,在Kubernetes中,您可以使用ServiceAccount令牌数量投影功能来创建有时限且针对特定audience的ServiceAccount令牌,这些令牌不会在群集存储中持久存在。

Kubernetes API服务器充当中央授权服务器,您不必担心令牌到期。

此功能在Kubernetes 1.12中引入,并在1.13中得到了进一步改进,并为特定于工作负载的ServiceAccount提供了更安全的替代方法。

这将在即将推出的Kubernetes 1.20版本中提升为GA功能。

在本文的下一部分中,您将重新实现相同的代码,以使用ServiceAccount令牌量投影对应用进行身份验证。

清理两个命名空间是一个好主意:

kubectl delete namespace api
namespace "api" deleted
kubectl delete namespace data-store
namespace "data-store" deleted

使用ServiceAccount令牌量投影的服务间验证

通过ServiceAccount令牌卷投影(ProjectedServiceAccountToken)可用于工作负载的ServiceAccount令牌是受时间限制,受audience约束的,并且不与secret对象关联。

如果删除了Pod或删除了ServiceAccount,则这些令牌将无效,从而可以防止任何误用。

一个serviceAccountToken卷投影是一个projected卷类型。

当将此卷类型添加到Pod时,ServiceAccount令牌将安装在文件系统上—与安装ServiceAccount令牌的方式相同。

虽然有区别。

Kubelet将在令牌即将到期时自动旋转令牌。

另外,您可以配置希望此令牌可用的路径。

让我们看看如何修改API组件以包括“ServiceAccount令牌卷投影”。

API组件

您可以使用以下内容读取通过批量投影安装的ServiceAccount令牌:

b, err := ioutil.ReadFile("/var/run/secrets/tokens/api-token")
serviceToken = string(b)

请注意,ServiceAccount令牌的路径与前一种情况不同(即以前是/var/run/secrets/http://kubernetes.io/serviceaccount/token)。

由于ServiceAccount令牌的卷投影功能依赖于kubelet定期刷新的令牌,因此建议每5分钟在应用程序中重新读取一次令牌。

您可以通过Go中的代码来完成此操作,如下所示:

ticker := time.NewTicker(300 * time.Second)
done := make(chan bool)go func() {for {select {case <-done:returncase <-ticker.C:readToken()}}
}()

该readToken()函数读取文件,/var/run/secrets/tokens/api-token并将全局变量serviceToken设置为令牌值。

如果您不熟悉Go的代码,可以将代码视为后台线程,该线程定期运行功能。

您可以在中找到整个应用程序代码service_accounts_volume_projection/api/main.go。

现在,让我们部署此服务。

您将在部署清单(service_accounts_volume_projection/api/deployment.yaml)中使用该镜像:

deployment.yaml
apiVersion: v1
kind: Namespace
metadata:name: api
---
apiVersion: v1
kind: ServiceAccount
metadata:name: apinamespace: api
---
apiVersion: apps/v1
kind: Deployment
metadata:name: appnamespace: api
spec:replicas: 1selector:matchLabels:app: apitemplate:metadata:labels:app: apispec:serviceAccount: apivolumes:- name: api-tokenprojected:sources:- serviceAccountToken:path: api-tokenexpirationSeconds: 600audience: data-storecontainers:- name: appimage: amitsaha/k8s-sa-volume-demo-api:sa-2env:- name: LISTEN_ADDRvalue: ":8080"- name: DATA_STORE_CONNSTRINGvalue: "http://app.data-store.svc.cluster.local"ports:- containerPort: 8080volumeMounts:- mountPath: /var/run/secrets/tokensname: api-token
---
apiVersion: v1
kind: Service
metadata:name: appnamespace: api
spec:type: NodePortselector:app: apiports:- port: 8080targetPort: 8080

名为api-token的projected类型卷将根据serviceAccountToken被创建。

该卷定义了三个附加属性:

  1. 在path其中令牌将可配置的volume内。
  2. 该audience字段指定令牌的目标audience(如果未指定,则默认为api)。
  3. 该expirationSeconds指示标记有效多久-最小为600秒或10分钟。

请注意,该audience字段如何指定该ServiceAccount令牌仅允许与标识为的服务进行通信data-store。

如果您data-store在Secret store组件中忽略作为audience,则该API将无法与其进行对话-不是它的audience!

您可以使用以下方法创建新的deployment:

kubectl apply -f service_accounts_volume_projection/api/deployment.yaml
namespace/api created
serviceaccount/api created
deployment.apps/app created
service/app created

通过以下方式检索API服务的URL:

minikube --namespace api service app --url
http://192.168.99.101:31541
您可以通过以下方式发出请求:重击
curl http://192.168.99.101:31541
curl: (7) Failed to connect to http://192.168.99.101 port 31541: Connection refused

这是预期的,因为尚未部署datastore。

保持终端打开。

接下来,让我们修改和部署datastore服务。

datastore

现在,datastore的tokenreview有效负载如下:

tr := authv1.TokenReview{pec: authv1.TokenReviewSpec{Token:  clientId,Audiences:  []string{"data-store"},},
}

现在,在TokenReview对象中,datastoredata-store作为访问者显式传递。

如果令牌不包括data-store在访问者中,则令牌审查API将不会授权该请求。

换句话说,datastore服务可以断言调用方的身份,并验证传入的请求令牌是否应用于datastore服务。

您可以在中找到整个应用程序代码service_accounts_volume_projection/data-store/main.go。

接下来,让我们部署此服务。

您可以使用以下方法创建deployment:

kubectl apply -f service_accounts_volume_projection/data-store/deployment.yaml
namespace/data-store created
serviceaccount/data-store created
clusterrolebinding.rbac.authorization.k8s.io/role-tokenreview-binding created
deployment.apps/app created
service/app created

让我们检查服务是否正常运行:

kubectl --namespace data-store describe service app
Name:           app
Namespace:      data-store
Labels:         <none>
Selector:       app=data-store
Type:           ClusterIP
IP:             10.106.239.243
Port:           <unset>  80/TCP
TargetPort:     8081/TCP
Endpoints:      172.18.0.5:8081

Endpoints上面输出中的值告诉我们应用程序现在已启动并正在运行。

现在,使用curl再次向API服务发出请求:

curl http://192.168.99.101:31541
Hello from data store. You have been authenticated

您应该使用以下方法检查secret存储的日志:

kubectl --namespace data-store logs <pod id>
(v1.TokenReviewStatus) &TokenReviewStatus{Authenticated:true,
User:UserInfo{Username:system:serviceaccount:api:api,
UID:ec7c304f-9722-4d1b-9f67-d3ce32cd8d4c,
Groups:[system:serviceaccounts system:serviceaccounts:api system:authenticated],
Extra:map[string]ExtraValue{authentication.kubernetes.io/pod-name:
[app-65d954658c-dbbr5],
authentication.kubernetes.io/pod-uid: [1b37a3f4-54f1-419c-b435-affce3f4a0f3],},},
Error:,Audiences:[data-store],}

在切换到API服务的日志时,应该看到以下几行说明了何时从文件系统中重新读取ServiceAccount令牌:

2020/08/26 05:03:43 Refreshing service account token
2020/08/26 05:13:42 Refreshing service account token
2020/08/26 05:18:42 Refreshing service account token

概要

ServiceAccount令牌卷投影可让您将非全局,有时间限制和受audience绑定的服务令牌与Kubernetes工作负载相关联。

在本文中,您看到了一个在服务之间使用它进行身份验证的示例,以及如何使用它更好地替代默认的ServiceAccount令牌。

诸如Linkerd和Istio之类的Kubernetes本机软件正在对其内部通信进行拥抱,而诸如GKE和AWS EKS之类的托管Kubernetes服务提供商正在使用这种投影卷类型来实现更强大的Pod身份系统。

原文:https://learnk8s.io/microservices-authentication-kubernetes

扫描关注我:

weblogic登录验证被拒绝_使用Kubernetes身份在微服务之间进行身份验证相关推荐

  1. 为什么 kubernetes 天然适合微服务

    最近总在思考,为什么在支撑容器平台和微服务的竞争中,Kubernetes 会取得最终的胜出,事实上从很多角度出发三大容器平台从功能方面来看,最后简直是一摸一样. 参考 Docker, Kubernet ...

  2. 后Kubernetes时代的微服务

    \ 本文要点 \\ 当前微服务架构依然是最流行的分布式系统架构风格.Kubernetes和云原生运动已大规模地重新定义了应用设计和开发中的一些方面.\\t 在云原生平台上,服务仅具备可观测性是不够的. ...

  3. springcloud 熔断不生效_深入理解SpringCloud与微服务构建

    目录 一.SpringCloud微服务技术简介 二.开发框架SpringBoot 三.服务注册和发现Ereka 四.负载均衡 五.申明式调用 六.熔断器 七.路由网关 八.配置中心 九.服务链路追踪 ...

  4. c++突破网关屏蔽_通过API网关实现微服务管控-限流,熔断和降级

    今天准备谈下基于API网关来实现微服务治理管控中的服务限流,熔断和降级方面的内容.在前面谈微服务架构的时候也谈到过类似通过Hystrix,Sentinel来是服务限流熔断.包括也不断地在谈去中心化架构 ...

  5. 使用spring boot+kubernetes构建完整微服务平台

    微服务架构被认为是构建大型复杂系统的最佳理论指导,其采用了分而治之.单一职责.关注点分离等方法论来设计系统架构.微服务的实现方式和思路有很多种,本文简述基于kubernetes的微服务平台建设思路及技 ...

  6. 马斯洛理论告诉你,Kubernetes可以满足微服务的这些需求

    需求层次理论是由心理学家艾伯特·马斯洛设计的,它是一种解释人类动机的心理学理论,它由多层次的人类需求模型组成,通常被描述成金字塔内的等级层次.马斯洛使用诸如生理.安全.归属感和爱.尊重.自我实现和自我 ...

  7. 服务网格——后 Kubernetes 时代的微服务(前言)

    目录 重要观点 阅读本文之前 Kubernetes vs Service Mesh kube-proxy 组件 kube-proxy 的缺陷 Kubernetes Ingress vs Istio G ...

  8. Service Mesh(服务网格)——后 Kubernetes 时代的微服务

    本文转载自:宋净超的博客 这不是一篇教程,本文试图带您梳理清楚 Kubernetes.Envoy(xDS 协议)以及 Istio Service Mesh 之间的关系及内在联系.本文介绍了 Kuber ...

  9. 微博中微服务缓存_微服务之间调用超时的设置治理

    原标题:微服务之间调用超时的设置治理 作者 | 奇正 微服务是⼀种分布式架构,系统内各部分(服务)被部署为单独的应用程序,并通过某种远程访问协议进⾏通讯.分布式应⽤的挑战之⼀就是如何管理远程服务的可用 ...

最新文章

  1. P4755 Beautiful Pair (数据结构+分治)
  2. 从电商用户触点看服务设计趋势
  3. boost::allocator_max_size的实例
  4. 论文浅尝 – KDD2020 | 使用图对比编码的图神经网络预训练模型
  5. window.open不重复打开同一个名称的窗口_干货满满|Ctrl键的正确打开方式
  6. Magento教程 10:如何修改网站文字?
  7. 数据结构6——回文树
  8. 阿里云总监课第四期:阿里褚霸携专家团独家分享弹性计算最佳实践
  9. 三维坐标转经纬度_地形图坐标转换小程序使用方法
  10. 淘宝用户行为分析——用户画像
  11. 新侨移民告诉你:为什么要移民新西兰?
  12. Linux系列: 777 755区别
  13. 【Zoomit】的安装及使用方法
  14. 两招让你成为很厉害的T型人才
  15. Java 常见摘要算法——md5、sha1、sha256
  16. 【微信小程序】选择器组件picker
  17. 什么是OEM ODM JDM OQM OBM?
  18. 微信淘宝客引流的正确玩法
  19. python制作翻译小软件_如何基于Python制作有道翻译小工具
  20. nginx访问后端偶尔超时问题

热门文章

  1. android h5状态栏消息,安卓实现系统状态栏的隐藏和显示
  2. hbase建索引java api_hbase java api样例(版本1.3.1,新API)
  3. xcode 编译静态库所要注意
  4. pygame简单的俄罗斯方块游戏和简单的打字游戏
  5. 松江主机点位怎么预留_智能家居设计篇:智能化布线怎么做到有备无患
  6. intouch负值显示0_excel 应用中计算结果显示为负数,使负数显示为0应如何操作?...
  7. 铺铜过孔不要十字_铺植草砖施工工艺
  8. 电脑ip地址设置_关于电脑的远程开机(唤醒)
  9. html主动发起重新布局,重启连不上网
  10. 【c语言】统计字符次数