The Automatic Certificate Management Environment (ACME) protocol automates the process of obtaining and renewing X.509 digital certificates. By using the ACME protocol, a certificate authority (CA) can automatically verify an applicant's ownership of a domain before issuing a certificate. Let's Encrypt is a non-profit public CA that supports the ACME protocol and issues certificates that are trusted by most web browsers. This topic explains how to use cert-manager with Let's Encrypt to issue a browser-trusted HTTPS certificate for a Service Mesh (ASM) ingress gateway.
Prerequisites
-
A Container Service for Kubernetes (ACK) cluster added to an ASM instance of v1.16 or later. For more information, see Add a cluster to an ASM instance and Upgrade an ASM instance.
-
An ingress gateway deployed with ports 80 and 443 exposed. For more information, see Create an ingress gateway.
-
The httpbin application deployed in the cluster associated with the ASM instance. For more information, see Deploy the httpbin application.
-
cert-manager installed. For more information, see Install cert-manager in a cluster.
-
Ingress API support enabled on the ASM gateway. For more information, see Step 1: Enable Ingress API access.
How ACME works in cert-manager
When you use cert-manager, the ACME Issuer component registers user accounts with CA servers that support the ACME protocol. When you create an ACME Issuer, cert-manager generates a private key for secure communication with the ACME CA server. Certificates from public CAs like Let's Encrypt are generally trusted by most web browsers, allowing users to access your website without security warnings. The primary role of a public CA is to prove to the browser that the server is the legitimate owner of the domain. To do this, the public CA must verify that the applicant controls the domain before issuing the certificate. For more details about the ACME protocol, see the Automatic Certificate Management Environment RFC.
Challenges
A challenge is a key mechanism in the ACME protocol used to verify that a certificate applicant owns a domain. During the certificate application process, the ACME CA server requires the client (the applicant) to complete a specific challenge. This ensures that only the legitimate domain owner can obtain a certificate, which improves security and prevents domain impersonation. cert-manager supports two primary challenge types: the HTTP-01 challenge and the DNS-01 challenge.
-
The HTTP-01 challenge requires the server to expose a validation key at a specific, publicly accessible HTTP URL. This URL uses the domain requesting the certificate. When the ACME CA server successfully retrieves this key, it considers the applicant to have control over the domain. To simplify this process, cert-manager automatically modifies the cluster's Ingress resource when an HTTP-01 challenge is configured. It directs requests for the validation URL to a temporary web service that holds the required key and responds to the ACME server's challenge.
-
The DNS-01 challenge works by publishing a specific key as a TXT record in the DNS system. After this TXT record propagates, the ACME CA server can retrieve the key through a standard DNS query to confirm domain ownership. With the proper permissions, cert-manager automatically creates and submits the required TXT record to your DNS provider to fulfill the DNS-01 challenge.
In a production environment, you must confirm whether your certificate authority (CA) supports the ACME protocol. If it does, the ASM ingress gateway can automatically obtain certificates from the CA using cert-manager. For example, Sectigo supports the ACME protocol, and its process is similar to that described in this topic.
Step 1: Prepare a public domain
To use Let's Encrypt to issue a certificate, you need a public domain. You must also point this domain to the ASM ingress gateway that you plan to use. For specific instructions, refer to the documentation from your DNS provider. If you use Alibaba Cloud DNS, see Add a DNS record. For more information about Let's Encrypt, see its Getting Started guide.
Step 2: Create an Issuer for Let's Encrypt
-
Use the KubeConfig for your data plane cluster to create the following resource.
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt-prod-issuer namespace: istio-system spec: acme: email: 'your-email@example.com' # This field is optional but recommended. The ACME server may use this email to send you important notices about your certificate. privateKeySecretRef: name: letsencrypt-prod server: https://acme-v02.api.letsencrypt.org/directory solvers: - http01: ingress: ingressClassName: istioThe Issuer resource above specifies an
http01solver, which uses the Ingress API with aningressClassNameofistio.Notecert-manager supports solvers for both the Ingress API and the Gateway API. ASM also supports both APIs. This example uses the Ingress API.
-
Wait for the Issuer to become ready. Run the following command to check its status.
kubectl -n istio-system get issuer letsencrypt-prod-issuerExpected output:
NAME READY AGE letsencrypt-prod-issuer True 8m3s
Step 3: Issue an ASM gateway certificate
-
Use the KubeConfig for your data plane cluster to create the following resource.
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: istio-ingressgateway-certs namespace: istio-system spec: dnsNames: - ${YOUR_DOMAIN} # test.com issuerRef: group: cert-manager.io kind: Issuer name: letsencrypt-prod-issuer secretName: istio-ingressgateway-certs -
Wait for the Certificate to become ready. Run the following command to check its status.
kubectl -n istio-system get certificate istio-ingressgateway-certsExpected output:
NAME READY SECRET AGE istio-ingressgateway-certs True istio-ingressgateway-certs 59m
How certificate issuance works
After you create the Certificate resource, cert-manager uses the specified Issuer to issue a certificate for the domain. During this process, the configured solver becomes active.
Let's Encrypt uses an HTTP-01 challenge to confirm that the server owns the domain. It sends an HTTP request to the domain and must receive a valid response to complete the verification. In this example, the ingress gateway only has routing rules for the httpbin application, with no explicit configuration for the challenge. Did Let's Encrypt actually send a challenge request? And how did the gateway answer it?
You can run the following command to check the gateway logs and determine if Let's Encrypt sent a challenge request.
kubectl -n istio-system logs ${GATEWAY_POD_NAME} | grep letsencrypt | tail -1
The logs show that the gateway received and successfully handled a request from Let's Encrypt. Because the Issuer is configured with an ingressClassName of istio, cert-manager automatically creates an Ingress resource with the same ingressClassName. This resource forwards the challenge request to the corresponding cert-manager solver, which completes the verification.
You will not see this Ingress resource if you run kubectl -n istio-system get ingress after the certificate is ready. This is because cert-manager automatically cleans up solver-related resources, such as Ingress, Service, and Deployment resources, once cert-manager successfully issues the certificate.
Step 4: Verify the certificate
-
Create the following gateway rule to apply the certificate generated in Step 3 to port 443 of the gateway. For more information, see Manage gateway rules.
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: httpbin-https namespace: default spec: selector: istio: ingressgateway servers: - hosts: - ${YOUR_DOMAIN} port: name: https number: 443 protocol: HTTPS tls: credentialName: istio-ingressgateway-certs mode: SIMPLE -
Update the existing httpbin-vs virtual service with the following content. For more information, see Manage virtual services.
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-vs namespace: default spec: gateways: - httpbin - httpbin-https # Add this line. hosts: - '*' http: - name: test route: - destination: host: httpbin.default.svc.cluster.local port: number: 8000 -
In your web browser, navigate to
https://${YOUR_DOMAIN}.The browser's address bar displays a lock icon. Click the icon (
). The message Connection is secure appears. This indicates that the browser trusts your certificate.