APISIX Ingress 如何使用 cert-Manager 管理证书

更新时间 2022-10-20

cert-manager 解决了什么问题

Cert-manager 是由 JETSTACK 在 2017 年开源,并在 2020 年 11 月正式捐赠给了 CNCF 成为 sandbox 级别的项目。在 2022 年 10 月正式成为 CNCF incubating 级别的项目。

Cert-manager 主要用来自动化的管理 Kubernetes 和 OpenShift 中的 x509 证书身份,它使证书和证书签发结构成为了 Kubernetes 上第一类支持的资源(通过 CRD 实现),并且允许开发者可以很简单的为应用程序申请证书,以便提升应用访问的安全性。

那么我们来看看在 cert-manager 出现之前,在 Kubernetes 中如何管理证书呢?

Kubernetes 中的证书如何管理

在 Kubernetes 中存储数据主要有以下两种原生的方式:

  • ConfigMap

  • Secret

不过 ConfigMap 中所有的信息都是明文的,存储一些相对普通的配置信息还可以,但对于证书这类比较私密的信息,就不那么适用了。

Kubernetes 在设计的时候就推荐使用 Secret 来存储证书等相关信息,并且还为此提供了默认支持。我们可以很简单的通过 kubectl create secret tls 来存储证书的信息。比如:

1➜  ~ kubectl create secret tls moelove-tls --cert=./cert.pem --key=./cert-key.pem
2secret/moelove-tls created
3➜  ~ kubectl get secret moelove-tls -oyaml
4apiVersion: v1
5data:
6  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNFekNDQWJtZ0F3SUJBZ0lVVHhCTC9aQkdpOEJCOUFVN2JRWi9jK3c2L1Rzd0NnWUlLb1pJemowRUF3SXcKVFRFTE1Ba0dBMVVFQmhNQ1EwNHhFREFPQmdOVkJBY1RCMEpsYVdwcGJtY3hGVEFUQmdOVkJBb1RERTF2WlV4dgpkbVVnU1U1R1R6RVZNQk1HQTFVRUF4TU1iVzlsYkc5MlpTNXBibVp2TUI0WERUSXlNVEF4T1RBM01UY3dNRm9YCkRUSXpNVEF4T1RBM01UY3dNRm93VFRFTE1Ba0dBMVVFQmhNQ1EwNHhFREFPQmdOVkJBY1RCMEpsYVdwcGJtY3gKRlRBVEJnTlZCQW9UREUxdlpVeHZkbVVnU1U1R1R6RVZNQk1HQTFVRUF4TU1iVzlsYkc5MlpTNXBibVp2TUZrdwpFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRVVTcEFjNGE1UXQwQ0NVa2hGSGY3WnZvR1FReVVPUUxSClJhZG0rSUUrV1ZkOThyWkc5NFpob08ybDZSWkY2MnVPN3FpZ2VsaUJwY0FGQ3FzWU9HNnVLcU4zTUhVd0RnWUQKVlIwUEFRSC9CQVFEQWdXZ01CMEdBMVVkSlFRV01CUUdDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFNQmdOVgpIUk1CQWY4RUFqQUFNQjBHQTFVZERnUVdCQlFnS01icnBUb3k4NVcvRy9hMGZtYzlDMUJRbURBWEJnTlZIUkVFCkVEQU9nZ3h0YjJWc2IzWmxMbWx1Wm04d0NnWUlLb1pJemowRUF3SURTQUF3UlFJZ1EzTzhJZ0N2MlRkNUhhV00KcE1LWmRCLzNXdEMreERlSVdPbER6L2hCdzE0Q0lRRExQNG0weFpmSkJvRGc5cERocThGdHN5VDdVZVhVdlZGQQpsS0tReFZNOXFBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
7  tls.key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUsyZjZHQlNZQ0R4eVoycnB2bVZ1YW5MNDhxeW9SK1NiWmxiQzNqSUZybzhvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFVVNwQWM0YTVRdDBDQ1VraEZIZjdadm9HUVF5VU9RTFJSYWRtK0lFK1dWZDk4clpHOTRaaApvTzJsNlJaRjYydU83cWlnZWxpQnBjQUZDcXNZT0c2dUtnPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
8kind: Secret
9metadata:
10  creationTimestamp: "2022-10-19T07:24:26Z"
11  name: moelove-tls
12  namespace: default
13  resourceVersion: "2103326"
14  uid: 14f86514-a1d1-4d99-b000-9ed8b5189d56
15type: kubernetes.io/tls

