Skip to content

Commit 77de77b

Browse files
Cert-Manager - Let's Encrypt - Ingress API
1 parent f51272f commit 77de77b

File tree

1 file changed

+333
-0
lines changed

1 file changed

+333
-0
lines changed
Lines changed: 333 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,333 @@
1+
---
2+
title: Cert-manager and Let's Encrypt with Application Gateway for Containers - Ingress API
3+
description: Learn how to configure Application Gateway for Containers with certificates managed by CNCF project cert-manager.
4+
services: application-gateway
5+
author: philwelz
6+
ms.service: azure-appgw-for-containers
7+
ms.topic: how-to
8+
ms.date: 3/24/2025
9+
ms.author: jstrom
10+
---
11+
12+
# Cert-manager and Let's Encrypt with Application Gateway for Containers - Ingress API
13+
14+
This guide demonstrates how to use cert-manager to automatically issue and renew SSL/TLS certificates to one or more frontends of your Azure Application Gateway for Containers deployment. We use the Ingress API to configure the necessary resources.
15+
16+
For the purposes of this example, we have cert-manager configure certificates issued from Let's Encrypt to demonstrate an end-to-end deployment, where Application Gateway for Containers is providing TLS offloading.
17+
18+
Insert PICTURE HRE
19+
20+
For certificates to be issued by Let's Encrypt, a challenge is required by the authority to validate domain ownership. This validation happens by allowing cert-manager to create a pod and Ingress resource that exposes an endpoint during certificate issuance, proving your ownership of the domain name.
21+
22+
More details on cert-manager and Let's Encrypt with AKS in general may be found [here](https://cert-manager.io/docs/tutorials/getting-started-aks-letsencrypt/).
23+
24+
## Prerequisites
25+
26+
1. If following the BYO deployment strategy, ensure that you set up your Application Gateway for Containers resources and [ALB Controller](quickstart-deploy-application-gateway-for-containers-alb-controller.md)
27+
2. If following the ALB managed deployment strategy, ensure that you provision your [ALB Controller](quickstart-deploy-application-gateway-for-containers-alb-controller.md) and the Application Gateway for Containers resources via the [ApplicationLoadBalancer custom resource](quickstart-create-application-gateway-for-containers-managed-by-alb-controller.md).
28+
3. Deploy sample HTTP application
29+
Apply the following deployment.yaml file on your cluster to create a sample web application to demonstrate the header rewrite.
30+
31+
```bash
32+
kubectl apply -f https://raw.githubusercontent.com/MicrosoftDocs/azure-docs/refs/heads/main/articles/application-gateway/for-containers/examples/traffic-split-scenario/deployment.yaml
33+
```
34+
35+
This command creates the following on your cluster:
36+
37+
- a namespace called `test-infra`
38+
- two services called `backend-v1` and `backend-v2` in the `test-infra` namespace
39+
- two deployments called `backend-v1` and `backend-v2` in the `test-infra` namespace
40+
41+
### Install Cert-Manager
42+
43+
Install cert-manager using Helm:
44+
45+
```bash
46+
helm repo add jetstack https://charts.jetstack.io --force-update
47+
helm upgrade -i \
48+
cert-manager jetstack/cert-manager \
49+
--namespace cert-manager \
50+
--create-namespace \
51+
--version v1.17.1 \
52+
--set installCRDs=true
53+
```
54+
55+
### Create a ClusterIssuer
56+
57+
Create a ClusterIssuer resource to define how cert-manager will communicate with Let's Encrypt. For this example, an HTTP challenge is used. During challenge, cert-manager creates an `Ingress` resource and corresponding pod presenting a validation endpoint to prove ownership of the domain. This is done by creating a temporary Ingress resource with the `http01` challenge type. This Ingress resource and corresponding pod created by cert-manager will be deleted after the challenge is completed.
58+
59+
>[!Tip]
60+
>Other challenges supported by Let's Encrypt are documented on [letsencrypt.org - Challenge Types](https://letsencrypt.org/docs/challenge-types/)
61+
62+
# [ALB managed deployment](#tab/alb-managed)
63+
64+
1. Create the ClusterIssuer resource
65+
66+
```bash
67+
kubectl apply -f - <<EOF
68+
apiVersion: cert-manager.io/v1
69+
kind: ClusterIssuer
70+
metadata:
71+
name: letsencrypt-prod
72+
spec:
73+
acme:
74+
server: https://acme-v02.api.letsencrypt.org/directory # production endpoint
75+
#server: https://acme-staging-v02.api.letsencrypt.org/directory # staging endpoint
76+
77+
privateKeySecretRef:
78+
name: letsencrypt-private-key
79+
solvers:
80+
- http01:
81+
ingress:
82+
ingressClassName: azure-alb-external
83+
# This section is required for the Ingress resource created by cert-manager during the challenge
84+
ingressTemplate:
85+
metadata:
86+
annotations:
87+
alb.networking.azure.io/alb-name: alb-test
88+
alb.networking.azure.io/alb-namespace: alb-test-infra
89+
EOF
90+
```
91+
92+
# [Bring your own (BYO) deployment](#tab/byo)
93+
94+
1. Set the following environment variables
95+
96+
```bash
97+
RESOURCE_GROUP='<resource group name of the Application Gateway For Containers resource>'
98+
RESOURCE_NAME='alb-test'
99+
100+
RESOURCE_ID=$(az network alb show --resource-group $RESOURCE_GROUP --name $RESOURCE_NAME --query id -o tsv)
101+
FRONTEND_NAME='frontend'
102+
```
103+
104+
2. Create the ClusterIssuer resource
105+
106+
```bash
107+
kubectl apply -f - <<EOF
108+
apiVersion: cert-manager.io/v1
109+
kind: ClusterIssuer
110+
metadata:
111+
name: letsencrypt-prod
112+
namespace: test-infra
113+
spec:
114+
acme:
115+
server: https://acme-v02.api.letsencrypt.org/directory # production endpoint
116+
#server: https://acme-staging-v02.api.letsencrypt.org/directory # staging endpoint
117+
118+
privateKeySecretRef:
119+
name: letsencrypt-private-key
120+
solvers:
121+
- http01:
122+
ingress:
123+
ingressClassName: azure-alb-external
124+
# This section is required for the Ingress resource created by cert-manager during the challenge
125+
ingressTemplate:
126+
metadata:
127+
annotations:
128+
alb.networking.azure.io/alb-id: $RESOURCE_ID
129+
alb.networking.azure.io/alb-frontend: $FRONTEND_NAME
130+
EOF
131+
```
132+
133+
Verify the resource was created by running the following command:
134+
135+
```bash
136+
kubectl get ClusterIssuer -A -o yaml
137+
```
138+
139+
The status should show `True` and type `Ready` under contidions.
140+
141+
```yaml
142+
status:
143+
acme:
144+
lastPrivateKeyHash: x+xxxxxxxxxxxxxxxxxxxxxxx+MY4PAEeotr9XH3V7I=
145+
lastRegisteredEmail: [email protected]
146+
uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/190567584
147+
conditions:
148+
- lastTransitionTime: "2025-03-20T16:00:21Z"
149+
message: The ACME account was registered with the ACME server
150+
observedGeneration: 1
151+
reason: ACMEAccountRegistered
152+
status: "True"
153+
type: Ready
154+
```
155+
156+
## Deploy the required Ingress resource
157+
158+
# [ALB managed deployment](#tab/alb-managed)
159+
160+
1. Create an Ingress
161+
162+
```bash
163+
kubectl apply -f - <<EOF
164+
apiVersion: networking.k8s.io/v1
165+
kind: Ingress
166+
metadata:
167+
name: ingress-01
168+
namespace: test-infra
169+
annotations:
170+
alb.networking.azure.io/alb-name: alb-test
171+
alb.networking.azure.io/alb-namespace: alb-test-infra
172+
cert-manager.io/cluster-issuer: letsencrypt-prod
173+
spec:
174+
ingressClassName: azure-alb-external
175+
tls:
176+
- hosts:
177+
- backend-v1.contoso.com
178+
# - backend-v2.contoso.com # You can uncomment this and the host line to add an aditional subject alternate name (SAN) to the certificate
179+
secretName: tls-backend
180+
rules:
181+
- host: backend-v1.contoso.com
182+
http:
183+
paths:
184+
- path: /
185+
pathType: Prefix
186+
backend:
187+
service:
188+
name: backend-v1
189+
port:
190+
number: 8080
191+
# - host: backend-v2.contoso.com
192+
# http:
193+
# paths:
194+
# - path: /
195+
# pathType: Prefix
196+
# backend:
197+
# service:
198+
# name: backend-v2
199+
# port:
200+
# number: 8080
201+
EOF
202+
```
203+
204+
# [Bring your own (BYO) deployment](#tab/byo)
205+
206+
1. Set the following environment variables
207+
208+
```bash
209+
RESOURCE_GROUP='<resource group name of the Application Gateway For Containers resource>'
210+
RESOURCE_NAME='alb-test'
211+
212+
RESOURCE_ID=$(az network alb show --resource-group $RESOURCE_GROUP --name $RESOURCE_NAME --query id -o tsv)
213+
FRONTEND_NAME='frontend'
214+
```
215+
216+
2. Create an Ingress resource
217+
218+
```bash
219+
kubectl apply -f - <<EOF
220+
apiVersion: networking.k8s.io/v1
221+
kind: Ingress
222+
metadata:
223+
name: ingress-01
224+
namespace: test-infra
225+
annotations:
226+
alb.networking.azure.io/alb-id: $RESOURCE_ID
227+
alb.networking.azure.io/alb-frontend: $FRONTEND_NAME
228+
cert-manager.io/cluster-issuer: letsencrypt-prod
229+
spec:
230+
ingressClassName: azure-alb-external
231+
tls:
232+
- hosts:
233+
- backend-v1.contoso.com
234+
# - backend-v2.contoso.com # You can uncomment this and the host line to add an aditional subject alternate name (SAN) to the certificate
235+
secretName: tls-backend
236+
rules:
237+
- host: backend-v1.contoso.com
238+
http:
239+
paths:
240+
- path: /
241+
pathType: Prefix
242+
backend:
243+
service:
244+
name: backend-v1
245+
port:
246+
number: 8080
247+
# - host: backend-v2.contoso.com
248+
# http:
249+
# paths:
250+
# - path: /
251+
# pathType: Prefix
252+
# backend:
253+
# service:
254+
# name: backend-v2
255+
# port:
256+
# number: 8080
257+
EOF
258+
```
259+
260+
---
261+
262+
Once the ingress resource is created, ensure the status shows the hostname of your load balancer:
263+
264+
```bash
265+
kubectl get ingress ingress-01 -n test-infra -o yaml
266+
```
267+
268+
Example output of successful Ingress creation.
269+
270+
```yaml
271+
status:
272+
loadBalancer:
273+
ingress:
274+
- hostname: xxxxxxxxxxxxxxxx.fz13.alb.azure.com
275+
ports:
276+
- port: 443
277+
protocol: TCP
278+
```
279+
280+
As mentioned above, cert-manager will create a temporary Ingress resource and pod to perform the challenge:
281+
282+
```bash
283+
kubectl get pods -n test-infra
284+
NAME READY STATUS RESTARTS AGE
285+
backend-v1-56d99ddb49-mwmcc 1/1 Running 0 10m
286+
backend-v2-8b5d4679b-rsfrg 1/1 Running 0 10m
287+
cm-acme-http-solver-5lmmv 1/1 Running 0 2s
288+
289+
kubectl get ingress -n test-infra
290+
NAME CLASS HOSTS ADDRESS PORTS AGE
291+
cm-acme-http-solver-zrp47 azure-alb-external backend-v1.contoso.com xxxxxxxxxxxxxxxx.fz13.alb.azure.com 80 8s
292+
ingress-01 azure-alb-external backend-v1.contoso.com xxxxxxxxxxxxxxxx.fz13.alb.azure.com 80, 443 10s
293+
```
294+
295+
You can check the status of the challenge by running:
296+
297+
```bash
298+
kubectl get challenges.acme.cert-manager.io -n test-infra
299+
NAME STATE DOMAIN AGE
300+
cert-backend-1-2982214480-3407407859 pending backend-v1.contoso.com 16s
301+
302+
kubectl get certificaterequests.cert-manager.io -n test-infra
303+
NAME APPROVED DENIED READY ISSUER REQUESTER AGE
304+
cert-backend-1 True False letsencrypt-prod system:serviceaccount:cert-manager:cert-manager 34s
305+
```
306+
307+
When the challenge is successful, the status will change to `READY=True` and the certificate will be issued:
308+
309+
```bash
310+
kubectl get certificate -n test-infra
311+
NAME READY SECRET AGE
312+
cert-backend True cert-backend 1m
313+
```
314+
315+
>[!Tip]
316+
>You can synchronize the hostnames of Ingress resources created in AKS automatically with Azure DNS zones by utilizing [External DNS](https://kubernetes-sigs.github.io/external-dns/latest/docs/tutorials/azure/) and [Workload Identity](https://kubernetes-sigs.github.io/external-dns/latest/docs/tutorials/azure/#managed-identity-using-workload-identity).
317+
318+
## Test access to the application
319+
320+
The environment is now configured to route traffic to the sample application using the hostname associated with your certificate.
321+
322+
>[!IMPORTANT]
323+
>Ensure you replace `contoso.com` with the domain name you are expecting the certificate to be issued to.
324+
325+
```bash
326+
curl https://backend-v1.contoso.com -v 2>&1 | grep issuer
327+
```
328+
329+
Upon result, you should see
330+
331+
`* issuer: C=US; O=Let's Encrypt; CN=R11`
332+
333+
You have successfully completed the following steps: installed the ALB Controller, deployed a backend application, obtained a certificate from Let's Encrypt using cert-manager, and configured traffic routing to the application through Application Gateway for Containers

0 commit comments

Comments
 (0)