AWS ACM 如何与 Kubernetes 配合使用?

更新时间 2022-12-14

为什么需要 AWS ACM

手动管理证书带来的问题

证书包含持有者、颁发者、失效日期等信息。为了确保证书能够被安全地使用,同时也确保证书能够被及时吊销和续订,证书的相关信息需要被记录下来,例如可以手动记录到电子表格中。但随着管理的证书越来越多,手动管理的方式容易因遗漏而导致证书中断,它无法根据新信息和法规自动更新。因为证书到期之前电子表格不会通知您,也不会自动为即将到期的证书续订。手动管理的方式不可避免会操作失误,这将为您带来不必要的风险。这时,自动管理证书的方式应运而生,它将减少您的工作负担和手工操作带来的风险。

ACM 自动管理证书

AWS Certificate Manager(ACM) 可以轻松预置、管理、部署和续订 SSL/TLS 证书。您可以直接通过 ACM 签发证书保护您的 AWS 网站和应用程序,或者将第三方证书导入 ACM 管理系统中。使用 ACM,您无需经历过去与使用和管理 SSL/TLS 证书相关的大量手动流程。您还可以导出由 AWS Private CA 签名的 ACM 证书,以便在内部 PKI 中的任何位置使用。同时,还集成了 AWS Elastic Load Balancing(ELB)。

acm

ACM Private CA 解决了哪些问题

当组织中没有任何 Private CA,在部署内部应用程序时,他们都使用了自签名证书。这些应用程序相互访问时,由于对方的不受信任而拒绝访问,如果盲目信任未知来源的应用程序会带来安全风险。这就需要有一个 Private CA 的托管服务,负责创建和管理 CA 层次结构,确保组织内的应用程序之间是受信任的。

ACM Private CA 就是一种高可用的托管服务,用于为您的组织创建和维护内部公钥基础设施,消除了持续维护的成本。私钥存储在经过 FIPS 140-2 认证的 AWS 托管硬件安全模块 (HSM) 中。与 Kubernetes 中的默认 CA 相比,提供更安全的证书颁发机构解决方案。

pca

如何与 Kubernetes 配合使用

在 Kubernetes 中终止 TLS 证书有两种配置方式:

配置方式

  • 在 NLB 终止:对于一些使用公开信任的证书,在 NLB 级别终止 TLS 证书是最常见的用例。此方式易于配置,将 ACM 公开信任证书绑定到 NLB。集群内部进行应用的访问依然用的是 HTTP 访问方式,无需额外的加解密运算。
  • 在 Ingress 终止: 当应用之间有加密需求,需要在 Ingress controller 中终止 TLS 。每个应用都可以通过 Ingress 管理自己的证书,互不干扰,能够保证应用之间的通信是受信任的,此方式更易于配置和管理。

在后续的演示示例中,您可以在 Amazon EKS 上设置 APISIX Ingress,我们将会根据这两种方式演示 APISIX Ingress 如何与 ACM 配合使用(以及 ACM Private CA)。

预置环境

开始之前,您需要具备以下条件:

Amazon EKS 集群

Amazon EKS 是一种托管服务,您可以使用它在 AWS 上运行 Kubernetes,轻松地部署和管理您的 Kubernetes 集群。本文将使用 eksctl 命令工具来管理集群。

  • 使用 eksctl 默认配置创建集群(如果您已有 EKS 集群请忽略)
1eksctl create cluster

安装 APISIX Ingress

  1. 在 EKS 集群中安装 APISIX Ingress,并设置为 LoadBalancer 类型。
1helm repo add apisix https://charts.apiseven.com
2helm repo add bitnami https://charts.bitnami.com/bitnami
3helm repo update
4
5helm install apisix apisix/apisix \
6  --set gateway.type=LoadBalancer \
7  --set gateway.tls.enabled=true \
8  --set ingress-controller.enabled=true \
9  --namespace ingress-apisix \
10  --create-namespace

:::note

请确保您的集群能够添加持久性卷,详情请参阅 Amazon EKS Storage。 如果只是为了体验本教程,需要在安装时配置 --set etcd.persistence.enabled=false 声明不使用持久性卷。

