In this this tutorial, we will learn how to setup E2E SSL with AGIC on Application Gateway.
We will
- Generate the frontend and the backend certificates
- Deploy a simple application with HTTPS
- Upload the backend certificate's root certificate to Application Gateway
- Setup ingress for E2E
Note: Following tutorial makes use of test certificate generated using OpenSSL. These certificates are only for illustration and should be used in testing only.
Let's start by first generating the certificates that we will be using for the frontend and backend SSL.
-
First, we will generate the frontend certificate that will be presented to the clients connecting to the Application Gateway. This will have subject name
CN=frontend
.openssl ecparam -out frontend.key -name prime256v1 -genkey openssl req -new -sha256 -key frontend.key -out frontend.csr -subj "/CN=frontend" openssl x509 -req -sha256 -days 365 -in frontend.csr -signkey frontend.key -out frontend.crt
Note: You can also use a certificate present on the Key Vault on Application Gateway for frontend SSL.
-
Now, we will generate the backend certificate that will be presented by the backends to the Application Gateway. This will have subject name
CN=backend
openssl ecparam -out backend.key -name prime256v1 -genkey openssl req -new -sha256 -key backend.key -out backend.csr -subj "/CN=backend" openssl x509 -req -sha256 -days 365 -in backend.csr -signkey backend.key -out backend.crt
-
Finally, we will install the above certificates on to our kubernetes cluster
kubectl create secret tls frontend-tls --key="frontend.key" --cert="frontend.crt" kubectl create secret tls backend-tls --key="backend.key" --cert="backend.crt"
Here is output after listing the secrets.
> kubectl get secrets NAME TYPE DATA AGE backend-tls kubernetes.io/tls 2 3m18s frontend-tls kubernetes.io/tls 2 3m18s
In this section, we will deploy a simple application exposing an HTTPS endpoint on port 8443.
apiVersion: v1
kind: Service
metadata:
name: website-service
spec:
selector:
app: website
ports:
- protocol: TCP
port: 8443
targetPort: 8443
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: website-deployment
spec:
selector:
matchLabels:
app: website
replicas: 2
template:
metadata:
labels:
app: website
spec:
containers:
- name: website
imagePullPolicy: Always
image: nginx:latest
ports:
- containerPort: 8443
volumeMounts:
- mountPath: /etc/nginx/ssl
name: secret-volume
- mountPath: /etc/nginx/conf.d
name: configmap-volume
volumes:
- name: secret-volume
secret:
secretName: backend-tls
- name: configmap-volume
configMap:
name: website-nginx-cm
---
apiVersion: v1
kind: ConfigMap
metadata:
name: website-nginx-cm
data:
default.conf: |-
server {
listen 8080 default_server;
listen 8443 ssl;
root /usr/share/nginx/html;
index index.html;
ssl_certificate /etc/nginx/ssl/tls.crt;
ssl_certificate_key /etc/nginx/ssl/tls.key;
location / {
return 200 "Hello World!";
}
}
You can also install the above yamls using:
kubectl apply -f https://raw.githubusercontent.com/Azure/application-gateway-kubernetes-ingress/master/docs/examples/sample-https-backend.yaml
Verify that you can curl the application
> kubectl get pods
NAME READY STATUS RESTARTS AGE
website-deployment-9c8c6df7f-5bqwh 1/1 Running 0 24s
website-deployment-9c8c6df7f-wxtnp 1/1 Running 0 24s
> kubectl exec -it website-deployment-9c8c6df7f-5bqwh -- curl -k https://localhost:8443
Hello World!
When you are setting up SSL between Application Gateway and Backend, if you are using a self-signed certificate or a certificate signed by a custom root CA on the backend, then you need to upload self-signed or the Custom root CA of the backend certificate on the Application Gateway.
applicationGatewayName="<gateway-name>"
resourceGroup="<resource-group>"
az network application-gateway root-cert create \
--gateway-name $applicationGatewayName \
--resource-group $resourceGroup \
--name backend-tls \
--cert-file backend.crt
Now, we will configure our ingress to use the frontend
certificate for frontend SSL and backend
certificate as root certificate so that Application Gateway can authenticate the backend.
cat << EOF | kubectl apply -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: website-ingress
annotations:
kubernetes.io/ingress.class: azure/application-gateway
appgw.ingress.kubernetes.io/ssl-redirect: "true"
appgw.ingress.kubernetes.io/backend-protocol: "https"
appgw.ingress.kubernetes.io/backend-hostname: "backend"
appgw.ingress.kubernetes.io/appgw-trusted-root-certificate: "backend-tls"
spec:
tls:
- secretName: frontend-tls
hosts:
- website.com
rules:
- host: website.com
http:
paths:
- path: /
backend:
serviceName: website-service
servicePort: 8443
EOF
For frontend SSL, we have added tls
section in our ingress resource.
tls:
- secretName: frontend-tls
hosts:
- website.com
For backend SSL, we have added the following annotations:
appgw.ingress.kubernetes.io/backend-protocol: "https"
appgw.ingress.kubernetes.io/backend-hostname: "backend"
appgw.ingress.kubernetes.io/appgw-trusted-root-certificate: "backend-tls"
Here, it is important to note that backend-hostname
should be the hostname that the backend will accept and it should also match with the Subject/Subject Alternate Name of the certificate used on the backend.
After you have successfully completed all the above steps, you should be able to see the ingress's IP address and visit the website.
> kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
website-ingress website.com <gateway-ip> 80, 443 36m
> curl -k -H "Host: website.com" https://<gateway-ip>
Hello World!