From Ingress to IngressRoute with CertManager, HTTP01 Challenge and Let's Encrypt ClusterIssuer - traefik

I have a Kubernetes (v1.25.2) cluster running with cert-manager 1.11.0 and Traefik 2.9.6.
For some services I want Let's Encrypt to auto sign certificates. For some reason, it feels nicer, to use IngressRoute instead of Ingress. I just can't get the IngressRoute to create the certificate.
Now, I have the a ClusterIssuer:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: my#email.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: traefik
and, working, corresponding Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-name-websecure
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: traefik
rules:
- host: my.host.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: linkingservice
port:
number: 80
tls:
- hosts:
- my.host.com
secretName: some-secret-name-tls
This works, nice. Instead, with IngressRoute the base resource is this:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: myapp-other-name-websecure
spec:
entryPoints:
- websecure
routes:
- match: Host(`other.host.com`)
kind: Rule
services:
- name: linkingservice
port: 80
tls:
# certResolver: ??? # resolve what? Doesn't link with the ClusterIssuer
# issuerRef: ??? # doesn't exist (anymore)
Now, I've tried to:
just as for the Ingress to use the annotations: cert-manager.io/cluster-issuer: letsencrypt-prod. Which is being ignored
use the tls.certResolver, which doesn't work, because it doesn't exist. Should I create one? I expect The ClusterIssuer to create the certificate and secret, just as it does for Ingress.
I also saw the issuerRef as option in the tls section, but that doesn't appear to exist.
I thought I read that the IngressRoute is like a layer on top of the k8s default Ingress, so it should be something logical/similar
FYI: the ClusterIssuer and Ingress will also work for Nginx, when you replace the solvers.http01.ingress.class with nginx, likewise for the Ingress's spec.ingressClassName. (perhaps also without, but I can't test)

Now, I did find a way, but still feels like more work than should be necessary. The thing here is to create the Certificate and link that to the ClusterIssuer, that certificate then creates a Secret. This secret needs to be added to the spec.tls.secretName, like:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my.host.com-cert
spec:
secretName: my.host.com-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- my.host.com
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
spec:
...
tls:
secretName: my.host.com-secret
I've also tried for, certResolver. But the CertificateResolver from cert-manager was discontinued in v0.15.0; alternatively the CertificateRequest, but this was also discontinued in cert-manager version 0.9.0. The suggested way seems to be the previous described one.
I revisited the Traefik deployment values.yaml where I found there is a field with certResolvers, from their file:
certResolvers:
letsencrypt:
# for challenge options cf. https://doc.traefik.io/traefik/https/acme/
email: email#example.com
dnsChallenge:
# also add the provider's required configuration under env
# or expand then from secrets/configmaps with envfrom
# cf. https://doc.traefik.io/traefik/https/acme/#providers
provider: digitalocean
# add futher options for the dns challenge as needed
# cf. https://doc.traefik.io/traefik/https/acme/#dnschallenge
delayBeforeCheck: 30
resolvers:
- 1.1.1.1
- 8.8.8.8
tlsChallenge: true
httpChallenge:
entryPoint: "web"
# It has to match the path with a persistent volume
storage: /data/acme.json
Which makes me wonder. If you set this up, then probably the:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
spec:
tls:
certResolver: letsencrypt
can work

Related

ArgoCD with nginx ingress and cert manager not working