通过上述命令,在 Kubernetes 中创建了一个名为 moelove-tls 的 secret 资源,并且它是 kubernetes.io/tls 类型的。

应用程序想要使用的时候,直接引用该资源即可从中获取相应的证书信息。多数情况下,我们会将其用于 Ingress 的场景中。比如:

1➜  ~ kubectl create ingress moelove-ing --rule="moelove.info/=moelove:8080,tls=moelove-tls"
2ingress.networking.k8s.io/moelove-ing created
3➜  ~ kubectl get ing moelove-ing -oyaml
4apiVersion: networking.k8s.io/v1
5kind: Ingress
6metadata:
7  creationTimestamp: "2022-10-19T07:32:43Z"
8  generation: 1
9  name: moelove-ing
10  namespace: default
11  resourceVersion: "2104268"
12  uid: b90f09f7-8036-4b9f-9744-a247141ea8da
13spec:
14  rules:
15  - host: moelove.info
16    http:
17      paths:
18      - backend:
19          service:
20            name: moelove
21            port:
22              number: 8080
23        path: /
24        pathType: Exact
25  tls:
26  - hosts:
27    - moelove.info
28    secretName: moelove-tls
29status:
30  loadBalancer: {}

通过上述命令,创建了一个名为 moelove-ing 的 Ingress 资源,并声明其域名为 moelove.info , 且使用 moelove-tls 为此域名添加了证书保护。对应的 Ingress controller 组件获取到此 Ingress 资源后,便可自动的将证书配置给此域名使用,进而提升网站的安全性。

遇到了哪些问题

我们来看看在此过程中遇到了哪些问题呢?

证书签发过程繁琐

上述内容中我并没有演示如何进行证书的签发,如果你对此感兴趣可以查看 OpenSSL 的文档 。在证书的签发过程中,需要理解很多概念。而且签发过程都发生在 Kubernetes 集群之外,不能很好的通过“声明式”配置的方式来了解具体发生了什么事情。尤其是证书可以有多种不同的加密算法,各种不同的配置等。

所以如果使用默认的方式,只能最后将生成的证书和密钥存储在 Kubernetes 的 Secrets 中。

证书续签/重签繁琐

我们都知道证书是有过期时间的,在证书过期或者被吊销之前,必须准备好新的证书,并且保证其过期时间要晚于原证书的过期时间。

在 Kubernetes Secrets 中存储的证书,从这方面考虑的话有些不足:

  • 不存在自动化的过期时间检查

    • 也就是说,你可以在 Kubernetes 中存储任意的证书,无论该证书是否已经过期。
  • 不存在无效数据的检查

    • 也就是说,如果存储在 Kubernetes Secrets 中的数据是损坏的,或者是无效的,那么在 Kubernetes 中也不会有什么特殊的处理。

安全性不足

事实上,存储在 Kubernetes Secretes 中的证书和密钥信息,仅仅是进行了 base64 的编码,任何人只要拿到了此数据,均可对其进行 base64 的解码,进而获取到其中的真实数据。比如:

1➜  ~ kubectl get secrets moelove-tls -o jsonpath='{ .data.tls\.crt }' |base64 -d
2-----BEGIN CERTIFICATE-----
3MIICEzCCAbmgAwIBAgIUTxBL/ZBGi8BB9AU7bQZ/c+w6/TswCgYIKoZIzj0EAwIw
4TTELMAkGA1UEBhMCQ04xEDAOBgNVBAcTB0JlaWppbmcxFTATBgNVBAoTDE1vZUxv
5dmUgSU5GTzEVMBMGA1UEAxMMbW9lbG92ZS5pbmZvMB4XDTIyMTAxOTA3MTcwMFoX
6DTIzMTAxOTA3MTcwMFowTTELMAkGA1UEBhMCQ04xEDAOBgNVBAcTB0JlaWppbmcx
7FTATBgNVBAoTDE1vZUxvdmUgSU5GTzEVMBMGA1UEAxMMbW9lbG92ZS5pbmZvMFkw
8EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUSpAc4a5Qt0CCUkhFHf7ZvoGQQyUOQLR
9Radm+IE+WVd98rZG94ZhoO2l6RZF62uO7qigeliBpcAFCqsYOG6uKqN3MHUwDgYD
10VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV
11HRMBAf8EAjAAMB0GA1UdDgQWBBQgKMbrpToy85W/G/a0fmc9C1BQmDAXBgNVHREE
12EDAOggxtb2Vsb3ZlLmluZm8wCgYIKoZIzj0EAwIDSAAwRQIgQ3O8IgCv2Td5HaWM
13pMKZdB/3WtC+xDeIWOlDz/hBw14CIQDLP4m0xZfJBoDg9pDhq8FtsyT7UeXUvVFA
14lKKQxVM9qA==
15-----END CERTIFICATE-----

通过以上命令便直接拿到了证书相关的原始数据。

另一方面,当我们要更新证书和密钥数据的时候,并不存在二次确认的过程,可以直接进行更新。

这对于大多数场景下都是不符合安全策略的。

接下来我们看看 cert-manager 如何解决这些问题

cert-manager 如何解决

自动签发

Cert-manager 通过 CRD 的方式进行开发和扩展,其添加和实现了 IssuersClusterIssuers 资源,代表证书的签发机构(CA)。

并且支持了多种内置类型,以及可以很方便的与外部组件进行集成,比如:

  • SelfSigned:自签证书

  • CA:提供 CA 进行签发

  • Vault:使用 Vault 进行签发

  • Venafi:使用 Venafi 进行签发

  • External:使用一些外部的组件进行签发,比如:

  • ACME(Automated Certificate Management Environment ):自动化进行证书签发

  1. 通过这些组件可以非常方便的进行证书的签发。后续内容中将会以 Vault 为例进行具体介绍。

自动续签/重签

Cert-manager 中我们可以非常方便的通过 cmctl CTL 手动的进行证书 renew 操作,同时 cert-manager 也会自动的检查证书的有效期和证书的完整性。

如果出现证书过期,或者证书数据不完整,都可以自动触发证书的重新签发,节约了人力成本和维护成本。

安全性保障

Cert-manager 中通过 CRD 的方式增加了 signers 资源,允许对证书请求进行确认,进行 Approved 或者 Denied 。只有 Approve 后,才会真正生效,并签发证书。这样可以更加的安全。

APISIX Ingress 如何与 cert-manager 集成

安装部署

Apache APISIX Ingress 是一个 Kubernetes Ingress controller,可以支持通过 Ingress,自定义资源,以及 Gateway API 等方式进行代理规则的配置。

接下来演示如何将 APISIX Ingress 与 cert-manager 集成,为代理的域名添加 TLS 证书,提升安全性。

同时,我们使用 Vault 进行证书的签发。

部署 APISIX Ingress controller

部署 APISIX Ingress 很简单,仅需要执行如下步骤即可:

1tao@moelove:~$ helm repo add apisix https://charts.apiseven.com
2tao@moelove:~$ helm repo add bitnami https://charts.bitnami.com/bitnami
3tao@moelove:~$ helm repo update
4tao@moelove:~$ helm install apisix apisix/apisix --set gateway.tls.enabled=true --set gateway.type=NodePort   --set ingress-controller.enabled=true   --set ingress-controller.config.apisix.serviceNamespace=apisix   --namespace apisix   --create-namespace   --set ingress-controller.config.apisix.serviceName=apisix-admin --set ingress-controller.config.ingressPublishService="apisix/apisix-gateway"
5NAME: apisix
6LAST DEPLOYED: Wed Oct 19 21:33:37 2022
7NAMESPACE: apisix
8STATUS: deployed
9REVISION: 1
10TEST SUITE: None
11NOTES:
121. Get the application URL by running these commands:
13  export NODE_PORT=$(kubectl get --namespace apisix -o jsonpath="{.spec.ports[0].nodePort}" services apisix-gateway)
14  export NODE_IP=$(kubectl get nodes --namespace apisix -o jsonpath="{.items[0].status.addresses[0].address}")
15  echo http://$NODE_IP:$NODE_PORT

