你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用适用于容器的应用程序网关的前端 MTLS - 网关 API

本文档可帮助设置一个使用网关 API 中以下资源的示例应用程序。 下面是步骤:

背景

相互传输层安全性 (MTLS) 是一个依赖于证书来加密通信和标识服务客户端的过程。 通过此操作,适用于容器的应用程序网关只需信任经过身份验证的设备的连接,即可进一步改善其安全态势。

请参见下图:

关系图显示了适用于容器的应用程序网关前端 MTLS 进程。

有效的客户端证书流会显示向适用于容器的应用程序网关前端提供证书的客户端。 适用于容器的应用程序网关可确定证书有效,并将请求代理到后端目标。 最终会向客户端返回响应。

吊销的客户端证书流会显示向适用于容器的应用程序网关前端提供已吊销证书的客户端。 适用于容器的应用程序网关可确定证书无效,并阻止将请求代理到客户端。 客户端将收到 HTTP 400 请求错误和相应的原因。

先决条件

  1. 如果遵循 BYO 部署策略,请确保设置适用于容器的应用程序网关资源和 ALB 控制器

  2. 如果遵循 ALB 托管部署策略,请确保预配 ALB 控制器,并通过 ApplicationLoadBalancer 自定义资源预配适用于容器的应用程序网关资源。

  3. 部署示例 HTTP 应用程序:

    在群集上应用以下 deployment.yaml 文件来创建示例 Web 应用程序并部署示例机密,以演示前端相互身份验证 (mTLS)。

    kubectl apply -f https://raw.githubusercontent.com/MicrosoftDocs/azure-docs/refs/heads/main/articles/application-gateway/for-containers/examples/https-scenario/ssl-termination/deployment.yaml
    

    此命令在群集上创建以下内容:

    • 名为 test-infra 的命名空间
    • test-infra 命名空间中一个名为 echo 的服务
    • test-infra 命名空间中名为 echo 的一个部署
    • test-infra 命名空间中名为 listener-tls-secret 的一个机密

生成证书

在此示例中,我们将创建根证书,并从根颁发客户端证书。 如果已有根证书和客户端证书,则可以跳过这些步骤。

生成根证书的私钥

openssl genrsa -out root.key 2048

生成根证书

openssl req -x509 -new -nodes -key root.key -sha256 -days 1024 -out root.crt -subj "/C=US/ST=North Dakota/L=Fargo/O=Contoso/CN=contoso-root"

生成客户端证书的私钥

openssl genrsa -out client.key 2048

为客户端证书创建证书签名请求

openssl req -new -key client.key -out client.csr -subj "/C=US/ST=North Dakota/L=Fargo/O=Contoso/CN=contoso-client"

生成由根证书签名的客户端证书

openssl x509 -req -in client.csr -CA root.crt -CAkey root.key -CAcreateserial -out client.crt -days 1024 -sha256

部署所需的网关 API 资源

创建网关

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway-01
  namespace: test-infra
  annotations:
    alb.networking.azure.io/alb-namespace: alb-test-infra
    alb.networking.azure.io/alb-name: alb-test
spec:
  gatewayClassName: azure-alb-external
  listeners:
  - name: mtls-listener
    port: 443
    protocol: HTTPS
    allowedRoutes:
      namespaces:
        from: Same
    tls:
      mode: Terminate
      certificateRefs:
      - kind : Secret
        group: ""
        name: listener-tls-secret
EOF

注意

当 ALB 控制器在 ARM 中创建适用于容器的应用程序网关时,它将对前端资源使用以下命名约定:fe-<8 个随机生成的字符>

如果要更改在 Azure 中创建的前端的名称,请考虑按照创建自己的部署策略中的说明进行操作。

创建网关资源后,请确保状态有效,侦听器已编程,并地址已分配给网关。

kubectl get gateway gateway-01 -n test-infra -o yaml

成功创建了网关时的示例输出:

status:
  addresses:
  - type: IPAddress
    value: xxxx.yyyy.alb.azure.com
  conditions:
  - lastTransitionTime: "2023-06-19T21:04:55Z"
    message: Valid Gateway
    observedGeneration: 1
    reason: Accepted
    status: "True"
    type: Accepted
  - lastTransitionTime: "2023-06-19T21:04:55Z"
    message: Application Gateway For Containers resource has been successfully updated.
    observedGeneration: 1
    reason: Programmed
    status: "True"
    type: Programmed
  listeners:
  - attachedRoutes: 0
    conditions:
    - lastTransitionTime: "2023-06-19T21:04:55Z"
      message: ""
      observedGeneration: 1
      reason: ResolvedRefs
      status: "True"
      type: ResolvedRefs
    - lastTransitionTime: "2023-06-19T21:04:55Z"
      message: Listener is accepted
      observedGeneration: 1
      reason: Accepted
      status: "True"
      type: Accepted
    - lastTransitionTime: "2023-06-19T21:04:55Z"
      message: Application Gateway For Containers resource has been successfully updated.
      observedGeneration: 1
      reason: Programmed
      status: "True"
      type: Programmed
    name: https-listener
    supportedKinds:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute

创建网关后,请创建 HTTPRoute 资源。

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: https-route
  namespace: test-infra
spec:
  parentRefs:
  - name: gateway-01
  rules:
  - backendRefs:
    - name: echo
      port: 80
EOF

创建 HTTPRoute 资源后,请确保路由被接受,并且适用于容器的应用程序网关已编程

kubectl get httproute https-route -n test-infra -o yaml

验证是否已成功更新适用于容器的应用程序网关资源的状态。

status:
  parents:
  - conditions:
    - lastTransitionTime: "2023-06-19T22:18:23Z"
      message: ""
      observedGeneration: 1
      reason: ResolvedRefs
      status: "True"
      type: ResolvedRefs
    - lastTransitionTime: "2023-06-19T22:18:23Z"
      message: Route is Accepted
      observedGeneration: 1
      reason: Accepted
      status: "True"
      type: Accepted
    - lastTransitionTime: "2023-06-19T22:18:23Z"
      message: Application Gateway For Containers resource has been successfully updated.
      observedGeneration: 1
      reason: Programmed
      status: "True"
      type: Programmed
    controllerName: alb.networking.azure.io/alb-controller
    parentRef:
      group: gateway.networking.k8s.io
      kind: Gateway
      name: gateway-01
      namespace: test-infra

使用 kubectl 创建 Kubernetes 机密(其中包含客户端证书的证书链)。

kubectl create secret generic ca.bundle -n test-infra --from-file=ca.crt=root.crt

创建 FrontendTLSPolicy

kubectl apply -f - <<EOF
apiVersion: alb.networking.azure.io/v1
kind: FrontendTLSPolicy
metadata:
  name: mtls-policy
  namespace: test-infra
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: Gateway
    name: gateway-01
    namespace: test-infra
    sectionNames:
    - mtls-listener
  default:
    verify:
      caCertificateRef:
        name: ca.bundle
        group: ""
        kind: Secret
        namespace: test-infra
EOF

创建 FrontendTLSPolicy 对象后,请检查对象的状态以确保策略有效:

kubectl get frontendtlspolicy mtls-policy -n test-infra -o yaml

创建有效 FrontendTLSPolicy 对象的示例输出:

status:
  conditions:
  - lastTransitionTime: "2023-06-29T16:54:42Z"
    message: Valid FrontendTLSPolicy
    observedGeneration: 1
    reason: Accepted
    status: "True"
    type: Accepted

测试对应用程序的访问

现在,我们已准备好通过分配给前端的 FQDN 将一些流量发送到示例应用程序。 使用以下命令获取 FQDN:

fqdn=$(kubectl get gateway gateway-01 -n test-infra -o jsonpath='{.status.addresses[0].value}')

在没有客户端证书的情况下,对前端的 FQDN 使用 curl。

curl --insecure https://$fqdn/

请注意,响应提示需要证书。

curl: (56) OpenSSL SSL_read: OpenSSL/1.1.1k: error:1409445C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required, errno 0

对显示生成的客户端证书的 FQDN 使用 curl。

curl --cert client.crt --key client.key --insecure https://$fqdn/

请注意,响应来自适用于容器的应用程序网关后面的后端服务。

恭喜,你已安装 ALB 控制器、部署了后端应用程序、通过客户端证书进行了身份验证,并通过适用于容器的应用程序网关从后端服务返回了流量。