I am trying to expose ArgoCD using ingress and cert-manager in GKE cluster(version 1.21.5-gke.1302) but the certificate is not issued.
Steps to reproduce:
Install cert-manager applying this yaml
Install nginx ingress-controller with helm running:
helm install my-release nginx-stable/nginx-ingress
Create clusterIssuer applying the following:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-cluster-issuer
spec:
acme:
email: example#email.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-cluster-issuer-key
solvers:
- http01:
ingress:
class: nginx
Applied ingress using this guide and the file:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-ingress
namespace: argocd
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
# If you encounter a redirect loop or are getting a 307 response code
# then you need to force the nginx ingress to connect to the backend using HTTPS.
#
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
rules:
- host: argocd.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
name: https
tls:
- hosts:
- argocd.example.com
secretName: argocd-secret # do not change, this is provided by Argo CD
Map the ip of ingress-controller to your host name.
Expected behaviour: I was expecting a certificate to be created successfully and have access to the app.
Current status:
Certificate describe gives me this:
Conditions:
Last Transition Time: 2022-01-18T14:10:14Z
Message: Existing issued Secret is not up to date for spec: [spec.dnsNames]
Observed Generation: 3
Reason: SecretMismatch
Status: False
Type: Ready
Last Transition Time: 2022-01-18T14:10:14Z
Message: Issuing certificate as Secret was previously issued by Issuer.cert-manager.io/
Observed Generation: 1
Reason: IncorrectIssuer
Status: True
Type: Issuing
Next Private Key Secret Name: argocd-secret-ccjtv
Not After: 2023-01-18T13:39:24Z
Not Before: 2022-01-18T13:39:24Z
Renewal Time: 2022-09-18T21:39:24Z
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Requested 16m cert-manager Created new CertificateRequest resource "argocd-secret-qm469"
Normal Requested 15m cert-manager Created new CertificateRequest resource "argocd-secret-9ctn4"
Normal Reused 7m19s (x2 over 45h) cert-manager Reusing private key stored in existing Secret resource "argocd-secret"
Finally I can access the provided url by the challenge but status is pending with reason:
Waiting for HTTP-01 challenge propagation: failed to perform self check GET request
Does anyone have any idea what might be wrong? It would be highly appreciated.
Thanks!
Looks like you have a different name for cluster issue in your ingress rule for ArgoCD.
From your example in the ClusterIssuer manifest:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-cluster-issuer
And from ingress rule
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
I think you need to specify:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-cluster-issuer
spec:
acme:
email: example#email.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: argocd-secret # HERE use secrets created by ArgoCD
solvers:
- http01:
ingress:
class: nginx

Kubernetes cert-manager certificate is created but can not get vertified

I am working on a DO kubernetes cluster and install ingress nginx and argocd on it, All seems fine and I can easily use the ingress as long as they are accessing the services via http.
I have also installed certmanager and here are the main files regarding my ingress, certificate and issuer:
Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rancher-demo
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
certmanager.k8s.io/cluster-issuer: "letsencrypt-production"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- {sub-domain}
secretName: ssl-cert-production
rules:
- host: {sub-domain}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rancher-demo
port:
number: 80
Issuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production
namespace: default
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: {my-email}
privateKeySecretRef:
name: letsencrypt-production
solvers:
- selector: {}
http01:
ingress:
class: nginx
Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ssl-cert-production
namespace: default
spec:
secretName: ssl-cert-production
issuerRef:
name: letsencrypt-production
kind: ClusterIssuer
commonName: {sub-domain}
dnsNames:
- {sub-domain}
I went through some other samples on github and questions on stackoverflow and unfortunetly I can not figure out where I am doing it wrong.
Thank you in advance for your attentions
I finally managed to fix the issue, what I have done was as follow:
creating a new kubernete instance
installing cert-manager manaully
installing ingress-nginx manaully
creating the issuer (waiting for it to complete)
creating deployment and cluster
creating ingress config for my application
creating the certificate (waiting for it to complete)
I was working on ArgoCD and had to first do these setups myself before handling CD with Argo. It was my own fault that I did not properly go through their documentations. The order is important, but the way I sat up Argo, it was provisioing everything in parallel so for example certificate was being provision before ingress be up or issuer be in place
Also for anyone who is interested in a detailed version please checkout the github repo I created below:
https://github.com/mehdiamenein/cert-manager-nginx-ingress-do
I hope this can be helpful to someone else as well :)
Huge thanks to marcel.dempers for his wonderful video https://www.youtube.com/watch?v=hoLUigg4V18
and many thanks to #justin and #harsh-manvar for their comments