待所有的 Pod 处于 Running 状态便表示已经部署成功。

1tao@moelove:~$ kubectl -n apisix get pods  
2NAME                                         READY   STATUS    RESTARTS   AGE
3apisix-777c9fdd67-rf8zs                      1/1     Running   0          6m48s
4apisix-etcd-0                                1/1     Running   0          6m48s
5apisix-etcd-1                                1/1     Running   0          6m48s
6apisix-etcd-2                                1/1     Running   0          6m48s
7apisix-ingress-controller-568544b554-k7nd4   1/1     Running   0          6m48s

部署 Vault

部署 Vault 的时候,也可以使用 Helm 。这里我增加了一个 --set "server.dev.enabled=true" 配置项,这样在部署后无需进额外操作便可直接使用了。 (注意这个配置不要用到生产环境)

1tao@moelove:~$ helm repo add hashicorp https://helm.releases.hashicorp.com
2tao@moelove:~$ helm install vault hashicorp/vault --set "injector.enabled=false" --set "server.dev.enabled=true"
3NAME: vault
4LAST DEPLOYED: Wed Oct 19 21:53:50 2022
5NAMESPACE: default
6STATUS: deployed
7REVISION: 1
8NOTES:
9Thank you for installing HashiCorp Vault!
10
11Now that you have deployed Vault, you should look over the docs on using
12Vault with Kubernetes available here:
13
14https://www.vaultproject.io/docs/
15
16
17Your release is named vault. To learn more about the release, try:
18
19  $ helm status vault
20  $ helm get manifest vault

在部署完成后,当 Pod 处于 Running 状态时,说明已经部署完成。

1tao@moelove:~$ kubectl get pods  
2NAME      READY   STATUS    RESTARTS   AGE
3vault-0   1/1     Running   0          29s
4tao@moelove:~$ kubectl get svc
5NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)             AGE
6kubernetes       ClusterIP   10.96.0.1      <none>        443/TCP             84m
7vault            ClusterIP   10.96.190.88   <none>        8200/TCP,8201/TCP   4m14s
8vault-internal   ClusterIP   None           <none>        8200/TCP,8201/TCP   4m14s

接下来进入 Vault 内进行操作,此处开启了 pki 的能力,并且配置了对应的 policy。

1tao@moelove:~$ kubectl  exec -it vault-0 -- sh
2/ $ vault secrets enable pki
3Success! Enabled the pki secrets engine at: pki/
4/ $ vault write pki/root/generate/internal common_name=moelove.info ttl=8760h
5Key              Value
6---              -----
7certificate      -----BEGIN CERTIFICATE-----
8MIIDODCCAiCgAwIBAgIUds5uMJV9rOkwFEt6Xof5T2SVFccwDQYJKoZIhvcNAQEL
9...
10VM4DRVgDkqY9JdHU
11-----END CERTIFICATE-----
12expiration       1668983612
13issuer_id        8df13015-7c70-df9a-7bb7-9b3b4afe7f82
14issuer_name      n/a
15issuing_ca       -----BEGIN CERTIFICATE-----
16MIIDODCCAiCgAwIBAgIUds5uMJV9rOkwFEt6Xof5T2SVFccwDQYJKoZIhvcNAQEL
17...
18VM4DRVgDkqY9JdHU
19-----END CERTIFICATE-----
20key_id           c9fcfcb0-3548-a9a7-e706-30510592c797
21key_name         n/a
22serial_number    76:ce:6e:30:95:7d:ac:e9:30:14:4b:7a:5e:87:f9:4f:64:95:15:c7
23/ $
24/ $ vault write pki/config/urls issuing_certificates="http://vault.default:8200/v1/pki/ca" crl_distribution_points="http://vault.default:8200/v1/pki/crl"
25Success! Data written to: pki/config/urls
26/ $ vault write pki/roles/moelove-dot-info allowed_domains=moelove.info allow_subdomains=true max_ttl=72h
27Success! Data written to: pki/roles/moelove-dot-info
28/ $
29/ $ vault policy write pki - <<EOF
30> path "pki*"                        { capabilities = ["read", "list"] }
31> path "pki/sign/moelove-dot-info"    { capabilities = ["create", "update"] }
32> path "pki/issue/moelove-dot-info"   { capabilities = ["create"] }
33> EOF
34Success! Uploaded policy: pki

