Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a "default" Certificate for TLS #187

Closed
SantoDE opened this issue May 27, 2020 · 15 comments
Closed

Provide a "default" Certificate for TLS #187

SantoDE opened this issue May 27, 2020 · 15 comments
Labels
kind/enhancement New feature or request

Comments

@SantoDE
Copy link
Contributor

SantoDE commented May 27, 2020

If a user provides us his certificate data, we could create a TLSStore and attach the cert as a default certificate.

Partially fixes #185

@SantoDE SantoDE added the kind/enhancement New feature or request label May 28, 2020
@flexchar
Copy link

flexchar commented Sep 29, 2020

I was searching a lot how I could swap Traefik auto generated certificates out and provide the default ones. Since there is a lot of confusion around this, I'll make an informational post here.

Specifically I use Kubernetes and Ingresses with Cloudflare as DNS and Firewall provider. Cloudflare provides their own Edge certificates (for connection between CF and host server) that I need to upload and serve for all the hosts.

I created secret of type tls. This is necessary.
kubectl create secret tls tls-secret --cert tls.crt --key tls.key

A) And tried using TLSStore (src: traefik/traefik#6057 (comment))

apiVersion: traefik.containo.us/v1alpha1
kind: TLSStore
metadata:
  name: cloudflare-tls
  namespace: traefik
spec:
  defaultCertificate:
    secretName: tls-secret

but seems to be ignored by Kubernetes Ingress resources. This may work if you are using IngressRoute (Kubernetes CRD provided by Traefik)

B) Then I went the dynamic config way:
Created ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: traefik-config
  labels:
    name: traefik-config
  namespace: traefik
data:
  dyn.yaml: |
    # https://doc.traefik.io/traefik/https/tls/
    tls:
      stores:
        default:
          defaultCertificate:
            certFile: '/certs/tls.crt'
            keyFile: '/certs/tls.key'

and used these values when deploying Traefik chart

additionalArguments:
  - '--providers.file.filename=/config/dyn.yaml'
volumes:
  - name: tls-secret
    mountPath: '/certs'
    type: secret
  - name: traefik-config
    mountPath: '/config'
    type: configMap

and it works!

It can be challenging to understand Traefik, especially when Kubernetes are involved, hope this will shed some light.

Relevant: traefik/traefik#5468 (comment)

@tillepille
Copy link

tillepille commented Dec 3, 2020

I would like to see the ConfigMap and therefore my custom configuration to be managed within this HelmChart as well.
So in values.yaml

additionalConfig: |
   # https://doc.traefik.io/traefik/https/tls/
    tls:
      stores:
        default:
          defaultCertificate:
            certFile: '/certs/tls.crt'
            keyFile: '/certs/tls.key'

and a ConfigMap like