:::

  1. 运行以下命令检查状态,确保全部 Pod 处于 Running。
1$ kubectl get pods -n ingress-apisix
2NAME                                         READY   STATUS    RESTARTS   AGE
3apisix-78bfc58588-qspmm                      1/1     Running   0          103s
4apisix-etcd-0                                1/1     Running   0          103s
5apisix-etcd-1                                1/1     Running   0          103s
6apisix-etcd-2                                1/1     Running   0          103s
7apisix-ingress-controller-6ff56cd4b4-rktr9   1/1     Running   0          103s
  1. 检查 NLB 状态,这里重点关注 PORT(S) 和 EXTERNAL-IP。
1$ kubectl get svc apisix-gateway -n ingress-apisix
2NAME             TYPE           CLUSTER-IP      EXTERNAL-IP                                                                    PORT(S)                      AGE
3apisix-gateway   LoadBalancer   10.100.178.65   a6cffe9f6fc5c47b9929cb758610fc5a-2074689558.ap-northeast-1.elb.amazonaws.com   80:30851/TCP,443:32735/TCP   103s

在 NLB 终止 TLS 证书

准备 ACM 证书

  1. 打开 ACM 控制台,为你的自定义域申请公共 ACM 证书或导入自定义证书

acm

LoadBalancer 配置证书

  1. 打开 EC2 控制台,选择您的 Load Balancers(负载均衡器) -> 侦听器 -> edit

nlb-1

  1. NLB 协议设置为 HTTPS,端口 443,实例协议设置为 HTTP,端口 30851。

nlb-2

  1. 将 ACM 中的 TLS 证书附加到 NLB。

nlb-3

将自定义域与负载均衡器名称关联

您可以使用 DNS 提供商的控制台,通过 CNAME 将应用程序的 DNS 记录指向 NLB 的 URL。例如 Route53并设置指向您的 NLB 的 CNAME 记录

1httpbin.example-test.org CNAME a6cffe9f6fc5c47b9929cb758610fc5a-2074689558.ap-northeast-1.elb.amazonaws.com

访问应用域名

1curl https://httpbin.example-test.org

在 Ingress 终止 TLS 证书

在开始本示例前,请确保 AWS NLB 的配置已恢复如下图片所示:

nls-0

安装 cert-manager

cert-manager 是一个 Kubernetes 附加组件,可用于自动管理和颁发来自各种颁发来源的 TLS 证书,您可以在常规方式安装 cert-manager

创建 ACM Private CA

  1. 打开 ACM PCA 控制台,选择创建证书,并安装

pca-1

  1. 在 CA 成功创建后,状态为 active,其中 PCA 的 ARN 将会在后续流程中多次使用。

pca-2

为 ACM Private CA 设置 EKS 节点权限

默认情况下是无颁发权限,为了从 ACM Private CA 颁发证书,需要将 IAM 策略添加到 EKS NodeInstanceRole 中,包括 iamserviceaccount 服务角色。

  1. 创建 pca-iam-policy.json 文件,需要将 ${PCA_ARN} 替换成您的 PCA_ARN
1{
2    "Version": "2012-10-17",
3    "Statement": [
4        {
5            "Sid": "awspcaissuer",
6            "Action": [
7                "acm-pca:DescribeCertificateAuthority",
8                "acm-pca:GetCertificate",
9                "acm-pca:IssueCertificate"
10            ],
11            "Effect": "Allow",
12            "Resource": "${PCA_ARN}"
13        }
14    ]
15}
  1. 根据 pca-iam-policy.json 创建 IAM 和 iamserviceaccount,需要将 ${account_id} 替换为您的 Amazon 账户ID。
1aws iam create-policy \
2    --policy-name AWSPCAIssuerIAMPolicy \
3    --policy-document file://pca-iam-policy.json
4
5# 创建命名空间
6
7kubectl create namespace aws-pca-issuer
8
9eksctl create iamserviceaccount \
10    --cluster=${cluster_name} \
11    --namespace=aws-pca-issuer \
12    --name=aws-pca-issuer \
13    --attach-policy-arn=arn:aws:iam::${account_id}:policy/AWSPCAIssuerIAMPolicy \
14    --override-existing-serviceaccounts \
15    --approve