接下来,配置 Kubernetes 认证:

1/ $ vault auth enable kubernetes
2Success! Enabled kubernetes auth method at: kubernetes/
3/ $ vault write auth/kubernetes/config kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443"
4Success! Data written to: auth/kubernetes/config
5/ $ vault write auth/kubernetes/role/issuer  bound_service_account_names=issuer bound_service_account_namespaces=default policies=pki ttl=20m
6Success! Data written to: auth/kubernetes/role/issuer

完成上述操作后,接下来部署 cert-manager。

部署 cert-manager

现在可以通过 Helm 安装 cert-manager 了,安装的过程也比较简单。

1tao@moelove:~$ helm repo add jetstack https://charts.jetstack.io
2tao@moelove:~$ helm repo update jetstack
3Hang tight while we grab the latest from your chart repositories...
4...Successfully got an update from the "jetstack" chart repository
5Update Complete. ⎈Happy Helming!⎈
6tao@moelove:~$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.0/cert-manager.crds.yaml
7customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
8customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
9customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
10customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
11customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
12customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created
13tao@moelove:~$ helm install \
14>   cert-manager jetstack/cert-manager \
15>   --namespace cert-manager \
16>   --create-namespace \
17>   --version v1.10.0
18
19xNAME: cert-manager
20LAST DEPLOYED: Wed Oct 19 22:51:06 2022
21NAMESPACE: cert-manager
22STATUS: deployed
23REVISION: 1
24TEST SUITE: None
25NOTES:
26cert-manager v1.10.0 has been deployed successfully!
27
28In order to begin issuing certificates, you will need to set up a ClusterIssuer
29or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).
30
31More information on the different types of issuers and how to configure them
32can be found in our documentation:
33
34https://cert-manager.io/docs/configuration/
35
36For information on how to configure cert-manager to automatically provision
37Certificates for Ingress resources, take a look at the `ingress-shim`
38documentation:
39
40https://cert-manager.io/docs/usage/ingress/

接下来检查 Pod 的状态:

1tao@moelove:~$ kubectl -n cert-manager get pods
2NAME                                       READY   STATUS    RESTARTS   AGE
3cert-manager-69b456d85c-znpq4              1/1     Running   0          117s
4cert-manager-cainjector-5f44d58c4b-wcd27   1/1     Running   0          117s
5cert-manager-webhook-566bd88f7b-7rptf      1/1     Running   0          117s

接下来便可以开始配置和验证了。

如何配置及验证

配置和签发证书

1tao@moelove:~$ kubectl create serviceaccount issuer
2serviceaccount/issuer created
3tao@moelove:~$ kubectl get secret
4NAME                          TYPE                 DATA   AGE
5sh.helm.release.v1.vault.v1   helm.sh/release.v1   1      36m
6tao@moelove:~$ vim issuer-secret.yaml
7tao@moelove:~$ cat issuer-secret.yaml
8apiVersion: v1
9kind: Secret
10metadata:
11  name: issuer-token-moelove
12  annotations:
13    kubernetes.io/service-account.name: issuer
14type: kubernetes.io/service-account-token
15tao@moelove:~$ kubectl apply -f issuer-secret.yaml
16secret/issuer-token-moelove created
17tao@moelove:~$ kubectl get sa,secret
18NAME                     SECRETS   AGE
19serviceaccount/default   0         118m
20serviceaccount/issuer    0         2m11s
21serviceaccount/vault     0         38m
22
23NAME                                 TYPE                                  DATA   AGE
24secret/issuer-token-moelove          kubernetes.io/service-account-token   3      35s
25secret/sh.helm.release.v1.vault.v1   helm.sh/release.v1                    1      38m