kubernetes certs not working with let's encrypt cert-manager

I can't seem to get cert-manager working:
$ kubectl get certificates -o wide
NAME READY SECRET ISSUER STATUS AGE
tls-secret False tls-secret letsencrypt Issuing certificate as Secret does not exist 115m
$ kubectl get CertificateRequest -o wide
NAME READY ISSUER STATUS AGE
tls-secret-xxxx False letsencrypt Referenced "ClusterIssuer" not found: clusterissuer.cert-manager.io "letsencrypt" not found 113m
my certificate.yaml is :
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: tls-secret
namespace: default
spec:
secretName: tls-secret
dnsNames:
- aks-xxxx.xxxxx.xxxx.aksapp.io
acme:
config:
- http01:
ingress:
name: xxxxxx
domains:
- aks-xxxx.xxxxx.xxxx.aksapp.io
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
When i get cluster issuers
$ kubectl get clusterissuers
No resources found
any idea whats wrong?
You have not created the clusterissuers so it wont be there.
As you have created the certificate you can try the
kubectl get certificate
Your error is clearly saying the issue you have to create the clusterissuers
Referenced "ClusterIssuer" not found: clusterissuer.cert-manager.io
"letsencrypt" not found
Cert-manager site : https://cert-manager.io/docs/
Installation : https://cert-manager.io/docs/installation/
in single line just apply :
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.3/cert-manager.yaml
how to configure & setup the clusterissuer : https://cert-manager.io/docs/configuration/acme/
Example of cluster issuer & ingress
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: cluster-issuer-name
namespace: development
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: harsh#example.com
privateKeySecretRef:
name: secret-name
solvers:
- http01:
ingress:
class: nginx-class-name
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx-class-name
cert-manager.io/cluster-issuer: cluster-issuer-name
nginx.ingress.kubernetes.io/rewrite-target: /
name: example-ingress
spec:
rules:
- host: sub.example.com
http:
paths:
- path: /api
backend:
serviceName: service-name
servicePort: 80
tls:
- hosts:
- sub.example.com
secretName: secret-name
Try with the latest cert-manager.
You'll also need issuer.yaml if you haven't set it up already

SSL Certificates on Kubernetes Using ACME

I have been following this tutorial: https://cert-manager.io/docs/ , and after I have installed my cert manager and made sure they are running with kubectl get pods --namespace cert-manager,
cert-manager-5597cff495-l5hjs 1/1 Running 0 91m
cert-manager-cainjector-bd5f9c764-xrb2t 1/1 Running 0 91m
cert-manager-webhook-5f57f59fbc-q5rqs 1/1 Running 0 91m
I then configured my cert-manager using ACME issuer by following this tutorial https://cert-manager.io/docs/configuration/acme/ .
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
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: aidenhsy#gmail.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Secret resource that will be used to store the account's private key.
name: letsencrypt-staging
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
class: nginx
Here is my full ingress config file:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-srv
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: 'true'
spec:
rules:
- host: www.hyhaus.xyz
http:
paths:
- path: /api/?(.*)
backend:
serviceName: devback-srv
servicePort: 4000
- path: /?(.*)
backend:
serviceName: devfront-srv
servicePort: 3000
---
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: 'true'
service.beta.kubernetes.io/do-loadbalancer-hostname: 'www.hyhaus.xyz'
labels:
helm.sh/chart: ingress-nginx-2.0.3
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 0.32.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: controller
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: LoadBalancer
externalTrafficPolicy: Local
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
- name: https
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
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: aidenhsy#gmail.com
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Secret resource that will be used to store the account's private key.
name: letsencrypt-staging
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
class: nginx
However when I browse to my site, the browser warns: security certificate is not trusted by your computer's operating system. And when I took a look a my certificate, it shows self-assigned, which is not really what I want. Am I doing something wrong here?
This is a certificate placeholder provided by nginx ingress controller. When you see it, it means there is no other (dedicated) certificate for the endpoint.
Now the first reason why this happened is that your Ingress doesn't have necessary data. Update it with this:
metadata:
annotations:
# which issuer to use
cert-manager.io/cluster-issuer: "letsencrypt-staging"
spec:
tls: # placing a host in TLS config indicates that a certificate should be created
- hosts:
- example.org
- www.example.org
- xyz.example.org
secretName: myingress-cert # cert-manager will store the created certificate in this secret
Documentation for ingress objects is here.
If the above didn't help, try the troubleshooting steps offered by the documentation. In my experience checking CertificateRequest and Certificate resources was enough in most cases to determine the problem.
$ kubectl get certificate
$ kubectl describe certificate <certificate-name>
$ kubectl get certificaterequest
$ kubectl describe certificaterequest <CertificateRequest name>
Remember that these objects are namespaced, meaning that they'll be in the same namespace as the ingress object.
To secure Ingress, First you have to add ClusterIssuer to your Ingress resources and cert-manager will then pick it up and create the Certificate resource for you .
Kind : ingress metadata: annotations : cert-manager.io/cluster-issuer: nameOfClusterIssuer .
Second you have to add tls <= this indicates the creation of certificate(key/cert pair) by Cert-manager via The ClusterIssuer.
Third you have to add secretName: myingress <= here the cert manager will store the tls secrets ( after creating key/cert pair and store them for you)..

