Installing Cert Manager
We want to issue free SSL certificates for ingress https resources.
Treafik has a build in integration with Letsencrypt but unfourtunatelly its is not compatible with a HA setup where you have more than one instance of the ingress running (Deployment with replicas > 1 or DaemonSet). Instead of using it, we will use a separate installation of cert-manager
We will also use the DNS chanllenge type with Cloudflare DNS provider.
Instalation
Is simple with helm:
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.5.4 --set installCRDs=true
Now lets create the token for the DNS challenge:
Go to your domain and select "Get your API token"
Got to "Create token" then select Edit zone DNS template
In "Zone Resources" select the DNS zone you want
In "Permissions" select the following
- Zone - DNS - Edit
- Zone - Zone - Read
Click on generate token
Configuration and Test
Create the cloudflare token:
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-token-secret
namespace: cert-manager
type: Opaque
stringData:
api-token: token-generate
Apply with kubectl apply -f cloudflare-dns-api-secret.yml
of course change the file name to your secret file.
Create the cluster issues for staging and production, files
staging-cluster-issuer.yml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
namespace: cert-manager
spec:
acme:
# You must replace this email address with your own.
# Let's Encrypt will use this to contact you about expiring
# certificates, and issues related to your account.
email: youremail
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: staging-issuer-account-key
solvers:
- dns01:
cloudflare:
email: yourcloudflareemail
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
prod-cluster-issuer.yml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: cert-manager
spec:
acme:
# You must replace this email address with your own.
# Let's Encrypt will use this to contact you about expiring
# certificates, and issues related to your account.
email: youremail
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: prod-issuer-account-key
solvers:
- dns01:
cloudflare:
email: yourcloudflareemail
apiTokenSecretRef:
name: cloudflare-api-token-secret
key: api-token
Apply this yaml:
kubectl apply -f staging-cluster-issuer.yml
kubectl apply -f prod-cluster-issuer.yml
Lets test the certification issuer:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: test-domain-com
namespace: cert-manager
spec:
secretName: test-domain-com
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
commonName: test.domain.com
dnsNames:
- test.domain.com
Edit test.domain.com and test-domain-com with your domain
Apply with kubectl apply -f test-certificate.yml
See if its ready:
kubectl -n cert-manager get certificate
When the certificate gets ready (it should take a minute or two), describe it:
kubectl -n cert-manager describe certificate test-domain-com
Should have something like:
Name: test-domain-com
Namespace: cert-manager
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: Certificate
Metadata:
Creation Timestamp: 2021-10-25T17:08:36Z
Generation: 1
Managed Fields:
API Version: cert-manager.io/v1
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.:
f:kubectl.kubernetes.io/last-applied-configuration:
f:spec:
.:
f:commonName:
f:dnsNames:
f:issuerRef:
.:
f:kind:
f:name:
f:secretName:
Manager: kubectl-client-side-apply
Operation: Update
Time: 2021-10-25T17:08:36Z
API Version: cert-manager.io/v1
Fields Type: FieldsV1
fieldsV1:
f:status:
.:
f:conditions:
f:notAfter:
f:notBefore:
f:renewalTime:
f:revision:
Manager: controller
Operation: Update
Time: 2021-10-25T17:10:03Z
Resource Version: 1002607
UID: 8646cd17-50fa-4419-9dcf-184ea2340bb5
Spec:
Common Name: test.doamin.com
Dns Names:
test.domain.com
Issuer Ref:
Kind: ClusterIssuer
Name: letsencrypt-staging
Secret Name: test-domain-com
Status:
Conditions:
Last Transition Time: 2021-10-25T17:10:03Z
Message: Certificate is up to date and has not expired
Observed Generation: 1
Reason: Ready
Status: True
Type: Ready
Not After: 2022-01-23T16:10:01Z
Not Before: 2021-10-25T16:10:02Z
Renewal Time: 2021-12-24T16:10:01Z
Revision: 1
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Issuing 3m6s cert-manager Issuing certificate as Secret does not exist
Normal Generated 3m6s cert-manager Stored new private key in temporary Secret resource "test-domain-com-zgtqd"
Normal Requested 3m6s cert-manager Created new CertificateRequest resource "test-domain-com-r78kp"
Normal Issuing 99s cert-manager The certificate has been successfully issued
Cleaning up:
kubectl delete -f test-certificate.yml
kubectl -n cert-manager delete secret test-domain-com
For more information on how to issue certificates for your ingress resources see the official documentation https://cert-manager.io/next-docs/usage/ingress/
A tip is when using traefik IngressRoute we need to issue the certificate outside the ingress, you can see a example in this post https://www.padok.fr/en/blog/traefik-kubernetes-certmanager
Congratulations, you have a automated, free SSL certification issuer. K8S is awesome!