创建 Issuer

通过此配置将使用 Vault 作为证书签发机构,通过引用在 Vault 中配置的 role 和 secret 等,进行自动的签发。

1tao@moelove:~$ cat vault-issuer.yaml
2apiVersion: cert-manager.io/v1
3kind: Issuer
4metadata:
5  name: vault-issuer
6  namespace: default
7spec:
8  vault:
9    server: http://vault.default
10    path: pki/sign/moelove-dot-info
11    auth:
12      kubernetes:
13        mountPath: /v1/auth/kubernetes
14        role: moelove-dot-info
15        secretRef:
16          name: issuer-token-moelove
17          key: token
18tao@moelove:~$ kubectl apply -f vault-issuer.yaml
19issuer.cert-manager.io/vault-issuer created

创建证书

通过此处的配置即可自动的签发证书,并在后续使用时候可以通过 moelove-info-tls 进行引用。

1tao@moelove:~$ cat moelove-dot-info-cert.yaml
2apiVersion: cert-manager.io/v1
3kind: Certificate
4metadata:
5  name: moelove-info
6  namespace: default
7spec:
8  secretName: moelove-info-tls
9  issuerRef:
10    name: vault-issuer
11  commonName: www.moelove.info
12  dnsNames:
13  - www.moelove.info
14tao@moelove:~$ kubectl apply -f moelove-dot-info-cert.yaml
15certificate.cert-manager.io/moelove-info created

验证

接下来通过代理一个 HTTPBIN 的服务进行验证。

首先创建一个 HTTPBIN 的应用程序,并创建相应的 Service。

1kubectl run httpbin --image kennethreitz/httpbin
2kubectl expose pod httpbin --port=80

然后定义如下资源进行代理和引用证书:

1# Define ApisixTls Objects
2apiVersion: apisix.apache.org/v2
3kind: ApisixTls
4metadata:
5  name: moelove
6spec:
7  hosts:
8  - moelove.info
9  secret:
10    name: moelove-info-tls
11
12---
13# Define the route to access the backend
14apiVersion: apisix.apache.org/v2
15kind: ApisixRoute
16metadata:
17  name: moelove
18spec:
19  http:
20  - name: httpbin
21    match:
22      paths:
23      - /*
24      hosts:
25      - moelove.info
26    backends:
27    - serviceName: httpbin
28      servicePort: 80

将这些资源应用到集群中即可。然后通过 kubectl port-forward 转发 APISIX 的 443 端口到本地后, 进行测试访问:

1$ ~ kubectl port-forward -n ingress-apisix svc/apisix-gateway 8443:443 &
2$ ~ curl -sk https://moelove.info:8443/ip --resolve 'moelove.info:8443:127.0.0.1'
3{
4  "origin": "172.17.18.1"
5}

可以看到,已经正确的为 moelove.info 这个域名配置了 HTTPS 证书,并且通过 APISIX Ingress 为其配置了代理。

总结

本文中介绍了 Kubernetes 中证书的默认存储方式,以及这种方式存在的一些痛点。cert-manager 的出现比较好的解决了这些问题,逐步成为了 Kubernetes 生态中证书签发/管理领域中的事实标准。并且其可以和 Vault 等工具进行集成,更加的安全。

Apache APISIX Ingress 项目致力于打造更好用的 Ingress controller,所以很早就添加了完善的 cert-manager 集成能力。本篇中也通过理论加实践的方式为读者介绍了如何在 Apache APISIX Ingress 中配合使用 cert-manager 通过 Vault 签发的证书,并为应用程序提供 HTTPS 代理。希望对读者能有所帮助。