GKE, NGINX ingress, HTTPS, and certificates

I have set up a Kubernetes cluster on GCP/GKE and it's all working well except for one thing. When I access the external IP for the service the (default?) "Kubernetes Ingress Controller Fake Certificate" is served.
I am trying to use the NGINX Ingress (https://kubernetes.github.io/ingress-nginx/) and have followed what I believe are the correct instructions for associating a TLS secret with the Ingress. For example:
https://estl.tech/configuring-https-to-a-web-service-on-google-kubernetes-engine-2d71849520d
https://kubernetes.github.io/ingress-nginx/user-guide/tls/
I have created a secret like this:
apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: default
data:
tls.crt: [removed]
tls.key: [removed]
type: kubernetes.io/tls
And associated that secret (which I can confirm is applied correctly and I can see in the cluster config) with the Ingress like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
kubernetes.io/ingress.allow-http: "false"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/affinity: "cookie"
spec:
backend:
serviceName: example-service
servicePort: 80
tls:
- secretName: example-tls
From the documentation I feel that this should work (but, barring a bug, I am obviously mistaken!).
I've also seen some documentation around requiring target proxies for HTTPS. Perhaps that is the way that I should be doing this?
Many thanks for your help in advance.
Cheers,
Ben
PS: This is my load balancer configuration:
kind: Service
apiVersion: v1
metadata:
name: ingress-nginx
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
externalTrafficPolicy: Cluster
loadBalancerIP: [removed]
sessionAffinity: ClientIP
type: LoadBalancer
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: https
Edit 1:
Looking at my Ingress I can see this:
➜ gke git:(develop) ✗ kubectl describe ing example-tls-ingress
Name: example-tls-ingress
Namespace: default
Address: [removed]
Default backend: example-webapp-service:80 ([removed])
TLS:
example-tls terminates
Rules:
Host Path Backends
---- ---- --------
* * example-webapp-service:80 ([removed])
So it looks like the secret is picked up.
And this makes me think that there is a difference between Ingress-terminated TLS and Load Balancer-terminated TLS?
You can just refer to this stackoverflow post.
You need to install jetstack cert-Manager, create clusterissuer/issuer, along with a certificate in which you have to pass domain name / hostname and jetstack will automatically create the secret for you, by the name you mentioned in the 'Certificate'.
That secret has to be patched to TLS in ingress rule.