{{ if .Values.additionalConfig }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: traefik-config
  labels:
    name: traefik-config
data:
  dyn.yaml: |
 {{ .Values.additionalConfig  }}
{{ end }}

Maybe it could be possible to do that with the defaultCert as well, at least for the standard Ingress type.

What do you think @SantoDE ?

@halradaideh
Copy link

Please add the additional configuration section to the helm chart !

i have been spinning for days until i found this issue ..

@bodom0015
Copy link

bodom0015 commented Mar 24, 2021

+1 wishing for an easier / more flexible way to configure this, as it feels like a very common use case when using wildcard certificates with LetsEncrypt: we want to be able to reuse this same certificate as the default at the cluster-level without needing to sync, copy, or reissue the TLS secret to each namespace where it is needed.

@flexchar mentions a workaround, but I believe that this assumes that you are in the same namespace in which the secret was created by cert-manager, since we can't mount a secret from a different namespace. This secret would typically be in the same namespace as the Ingress rules that it secures, but not necessarily where Traefik itself is running.

For example:

  • CertManager Helm chart running in namespace cert-manager
  • Traefik Helm chart running in namespace traefik
  • Our application running in namespace example, where our Ingress rules are created

What happens:

  • CertManager sees a new Ingress rule requiring TLS in example, so it creates a new secret in the example namespace containing the needed tls.key / tls.crt files
  • We cannot mount in the tls.key / tls.crt files that are needed by Traefik to set the default certificates for the cluster, because they are not in the traefik namespace
  • To properly support this case, we would need to make sure that the correct TLS secret exists in both namespaces, which seems odd

Syncing/copying to every needed namespace adds complexity to automating the renewal of these certs, and it can be difficult to debug or even know if the sync/copy ever fails. Reissuing the same cert for every namespace can lead to being rate-limited by LetsEncrypt if your application scales out too far or too quickly.

For our use case, we may need to switch back to NGINX, where this is a simple command-line flag that we can add to extraArgs in the Helm chart: --set controller.extraArgs.default-ssl-certificate=<namespace>/<secretname>. In this case, they do not assume that the secret will actually live in the same namespace, but are somehow able to read it anyways.

@flexchar
Copy link

flexchar commented Mar 24, 2021

I'm going to quickly clarify that I have manually uploaded a certificate files (we are using Cloudflare ones) as a secret to Traefik namespace. Works great.

Each of the actual applications incl. the Ingress manifest are in their own respective namespace zone - that works fine.

@gmorse81
Copy link

gmorse81 commented Apr 8, 2021

I was able to achieve this by just creating a TLSStore

apiVersion: traefik.containo.us/v1alpha1
kind: TLSStore
metadata:
  name: default
spec:
  defaultCertificate:
    secretName: custom-default-cert

Note that i did need to enable the feature for the IngressRoute custom resources, even though i am not using them. The default cert defined in the TLSStore works for Ingress objects. I also named the TLSStore "default". not sure if that is required, but the docs do mention that the only valid store is "default"

@iTaybb
Copy link

iTaybb commented Apr 27, 2021

@gmorse81 's solution works.
It would be great if we could configure it beforehand at the helm chart installation.

@ChristianCiach

This comment was marked as resolved.

@pfisterer
Copy link

@bodom0015 I have exactly the same issue. I've got

  • cert-manager running in namespace cert-manager and
  • Traefik (deployed using k3s that internally uses this helm chart) in namespace kube-system.

Therefore using the solution proposed by @gmorse81 with a TLSStore does not work as this would require referencing a secret across namespaces. I also tried using a namespace prefix (cert-manager/name-of-the-secret) but this does not work, too. So I guess I need to revert to an nginx ingress.

@kraihn
Copy link

kraihn commented Jul 21, 2022

@pfisterer, the answer provided by @gmorse81 does work, but you need to use a ClusterIssuer for cert-manager instead of an Issuer.

My setup:

  • k3s cluster with 3 nodes (--disable=traefik)
  • cert-manager helm chart deployed to the namespace cert-manager
  • Traefik helm chart deployed to the namespace traefik

First I create my ClusterIssuer which doesn't belong to a namespace.

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: email@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
      - dns01:
          cloudflare:
            email: email@example.com
            apiTokenSecretRef:
              name: super-secret-secret-name
              key: api-token

Then I create a Certificate and assign it as default in the TLSStore. Note, the namespace for both the Certificate and TLSStore should match where you deployed Traefik. Generally kube-system or traefik, either will work.

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-example-com
  namespace: `YOUR_TRAEFIK_NAMESPACE`
spec:
  secretName: wildcard-example-com-tls
  dnsNames:
    - "example.com"
    - "*.example.com"
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
---
apiVersion: traefik.containo.us/v1alpha1
kind: TLSStore
metadata:
  name: default
  namespace: `YOUR_TRAEFIK_NAMESPACE`
spec:
  defaultCertificate:
    secretName: wildcard-example-com-tls

Once the certificate creation process has completed, Traefik will reload using the new default certificate.

@pfisterer
Copy link

@kraihn Great, thank you!

@bretmckee
Copy link

@kraihn, I'm trying to do the same thing, and I can't seem to get it to work.

I have:

  • A TLSStore in the kube-system namespace with a default secret
  • That secret in the kube-system namespace
  • the traefik entrypoint configured as:
websecure:
   address: :8443
   http:
      tls: {}
  • I have tried configuring the IngressRoute with
    • no tls: entry
    • tls: {}
    • and
tls:
  store:
  name: default

All with no success. Traefik debug level logging just keeps claiming there is "No certificate found for domain:..."

Could you share your entrypoint and ingress tls configuration?

@mloiseleur
Copy link
Contributor

Hello,

Now that PR #601 has been merged, as @gmorse81 said, you can use the TLSStore to achieve this.

@jpjonte
Copy link

jpjonte commented Dec 5, 2022

For anyone reading this and trying to get @kraihn's solution to work, I had to add the certificates array to the TLSStore for it to work:

apiVersion: traefik.containo.us/v1alpha1
kind: TLSStore
metadata:
  name: default
  namespace: `YOUR_TRAEFIK_NAMESPACE`
spec:
  certificates:
    - secretName: wildcard-example-com-tls
  defaultCertificate:
    secretName: wildcard-example-com-tls

@mloiseleur
Copy link
Contributor

mloiseleur commented Dec 6, 2022

@jpjonte I checked and I was able to make it work without this with current version of Traefik and this Helm Chart.

I provided a complete example in PR #754, does this work for you ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/enhancement New feature or request
Projects
None yet
Development

No branches or pull requests