为什么需要 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 Private CA 解决了哪些问题
当组织中没有任何 Private CA,在部署内部应用程序时,他们都使用了自签名证书。这些应用程序相互访问时,由于对方的不受信任而拒绝访问,如果盲目信任未知来源的应用程序会带来安全风险。这就需要有一个 Private CA 的托管服务,负责创建和管理 CA 层次结构,确保组织内的应用程序之间是受信任的。
ACM Private CA 就是一种高可用的托管服务,用于为您的组织创建和维护内部公钥基础设施,消除了持续维护的成本。私钥存储在经过 FIPS 140-2 认证的 AWS 托管硬件安全模块 (HSM) 中。与 Kubernetes 中的默认 CA 相比,提供更安全的证书颁发机构解决方案。
如何与 Kubernetes 配合使用
在 Kubernetes 中终止 TLS 证书有两种配置方式:
- 在 NLB 终止:对于一些使用公开信任的证书,在 NLB 级别终止 TLS 证书是最常见的用例。此方式易于配置,将 ACM 公开信任证书绑定到 NLB。集群内部进行应用的访问依然用的是 HTTP 访问方式,无需额外的加解密运算。
- 在 Ingress 终止: 当应用之间有加密需求,需要在 Ingress controller 中终止 TLS 。每个应用都可以通过 Ingress 管理自己的证书,互不干扰,能够保证应用之间的通信是受信任的,此方式更易于配置和管理。
在后续的演示示例中,您可以在 Amazon EKS 上设置 APISIX Ingress,我们将会根据这两种方式演示 APISIX Ingress 如何与 ACM 配合使用(以及 ACM Private CA)。
预置环境
开始之前,您需要具备以下条件:
- AWS 账号与 AWS 命令行界面(AWS CLI).
- 您必须有权使用 Amazon EKS IAM 角色和服务相关角色、AWS CloudFormation、Amazon Virtual Private Cloud (Amazon VPC)和相关资源。请参阅 IAM 用户指南中的适用于 Kubernetes 的 Amazon Elastic Container Service 的操作、资源和条件键以及使用服务相关角色。此外,此 IAM 安全主体需要附加一个 AWSCertificateManagerPrivateCAFullAccess IAM 托管策略。
- 安装并配置了 kubectl 和 eksctl 工具。
Amazon EKS 集群
Amazon EKS 是一种托管服务,您可以使用它在 AWS 上运行 Kubernetes,轻松地部署和管理您的 Kubernetes 集群。本文将使用 eksctl 命令工具来管理集群。
- 使用 eksctl 默认配置创建集群(如果您已有 EKS 集群请忽略)
1eksctl create cluster
安装 APISIX Ingress
- 在 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
声明不使用持久性卷。
:::
- 运行以下命令检查状态,确保全部 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
- 检查 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 证书
- 打开 ACM 控制台,为你的自定义域申请公共 ACM 证书或导入自定义证书
LoadBalancer 配置证书
- 打开 EC2 控制台,选择您的 Load Balancers(负载均衡器) -> 侦听器 -> edit。
- NLB 协议设置为 HTTPS,端口 443,实例协议设置为 HTTP,端口 30851。
- 将 ACM 中的 TLS 证书附加到 NLB。
将自定义域与负载均衡器名称关联
您可以使用 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 的配置已恢复如下图片所示:
安装 cert-manager
cert-manager 是一个 Kubernetes 附加组件,可用于自动管理和颁发来自各种颁发来源的 TLS 证书,您可以在常规方式安装 cert-manager。
创建 ACM Private CA
- 打开 ACM PCA 控制台,选择创建证书,并安装
- 在 CA 成功创建后,状态为 active,其中 PCA 的 ARN 将会在后续流程中多次使用。
为 ACM Private CA 设置 EKS 节点权限
默认情况下是无颁发权限,为了从 ACM Private CA 颁发证书,需要将 IAM 策略添加到 EKS NodeInstanceRole 中,包括 iamserviceaccount 服务角色。
- 创建 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}
- 根据 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)签署证书请求。
- 使用 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$ 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
创建颁发者并申请证书
- 将 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
- 运行以下命令验证证书是否已颁发,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 应用程序
- 部署 httpbin 应用程序
1kubectl run httpbin --image kennethreitz/httpbin --port 80
2kubectl expose pod httpbin --port 80
- 创建 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$ 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 流量。