安装 aws-privateca-issuer

AWS PrivateCA Issuer 充当 cert-manager 的插件(External Issuers)签署证书请求。

  1. 使用 Helm 安装
1helm repo add awspca https://cert-manager.github.io/aws-privateca-issuer
2helm repo update
3
4helm install aws-pca-issuer awspca/aws-privateca-issuer \
5    -n aws-pca-issuer \
6    --set serviceAccount.create=false \
7    --set serviceAccount.name=aws-pca-issuer
  1. 查看状态
1$ kubectl get pods -n aws-pca-issuer
2NAME                                                   READY   STATUS    RESTARTS   AGE
3aws-pca-issuer-aws-privateca-issuer-5cdd4b4687-z52n7   1/1     Running   0          20s

创建颁发者并申请证书

  1. 将 issuer-cert.yaml 文件中的 ${PCA_ARN} 替换成您的配置,并执行如下命令:
  • kubectl apply -f issuer-cert.yaml
1# issuer-cert.yaml
2apiVersion: awspca.cert-manager.io/v1beta1
3kind: AWSPCAClusterIssuer
4metadata:
5  name: demo-test-root-ca
6spec:
7  arn: ${PCA_ARN}
8
9---
10
11kind: Certificate
12apiVersion: cert-manager.io/v1
13metadata:
14  name: nlb-lab-tls-cert
15spec:
16  commonName: httpbin.example-test.org # 需要替换成您的自定义域名
17  dnsNames:
18    - httpbin.example-test.org # 需要替换为您的自定义域名
19  duration: 2160h0m0s
20  issuerRef:
21    group: awspca.cert-manager.io
22    kind: AWSPCAClusterIssuer
23    name: demo-test-root-ca
24  renewBefore: 360h0m0s
25  secretName: nlb-tls-app-secret
26  usages:
27    - server auth
28    - client auth
29  privateKey:
30    algorithm: "RSA"
31    size: 2048
  1. 运行以下命令验证证书是否已颁发,secret 是否已生成。
1$ kubectl get cert
2NAME                READY   SECRET                AGE
3nlb-lab-tls-cert    True    nlb-tls-app-secret    10s
4
5$ kubectl get secret
6NAME                  TYPE                                  DATA   AGE
7nlb-tls-app-secret    kubernetes.io/tls                     3      8s

公开并保护 httpbin 应用程序

请确保 APISIX Ingress 已成功安装

  1. 部署 httpbin 应用程序
1kubectl run httpbin --image kennethreitz/httpbin --port 80
2kubectl expose pod httpbin --port 80
  1. 创建 Ingress 以公开并保护 httpbin 应用程序
  • kubectl apply -f ingress-httpbin.yaml
1# ingress-httpbin.yaml
2apiVersion: networking.k8s.io/v1
3kind: Ingress
4metadata:
5  name: httpbin-demo-apisix
6spec:
7  ingressClassName: apisix
8  tls:
9  - hosts:
10    - httpbin.example-test.org
11    secretName: nlb-tls-app-secret
12  rules:
13  - host: httpbin.example-test.org
14    http:
15      paths:
16      - backend:
17          service:
18            name: httpbin
19            port:
20              number: 80
21        path: /
22        pathType: Prefix
  1. 访问应用域名

请确保您的自定义域已与负载均衡器名称关联

1$ curl https://httpbin.example-test.org/headers --cacert acm-pca/cacert.pem
2{
3  "headers": {
4    "Accept": "*/*",
5    "Host": "httpbin.example-test.org",
6    "User-Agent": "curl/7.74.0",
7    "X-Forwarded-Host": "httpbin.example-test.org"
8  }
9}

总结

本文中通过实践演示了 APISIX Ingress 与 AWS ACM 和 ACM Private CA 组件配合使用,并介绍了在 Kubernetes 中终止 TLS 证书的两种配置方式。在公开信任的证书中,ACM + NLB 的配置方式会更合适。如果应用之间有加密的要求,ACM Private CA 提供了安全性更强的托管服务。希望本文的实践环节能帮助读者在 AWS EKS 集群中更有效配置和管理 TLS 流量。