32. 限制对服务的访问

Linkerd policy 资源可用于限制哪些客户端可以访问服务。 在此示例中,我们将使用 Emojivoto 来展示如何限制对 Voting 服务的访问,使其只能从 Web 服务中调用。

有关 policy 资源的更全面描述,请参阅 Policy reference文档

设置

确保您安装了 Linkerd 版本 stable-2.11.0 或更高版本,并且它是健康的:

$ linkerd install | kubectl apply -f -
...
$ linkerd check -o short
...

注入并安装 Emojivoto 应用程序:

$ linkerd inject https://run.linkerd.io/emojivoto.yml | kubectl apply -f -
...
$ linkerd check -n emojivoto --proxy -o short
...

为了观察发生了什么,我们还将安装 Viz 扩展:

$ linkerd viz install | kubectl apply -f -
...
$ linkerd viz check
...

创建 Server 资源

我们首先为 Voting 服务创建一个 Server 资源。 ServerLinkerd 自定义资源,它描述了工作负载的特定端口。 一旦 Server 资源被创建,只有被授权的客户端才能访问它(我们稍后会看到如何授权客户端)。

cat << EOF | kubectl apply -f -
---
apiVersion: policy.linkerd.io/v1beta1
kind: Server
metadata:
  namespace: emojivoto
  name: voting-grpc
  labels:
    app: voting-svc
spec:
  podSelector:
    matchLabels:
      app: voting-svc
  port: grpc
  proxyProtocol: gRPC
EOF

我们看到该 Server 使用 podSelector 来选择它所描述的 pod:在本例中是 voting 服务 pod。 它还指定了它适用的命名端口 (grpc)。 最后,它指定在此端口上提供服务的协议。 这可确保代理正确处理流量并允许它跳过协议检测(protocol detection)

此时,没有客户端被授权访问此服务,您可能会看到成功率下降, 因为从 Web 服务到 Voting 的请求开始被拒绝。

我们可以使用 linkerd viz authz 命令查看进入 voting 服务的请求的授权状态, 并查看所有传入的请求当前都未经授权:

> linkerd viz authz -n emojivoto deploy/voting
SERVER       AUTHZ           SUCCESS     RPS  LATENCY_P50  LATENCY_P95  LATENCY_P99
voting-grpc  [UNAUTHORIZED]        -  0.9rps            -            -            -

创建 ServerAuthorization 资源

ServerAuthorization 授予一组客户端访问一组 Servers 的权限。 在这里,我们将创建一个 ServerAuthorization, 它授予 Web 服务访问我们上面创建的 Voting Server 的权限。 请注意,meshed mTLS 使用 ServiceAccounts 作为身份基础, 因此我们的授权也将基于 ServiceAccounts

> cat << EOF | kubectl apply -f -
---
apiVersion: policy.linkerd.io/v1beta1
kind: ServerAuthorization
metadata:
  namespace: emojivoto
  name: voting-grpc
  labels:
    app.kubernetes.io/part-of: emojivoto
    app.kubernetes.io/name: voting
    app.kubernetes.io/version: v11
spec:
  server:
    name: voting-grpc
  # The voting service only allows requests from the web service.
  client:
    meshTLS:
      serviceAccounts:
        - name: web
EOF

有了这个,我们现在可以看到所有对 Voting 服务的请求都是由 voting-grpc ServerAuthorization 授权的。 请注意,由于 linkerd viz auth 命令在一个时间窗口内查询,您可能会看到一些未授权(UNAUTHORIZED)的请求在短时间内显示。

> linkerd viz authz -n emojivoto deploy/voting
SERVER       AUTHZ        SUCCESS     RPS  LATENCY_P50  LATENCY_P95  LATENCY_P99
voting-grpc  voting-grpc   70.00%  1.0rps          1ms          1ms          1ms

我们还可以通过创建 grpcurl pod 并尝试从中访问 Voting 服务来测试来自其他 pod 的请求是否会被拒绝:

> kubectl run grpcurl --rm -it --image=networld/grpcurl --restart=Never --command -- ./grpcurl -plaintext voting-svc.emojivoto:8080 emojivoto.v1.VotingService/VoteDog
Error invoking method "emojivoto.v1.VotingService/VoteDog": failed to query for service descriptor "emojivoto.v1.VotingService": rpc error: code = PermissionDenied desc =
pod "grpcurl" deleted
pod default/grpcurl terminated (Error)

由于此 client 未经授权,此请求将被拒绝并显示 PermissionDenied 错误。

您可以根据需要创建任意数量的 ServerAuthorization 资源来授权许多不同的客户端。 您还可以指定是授权未经身份验证(即 unmeshed)的客户端、任何经过身份验证的客户端, 还是仅授权具有特定身份的经过身份验证的客户端。 有关更多详细信息,请参阅 Policy reference 文档

设置默认策略

要进一步锁定集群,您可以设置一个默认策略,该策略将应用于所有未定义 Server 资源的端口。 Linkerd 在决定是否允许请求时使用以下逻辑:

  • 如果端口有一个 Server 资源并且客户端为其匹配一个 ServerAuthorization 资源:ALLOW
  • 如果端口有一个 Server 资源,但客户端不匹配它的任何 ServerAuthorizations:DENY
  • 如果端口没有 Server 资源:使用默认策略

我们可以使用 linkerd upgrade 命令将默认策略设置为 deny

> linkerd upgrade --set policyController.defaultAllowPolicy=deny | kubectl apply -f -

或者,可以通过设置 config.linkerd.io/default-inbound-policy annotation 在单个工作负载或命名空间上设置默认策略。有关更多详细信息,请参阅Policy reference 文档

这意味着除非通过创建 ServerServerAuthorization 资源明确授权,否则所有请求都将被拒绝。 这样做的一个重要后果是 livenessreadiness 探针需要明确授权, 否则 Kubernetes 将无法将 pod 识别为 liveready 状态,并将重新启动它们。

此策略允许所有客户端访问 Linkerd admin 端口, 以便 Kubernetes 可以执行 livenessreadiness 检查:

> cat << EOF | kubectl apply -f -
---
# Server "admin": matches the admin port for every pod in this namespace
apiVersion: policy.linkerd.io/v1beta1
kind: Server
metadata:
  namespace: emojivoto
  name: admin
spec:
  port: linkerd-admin
  podSelector:
    matchLabels: {} # every pod
  proxyProtocol: HTTP/1
---
# ServerAuthorization "admin-everyone": allows unauthenticated access to the
# "admin" Server, so that Kubernetes health checks can get through.
apiVersion: policy.linkerd.io/v1beta1
kind: ServerAuthorization
metadata:
  namespace: emojivoto
  name: admin-everyone
spec:
  server:
    name: admin
  client:
    unauthenticated: true

如果您知道 Kubelet(执行健康检查)的 IP 地址或范围, 您可以进一步将 ServerAuthorization 限制为这些 IP 地址或范围。 例如,如果您知道 Kubelet10.244.0.1 上运行,那么您的 ServerAuthorization 可以改为:

# ServerAuthorization "admin-kublet": allows unauthenticated access to the
# "admin" Server from the kubelet, so that Kubernetes health checks can get through.
apiVersion: policy.linkerd.io/v1beta1
kind: ServerAuthorization
metadata:
  namespace: emojivoto
  name: admin-kubelet
spec:
  server:
    name: admin
  client:
    networks:
    - cidr: 10.244.0.1/32
    unauthenticated: true

进一步的考虑

您可能已经注意到, 在我们创建 Server 资源之后但在创建 ServerAuthorization 之前有一段时间,所有请求都被拒绝。 为了避免在实时系统中出现这种情况,我们建议您在部署服务之前创建 policy 资源, 或者在创建 Server 之前创建 ServiceAuthorizations,以便立即授权客户端。