The Automatic Certificate Management Environment (ACME) protocol automates the process of obtaining and renewing X.509 certificates. The ACME protocol allows a certificate authority (CA) to automatically verify that you own a domain and issue a certificate for it. Let's Encrypt is a non-profit public CA that uses the ACME protocol to issue certificates that are trusted by most web browsers. This topic describes how to use cert-manager with Let's Encrypt to issue a browser-trusted HTTPS certificate for an ASM ingress gateway.
Prerequisites
-
A Container Service for Kubernetes (ACK) cluster added to a Service Mesh (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.
-
Ingress API support enabled on the ASM ingress gateway. For more information, see Step 1: Enable Ingress API access.
ACME in cert-manager
When you use cert-manager, the ACME Issuer component registers a user account with a CA server that supports the ACME protocol. When you create an ACME Issuer, cert-manager generates a private key that is used to securely communicate with the ACME server. Certificates from public CAs like Let's Encrypt are trusted by default in most web browsers. This means that when a user visits your website, their browser automatically trusts the site's SSL/TLS certificate. The primary purpose of a public CA is to prove to the browser that the server is the legitimate owner of the domain. To do this, the CA must verify that the applicant actually controls the domain before issuing a certificate. For more information about the ACME protocol, see Automatic Certificate Management Environment.
Solving challenges
A challenge is how the ACME protocol verifies your domain ownership. During the certificate issuance process, the ACME server requires the client to complete a specific challenge. This ensures that only the legitimate owner of a domain can obtain a certificate for it, which prevents domain spoofing and enhances security. cert-manager supports two main types of challenges: HTTP-01 and DNS-01.
-
The HTTP-01 challenge requires you to prove ownership by placing a file with a validation key at a specific URL on your server. This URL must be publicly accessible and include the domain for which you are requesting the certificate. When the ACME server successfully retrieves the key from this path, it considers the domain validated. To simplify this, cert-manager automates the process. When you configure an HTTP-01 challenge, cert-manager temporarily adjusts your cluster's Ingress resources to route validation requests to a small web service. This service presents the required validation key to the ACME server.
-
The DNS-01 challenge requires you to prove ownership by creating a specific DNS TXT record that contains a validation key. After the record propagates through the DNS system, the ACME server can verify your domain ownership by performing a DNS lookup. If granted the necessary permissions, cert-manager can automatically create and submit the required TXT record to your DNS provider to solve the DNS-01 challenge.
In a production environment, you must confirm whether your certificate authority supports the ACME protocol. If it does, the ASM ingress gateway can automatically obtain a certificate from the CA through cert-manager. For example, Sectigo supports the ACME protocol, which works on a similar principle.
Step 1: Prepare a public domain
To use Let's Encrypt to issue a certificate, you need a public domain that points to the ASM ingress gateway. For specific instructions, refer to the documentation from your DNS provider. If you use Alibaba Cloud DNS, see Add DNS records. For more information about Let's Encrypt, see Getting Started.
Step 2: Create a Let's Encrypt Issuer resource
-
Use the KubeConfig of 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: 'te**@mail.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 preceding Issuer resource specifies an
http01solver that uses the Ingress API with aningressClassNameofistio. The following steps explain how this solver works.Notecert-manager supports both Ingress API and Gateway API solvers. 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 a certificate
-
Use the KubeConfig of 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} # For example, 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
Certificate issuance process
After creating the Certificate resource, cert-manager uses the specified Issuer to issue a certificate for the domain. During this process, the configured solver is activated.
Let's Encrypt uses an HTTP-01 challenge to confirm that the server requesting the certificate owns the domain. To do this, Let's Encrypt sends an HTTP request to the domain and expects to receive a valid response to complete the verification. In this example, the ingress gateway only has routing rules for the httpbin application, with no specific configuration for the challenge. Does Let's Encrypt actually send a challenge request? And how is it answered?
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 log shows that the gateway received and successfully handled a request from Let's Encrypt. Because the Issuer was configured with an ingressClassName of istio, cert-manager automatically creates a temporary Ingress resource with the same ingressClassName of istio. This Ingress resource forwards the challenge request to the cert-manager solver, which completes the verification.
After the Certificate resource is ready, you cannot see the temporary Ingress resource by running kubectl -n istio-system get ingress. This is because cert-manager automatically deletes solver-related resources, such as the Ingress, Service, and Deployment, after the certificate is successfully issued.
Step 4: Verify the certificate
-
Create the following Gateway resource to configure the certificate generated in Step 3 on port 443 of the gateway. For more information, see Manage Istio gateways.
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 -
Modify the existing httpbin-vs virtual service as follows. 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 browser, navigate to
https://${YOUR_DOMAIN}.In the browser's address bar, click the lock
icon. The message Connection is secure appears, indicating that your browser trusts the certificate.