How to do a HTTPS Redirect with Kubernetes Traefik Ingress and get automatic HTTPS Certificates with LetsEncrypt and Infomaniak with a ClusterIssuer
This blog post explores an end-to-end setup of how to automatically generate https certificates on Kubernetes ingresses with the Traefik Ingress controller.
HTTPS Redirect
In order to redirect an ingress to https, first we have tho create the Traefik Middleware handling the redirect.
Important: The apiVersion string is different for Traefik v3. The below applies to Traefik V3; if you're using Traefik V2, then the apiVersion needs to be specified as follows: apiVersion: traefik.containo.us/v1alpha1.
```yaml
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: redirect-https
namespace: default
spec:
redirectScheme:
scheme: https
permanent: true
---
Ingress Config
With a ClusterIssuer (see below) and the redirect configured, any ingress can be configured to use https (and to redirect all traffik to https) with the following 2 annotations. To use the http challenge instead of the dns challenge, in my setup I just have to change the cluster-issuer to the following: cert-manager.io/cluster-issuer: letsencrypt-http.
Overall it's a relatively simple and lean setup to automatically generate certificates via Kubernetes.
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: foo-ingress
namespace: foo
annotations:
cert-manager.io/cluster-issuer: letsencrypt
traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd
---
HTTPS Certificates with ClusterIssuer and Infomaniak
The setup for the ClusterIssuer is minimal, provided the required secrets are created. The below are examples for the dns01 and the http01 solvers; this allows for https certificates to be generated either via http or via dns challenge. The dns challenge is more powerful, but requires the dns provider to support cert-manager (or at least the cert-manager-webhook). The advantage of the http challenge is that you don't even need to have access to the DNS zone of the domain (so you don't need to be a domain owner). That simplifies the setup.
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: 'raphael@akehir.com'
server: 'https://acme-v02.api.letsencrypt.org/directory'
privateKeySecretRef:
name: letsencrypt
solvers:
- dns01:
webhook:
groupName: acme.infomaniak.com
solverName: infomaniak
config:
apiTokenSecretRef:
name: infomaniak-api-credentials
key: api-token
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-http
spec:
acme:
email: 'raphael@akehir.com'
server: 'https://acme-v02.api.letsencrypt.org/directory'
privateKeySecretRef:
name: letsencrypt-http
solvers:
- http01:
ingress:
class: traefik
---
Infomaniak WebHook Setup
The below yaml is basically the result of following the instructions by Infomaniak on Github. I created the necessary secrets and applied the below config to have an Infomaniak ClusterIssuer running. It has been solving Letsencrypt https certificates with the dns challenge just nicely.
---
# Source: infomaniak-webhook/templates/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: 'cert-manager-infomaniak'
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
---
# Source: infomaniak-webhook/templates/rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: infomaniak-webhook
namespace: 'cert-manager-infomaniak'
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
---
# Source: infomaniak-webhook/templates/rbac.yaml
# Grant cert-manager permission to validate using our apiserver
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: infomaniak-webhook:domain-solver
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
rules:
- apiGroups:
- acme.infomaniak.com
resources:
- '*'
verbs:
- 'create'
---
# Source: infomaniak-webhook/templates/rbac.yaml
# apiserver gets the auth-delegator role to delegate auth decisions to
# the core apiserver
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: infomaniak-webhook:auth-delegator
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- apiGroup: ''
kind: ServiceAccount
name: infomaniak-webhook
namespace: cert-manager-infomaniak
---
# Source: infomaniak-webhook/templates/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: infomaniak-webhook:domain-solver
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: infomaniak-webhook:domain-solver
subjects:
- apiGroup: ''
kind: ServiceAccount
name: cert-manager
namespace: cert-manager
# Role to access infomaniak-webhook secrets
---
# Source: infomaniak-webhook/templates/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: infomaniak-webhook:secret-reader
namespace: cert-manager
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
rules:
- apiGroups: ['']
resources:
- 'secrets'
resourceNames: [infomaniak-api-credentials]
verbs:
- 'get'
- 'watch'
- 'list'
# Allow infomaniak-webhook ServiceAccount to read its secrets
---
# Source: infomaniak-webhook/templates/rbac.yaml
# Grant the webhook permission to read the ConfigMap containing the Kubernetes
# apiserver's requestheader-ca-certificate.
# This ConfigMap is automatically created by the Kubernetes apiserver.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: infomaniak-webhook:webhook-authentication-reader
namespace: kube-system
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: extension-apiserver-authentication-reader
subjects:
- apiGroup: ''
kind: ServiceAccount
name: infomaniak-webhook
namespace: cert-manager-infomaniak
---
# Source: infomaniak-webhook/templates/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: infomaniak-webhook:secret-reader
namespace: cert-manager
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: infomaniak-webhook:secret-reader
subjects:
- apiGroup: ''
kind: ServiceAccount
name: infomaniak-webhook
namespace: cert-manager-infomaniak
---
# Source: infomaniak-webhook/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: infomaniak-webhook
namespace: 'cert-manager-infomaniak'
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
spec:
type: ClusterIP
ports:
- port: 443
targetPort: https
protocol: TCP
name: https
selector:
app: infomaniak-webhook
release: infomaniak-webhook
---
# Source: infomaniak-webhook/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: infomaniak-webhook
namespace: 'cert-manager-infomaniak'
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
spec:
replicas: 1
selector:
matchLabels:
app: infomaniak-webhook
release: infomaniak-webhook
template:
metadata:
labels:
app: infomaniak-webhook
release: infomaniak-webhook
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
serviceAccountName: infomaniak-webhook
containers:
- name: infomaniak-webhook
image: 'ghcr.io/infomaniak/cert-manager-webhook-infomaniak:latest'
imagePullPolicy: IfNotPresent
args:
- --v=2
- --tls-cert-file=/tls/tls.crt
- --tls-private-key-file=/tls/tls.key
env:
- name: GROUP_NAME
value: 'acme.infomaniak.com'
ports:
- name: https
containerPort: 443
protocol: TCP
livenessProbe:
httpGet:
scheme: HTTPS
path: /healthz
port: https
readinessProbe:
httpGet:
scheme: HTTPS
path: /healthz
port: https
volumeMounts:
- name: certs
mountPath: /tls
readOnly: true
resources: {}
volumes:
- name: certs
secret:
secretName: infomaniak-webhook-webhook-tls
---
# Source: infomaniak-webhook/templates/apiservice.yaml
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1alpha1.acme.infomaniak.com
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
annotations:
cert-manager.io/inject-ca-from: 'cert-manager-infomaniak/infomaniak-webhook-webhook-tls'
spec:
group: acme.infomaniak.com
groupPriorityMinimum: 1000
versionPriority: 15
service:
name: infomaniak-webhook
namespace: cert-manager-infomaniak
version: v1alpha1
---
# Source: infomaniak-webhook/templates/pki.yaml
# Generate a CA Certificate used to sign certificates for the webhook
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: infomaniak-webhook-ca
namespace: 'cert-manager-infomaniak'
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
spec:
secretName: infomaniak-webhook-ca
duration: 43800h
issuerRef:
name: infomaniak-webhook-selfsign
commonName: 'ca.infomaniak-webhook.cert-manager'
isCA: true
---
# Source: infomaniak-webhook/templates/pki.yaml
# Finally, generate a serving certificate for the webhook to use
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: infomaniak-webhook-webhook-tls
namespace: 'cert-manager-infomaniak'
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
spec:
secretName: infomaniak-webhook-webhook-tls
duration: 8760h
issuerRef:
name: infomaniak-webhook-ca
dnsNames:
- infomaniak-webhook
- infomaniak-webhook.cert-manager-infomaniak
- infomaniak-webhook.cert-manager-infomaniak.svc
---
# Source: infomaniak-webhook/templates/pki.yaml
# Create a selfsigned Issuer, in order to create a root CA certificate for
# signing webhook serving certificates
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: infomaniak-webhook-selfsign
namespace: 'cert-manager-infomaniak'
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
spec:
selfSigned: {}
---
# Source: infomaniak-webhook/templates/pki.yaml
# Create an Issuer that uses the above generated CA certificate to issue certs
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: infomaniak-webhook-ca
namespace: 'cert-manager-infomaniak'
labels:
app: infomaniak-webhook
chart: infomaniak-webhook-0.2.0
release: infomaniak-webhook
heritage: Helm
spec:
ca:
secretName: infomaniak-webhook-ca
---