CérénIT - cert-manager
Le blog tech de Nicolas Steinmetz (Time Series, IoT, Web, Ops, Data)
Zola
2020-05-27T09:30:00+02:00
https://cerenit.fr/tags/cert-manager/atom.xml
Web, Ops & Data - Mai 2020
2020-05-27T09:30:00+02:00
2020-05-27T09:30:00+02:00
Unknown
https://cerenit.fr/blog/web-ops-and-data-mai-2020/
<p>Le mois prochain, dans le cadre d'<a rel="noopener" target="_blank" href="https://www.influxdays.com/london-2020/">InfluxDays London</a>, j'aurai le plaisir de présenter un talk sur le passage d'un monitoring Bare Metal vers un monitoring dans un monde Kubernetes avec Telegraf et InfluxDB.</p>
<h3 id="cloud">Cloud</h3>
<ul>
<li><a rel="noopener" target="_blank" href="https://github.com/hashicorp/terraform/issues/25016">Terraform v0.13.0 beta program</a> : Terraform 0.13 (beta) devrait supporter au niveau des modules <code>depends_on</code>, <code>count</code> et <code>for_each</code>. Cela devrait éviter des dépendances parfois cryptiques.</li>
<li><a rel="noopener" target="_blank" href="https://www.hashicorp.com/blog/deploy-any-resource-with-the-new-kubernetes-provider-for-hashicorp-terraform/">Deploy Any Resource With The New Kubernetes Provider for HashiCorp Terraform</a> : la prochaine version du provider kubernetes de terraform permettra de déployer n'importe quelle ressource. Pratique ! Il vous faudra un cluster kubernetes 1.17+ pour utliser la fonctionnalité "Server Side Apply".</li>
<li><a rel="noopener" target="_blank" href="https://www.grottedubarbu.fr/ovh-api-openstack/">OVH : Utilisation de l'API OpenStack</a> : Tutoriel pour le déploiement d'un wordpress sur un cluser k3s chez OVH en utilisant l'API OpenStack ; le reste du blog <a rel="noopener" target="_blank" href="https://www.grottedubarbu.fr/">La Grotte du Barbu</a> fournit plein de ressources sur kubernetes, traefik, docker, etc.</li>
</ul>
<h3 id="container-orchestration">Container & orchestration</h3>
<ul>
<li><a rel="noopener" target="_blank" href="https://www.linuxuprising.com/2019/11/how-to-install-and-use-docker-on-fedora.html">How To Install Docker On Fedora 32 Or 31 (And Alternatives)</a> : Même si l'utilisation de podman est recommandée en lieu et place de docke-ce depuis Fedora 31, il peut être nécessaire de vouloir utiliser docker-ce sous Fedora. Avec Fedora 32, il faut en plus des cgroups v1 à activer, il y a une règle firewall à ajouter pour que vos conteneurs aient accès au réseau / à internet.</li>
<li><a rel="noopener" target="_blank" href="https://goharbor.io/blog/harbor-2.0/">Harbor 2.0</a> : Version 2.0 de la registry Harbor qui permet d'héberger aussi des charts Helm. Pour la partie scan de vulnérabilités, le produit Clair de Quay a été remplacé par <a rel="noopener" target="_blank" href="https://github.com/aquasecurity/trivy">Aqua Trivy</a></li>
<li><a rel="noopener" target="_blank" href="https://containo.us/blog/announcing-maesh-1-2/">Announcing Maesh 1.2</a> : la solution de Service Mesh de Containous basée sur Traefik sort en 1.2 ; elle se base sur Traefik 2.2 et apporte donc le support de l'UDP au niveau reverse proxy. Cette version permet aussi des améliorations au niveau ACL, gestion de la configuration et gestion des middlewares par service.</li>
<li><a rel="noopener" target="_blank" href="https://www.percona.com/blog/2020/05/07/introduction-to-percona-kubernetes-operator-for-percona-xtradb-cluster/">Introduction to Percona Kubernetes Operator for Percona XtraDB Cluster</a></li>
<li><a rel="noopener" target="_blank" href="https://blog.jetstack.io/blog/cert-manager-0.15-and-beyond/">Cert-manager v0.15 and beyond</a></li>
<li><a rel="noopener" target="_blank" href="https://cdk8s.io/">CDK for Kubernetes</a> : AWS vient de sortir un "Cloud Development Kit" permettant de manipuler et déployer des ressources kubernetes en python, typescript ou javascript.</li>
</ul>
<h3 id="devops">DevOps</h3>
<ul>
<li><a rel="noopener" target="_blank" href="https://devops.training.barpilot.io/">DevOps : Discovering, Learning and Sharing</a> (<a rel="noopener" target="_blank" href="https://github.com/guilhem/devops-training">code source</a>) : Guilhem vient de publier sa formation de culture DevOps ; à consulter !</li>
<li><a rel="noopener" target="_blank" href="https://shows.acast.com/radio-devops">Radio DevOps</a> : un podcast qui s'améliore d'épisode en épisode et plutôt adressé à des débutants dans le monde du DevOps.</li>
</ul>
<h2 id="iot">IoT</h2>
<ul>
<li><a rel="noopener" target="_blank" href="https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=274595">Raspberry Pi 4 USB mass storage beta (beta means it not ready yet, and not officially released!)</a> : Le Raspberry Pi 4 va pouvoir démarrer sur un périphérique USB (clé USB, disque SSD, etc) avec l'arrivée du prochain firmware. La nécessité de la SDCard va disparaitre.</li>
</ul>
<h3 id="time-series">Time Series</h3>
<ul>
<li><a rel="noopener" target="_blank" href="https://blog.timescale.com/blog/multi-node-petabyte-scale-time-series-database-postgresql-free-tsdb/">A multi-node, elastic, petabyte scale, time-series database on Postgres for free (and more ways we are investing in our community)</a> : Timescale annonce que sa version cluster de TimescaleDB sera gratuite (sous licence Timescale, source code available mais pas le droit de faire un produit SaaS avec). La version monoserveur reste sous licence Apache 2.</li>
<li><a rel="noopener" target="_blank" href="https://grafana.com/blog/2020/05/18/grafana-v7.0-released-new-plugin-architecture-visualizations-transformations-native-trace-support-and-more/">Grafana v7.0 released: New plugin architecture, visualizations, transformations, native trace support, and more</a> : A l'occasion de la <a rel="noopener" target="_blank" href="https://grafana.com/about/events/grafanacon/2020/#schedule">GrafanaCon 2020</a>, Grafana Labs a sorti notamment Grafana 7.0 avec des tonnes d'amélioration. Il va falloir un peu de temps pour bien apprécier tout cela.</li>
<li><a rel="noopener" target="_blank" href="https://grafana.com/about/events/grafanacon/2020/#schedule">GrafanaCon 2020</a> : la conférence annuelle de Grafana s'est tenue tout le mois de Mai, les vidéos sont accessibles sur la page de chaque talk après avoir saisi son email. Je n'ai malheureusement pas encore eu le temps de les visionner. <a rel="noopener" target="_blank" href="https://grafana.com/blog/2020/05/21/cortex-v1.1-released-with-improved-reliability-and-performance/">Cortex 1.1</a> et <a rel="noopener" target="_blank" href="https://grafana.com/blog/2020/05/20/loki-v1.5.0-released-with-no-more-dependency-on-a-separate-index-store">Loki 1.5</a> y ont notamment été annoncés.</li>
</ul>
Kubernetes @ OVH - Traefik2 et Cert Manager pour le stockage des certificats en secrets
2019-11-08T18:00:00+01:00
2019-11-08T18:00:00+01:00
Unknown
https://cerenit.fr/blog/kubernetes-ovh-traefik2-cert-manager-secrets/
<p>Avec la sortie de <a rel="noopener" target="_blank" href="https://blog.containo.us/traefik-2-0-6531ec5196c2">Traefik 2</a>, il était temps de mettre à jour le billet <a rel="noopener" target="_blank" href="https://www.cerenit.fr/blog/kubernetes-ovh-traefik-cert-manager-secrets/">Kubernetes @ OVH - Traefik et Cert Manager pour le stockage des certificats en secrets</a> pour tenir compte des modifications.</p>
<p>L'objectif est toujours de s'appuyer sur <a rel="noopener" target="_blank" href="https://cert-manager.readthedocs.io/">Cert-Manager</a> pour la génération et le stockage des certificats Let's Encrypt qui seront utilisés par Traefik. L'idée est de stocker ces certificats sous la forme d'un objet <code>Certificate</code> et de ne plus avoir à provisionner un volume pour les stocker. On peut dès lors avoir plusieurs instances de Traefik et non plus une seule à laquelle le volume serait attaché.</p>
<p>Installation de cert-manager :</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#65737e;"># Install the CustomResourceDefinition resources separately
</span><span style="color:#bf616a;">kubectl</span><span> apply</span><span style="color:#bf616a;"> --validate</span><span>=false</span><span style="color:#bf616a;"> -f</span><span> https://raw.githubusercontent.com/jetstack/cert-manager/release-0.11/deploy/manifests/00-crds.yaml
</span><span>
</span><span style="color:#65737e;"># Create the namespace for cert-manager
</span><span style="color:#bf616a;">kubectl</span><span> create namespace cert-manager
</span><span>
</span><span style="color:#65737e;"># Add the Jetstack Helm repository
</span><span style="color:#bf616a;">helm</span><span> repo add jetstack https://charts.jetstack.io
</span><span>
</span><span style="color:#65737e;"># Update your local Helm chart repository cache
</span><span style="color:#bf616a;">helm</span><span> repo update
</span><span>
</span><span style="color:#65737e;"># Install the cert-manager Helm chart
</span><span style="color:#bf616a;">helm</span><span> install \
</span><span style="color:#bf616a;"> --name</span><span> cert-manager \
</span><span style="color:#bf616a;"> --namespace</span><span> cert-manager \
</span><span style="color:#bf616a;"> --version</span><span> v0.11.0 \
</span><span> jetstack/cert-manager
</span></code></pre>
<p>Nous allons ensuite devoir créer un <a rel="noopener" target="_blank" href="https://cert-manager.readthedocs.io/en/latest/reference/issuers.html">Issuer</a> dans chaque namespace pour avoir un générateur de certificats propre à chaque namespace. Cela est notamment du au fait que Traefik s'attend à ce que le secret et l'ingress utilisant ce secret soient dans le même namespace. Nous spécifions également que nous utiliserons traefik comme ingress pour la génération des certificats.</p>
<p><code>cert-manager/issuer.yml</code>:</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">cert-manager.io/v1alpha2
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Issuer
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">letsencrypt-prod
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">acme</span><span>:
</span><span> </span><span style="color:#65737e;"># The ACME server URL
</span><span> </span><span style="color:#bf616a;">server</span><span>: </span><span style="color:#a3be8c;">https://acme-v02.api.letsencrypt.org/directory
</span><span> </span><span style="color:#65737e;"># Email address used for ACME registration
</span><span> </span><span style="color:#bf616a;">email</span><span>: </span><span style="color:#a3be8c;">user@example.com
</span><span> </span><span style="color:#65737e;"># Name of a secret used to store the ACME account private key
</span><span> </span><span style="color:#bf616a;">privateKeySecretRef</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">letsencrypt-prod
</span><span> </span><span style="color:#65737e;"># Enable HTTP01 validations
</span><span> </span><span style="color:#bf616a;">solvers</span><span>:
</span><span> - </span><span style="color:#bf616a;">selector</span><span>: {}
</span><span> </span><span style="color:#bf616a;">http01</span><span>:
</span><span> </span><span style="color:#bf616a;">ingress</span><span>:
</span><span> </span><span style="color:#bf616a;">class</span><span>: </span><span style="color:#a3be8c;">traefik
</span></code></pre>
<p>Puis créons le "issuer" dans la/les namespace(s) voulu(s) :</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#65737e;"># Create issuer in a given namespace
</span><span style="color:#bf616a;">kubectl</span><span> create</span><span style="color:#bf616a;"> -n </span><span><namespace> -f cert-manager/issuer.yml
</span></code></pre>
<p>Installons ensuite traefik V2</p>
<p>Créons le namespace traefik2 :</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#65737e;"># Create namespace
</span><span style="color:#bf616a;">kubectl</span><span> create ns traefik2
</span><span style="color:#65737e;"># Change context to this namespace so that all commands are by default run for this namespace
</span><span style="color:#65737e;"># see https://github.com/ahmetb/kubectx
</span><span style="color:#bf616a;">kubens</span><span> traefik2
</span></code></pre>
<p>En premier lieu, Traefik V2 permet d'avoir un provider Kubernetes qui se base sur des <code>Custom Ressources Definition</code> (aka <code>CRD</code>).</p>
<p>Créeons le fichier <code>traefik2/crd.yml</code> :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">apiextensions.k8s.io/v1beta1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">CustomResourceDefinition
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">ingressroutes.traefik.containo.us
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">group</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us
</span><span> </span><span style="color:#bf616a;">version</span><span>: </span><span style="color:#a3be8c;">v1alpha1
</span><span> </span><span style="color:#bf616a;">names</span><span>:
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">IngressRoute
</span><span> </span><span style="color:#bf616a;">plural</span><span>: </span><span style="color:#a3be8c;">ingressroutes
</span><span> </span><span style="color:#bf616a;">singular</span><span>: </span><span style="color:#a3be8c;">ingressroute
</span><span> </span><span style="color:#bf616a;">scope</span><span>: </span><span style="color:#a3be8c;">Namespaced
</span><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">apiextensions.k8s.io/v1beta1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">CustomResourceDefinition
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">middlewares.traefik.containo.us
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">group</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us
</span><span> </span><span style="color:#bf616a;">version</span><span>: </span><span style="color:#a3be8c;">v1alpha1
</span><span> </span><span style="color:#bf616a;">names</span><span>:
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Middleware
</span><span> </span><span style="color:#bf616a;">plural</span><span>: </span><span style="color:#a3be8c;">middlewares
</span><span> </span><span style="color:#bf616a;">singular</span><span>: </span><span style="color:#a3be8c;">middleware
</span><span> </span><span style="color:#bf616a;">scope</span><span>: </span><span style="color:#a3be8c;">Namespaced
</span><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">apiextensions.k8s.io/v1beta1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">CustomResourceDefinition
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">ingressroutetcps.traefik.containo.us
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">group</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us
</span><span> </span><span style="color:#bf616a;">version</span><span>: </span><span style="color:#a3be8c;">v1alpha1
</span><span> </span><span style="color:#bf616a;">names</span><span>:
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">IngressRouteTCP
</span><span> </span><span style="color:#bf616a;">plural</span><span>: </span><span style="color:#a3be8c;">ingressroutetcps
</span><span> </span><span style="color:#bf616a;">singular</span><span>: </span><span style="color:#a3be8c;">ingressroutetcp
</span><span> </span><span style="color:#bf616a;">scope</span><span>: </span><span style="color:#a3be8c;">Namespaced
</span><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">apiextensions.k8s.io/v1beta1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">CustomResourceDefinition
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">ingressrouteudps.traefik.containo.us
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">group</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us
</span><span> </span><span style="color:#bf616a;">version</span><span>: </span><span style="color:#a3be8c;">v1alpha1
</span><span> </span><span style="color:#bf616a;">names</span><span>:
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">IngressRouteUDP
</span><span> </span><span style="color:#bf616a;">plural</span><span>: </span><span style="color:#a3be8c;">ingressrouteudps
</span><span> </span><span style="color:#bf616a;">singular</span><span>: </span><span style="color:#a3be8c;">ingressrouteudp
</span><span> </span><span style="color:#bf616a;">scope</span><span>: </span><span style="color:#a3be8c;">Namespaced
</span><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">apiextensions.k8s.io/v1beta1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">CustomResourceDefinition
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">tlsoptions.traefik.containo.us
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">group</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us
</span><span> </span><span style="color:#bf616a;">version</span><span>: </span><span style="color:#a3be8c;">v1alpha1
</span><span> </span><span style="color:#bf616a;">names</span><span>:
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">TLSOption
</span><span> </span><span style="color:#bf616a;">plural</span><span>: </span><span style="color:#a3be8c;">tlsoptions
</span><span> </span><span style="color:#bf616a;">singular</span><span>: </span><span style="color:#a3be8c;">tlsoption
</span><span> </span><span style="color:#bf616a;">scope</span><span>: </span><span style="color:#a3be8c;">Namespaced
</span><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">apiextensions.k8s.io/v1beta1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">CustomResourceDefinition
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">tlsstores.traefik.containo.us
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">group</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us
</span><span> </span><span style="color:#bf616a;">version</span><span>: </span><span style="color:#a3be8c;">v1alpha1
</span><span> </span><span style="color:#bf616a;">names</span><span>:
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">TLSStore
</span><span> </span><span style="color:#bf616a;">plural</span><span>: </span><span style="color:#a3be8c;">tlsstores
</span><span> </span><span style="color:#bf616a;">singular</span><span>: </span><span style="color:#a3be8c;">tlsstore
</span><span> </span><span style="color:#bf616a;">scope</span><span>: </span><span style="color:#a3be8c;">Namespaced
</span><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">apiextensions.k8s.io/v1beta1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">CustomResourceDefinition
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefikservices.traefik.containo.us
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">group</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us
</span><span> </span><span style="color:#bf616a;">version</span><span>: </span><span style="color:#a3be8c;">v1alpha1
</span><span> </span><span style="color:#bf616a;">names</span><span>:
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">TraefikService
</span><span> </span><span style="color:#bf616a;">plural</span><span>: </span><span style="color:#a3be8c;">traefikservices
</span><span> </span><span style="color:#bf616a;">singular</span><span>: </span><span style="color:#a3be8c;">traefikservice
</span><span> </span><span style="color:#bf616a;">scope</span><span>: </span><span style="color:#a3be8c;">Namespaced
</span></code></pre>
<p>Vous pouvez retrouver les <a rel="noopener" target="_blank" href="https://docs.traefik.io/reference/dynamic-configuration/kubernetes-crd/#definitions">sources de ces CRD</a>.</p>
<p>Continuons avec <code>traefik2/rbac.yml</code> - le fichier défini le compte de service (<code>Service Account</code>), le rôle au niveau du cluster (<code>Cluster Role</code>) et la liaison entre le rôle et le compte de service (<code>Cluster Role Binding</code>). Si vous venez d'une installation avec Traefik 1, ce n'est pas tout à fait la même définition des permissions.</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">v1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ServiceAccount
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-controller
</span><span> </span><span style="color:#bf616a;">namespace</span><span>: </span><span style="color:#a3be8c;">traefik2
</span><span>---
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ClusterRole
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">rbac.authorization.k8s.io/v1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-controller
</span><span> </span><span style="color:#bf616a;">namespace</span><span>: </span><span style="color:#a3be8c;">traefik2
</span><span style="color:#bf616a;">rules</span><span>:
</span><span> - </span><span style="color:#bf616a;">apiGroups</span><span>:
</span><span> - ""
</span><span> </span><span style="color:#bf616a;">resources</span><span>:
</span><span> - </span><span style="color:#a3be8c;">services
</span><span> - </span><span style="color:#a3be8c;">endpoints
</span><span> - </span><span style="color:#a3be8c;">secrets
</span><span> </span><span style="color:#bf616a;">verbs</span><span>:
</span><span> - </span><span style="color:#a3be8c;">get
</span><span> - </span><span style="color:#a3be8c;">list
</span><span> - </span><span style="color:#a3be8c;">watch
</span><span> - </span><span style="color:#bf616a;">apiGroups</span><span>:
</span><span> - </span><span style="color:#a3be8c;">extensions
</span><span> </span><span style="color:#bf616a;">resources</span><span>:
</span><span> - </span><span style="color:#a3be8c;">ingresses
</span><span> </span><span style="color:#bf616a;">verbs</span><span>:
</span><span> - </span><span style="color:#a3be8c;">get
</span><span> - </span><span style="color:#a3be8c;">list
</span><span> - </span><span style="color:#a3be8c;">watch
</span><span> - </span><span style="color:#bf616a;">apiGroups</span><span>:
</span><span> - </span><span style="color:#a3be8c;">extensions
</span><span> </span><span style="color:#bf616a;">resources</span><span>:
</span><span> - </span><span style="color:#a3be8c;">ingresses/status
</span><span> </span><span style="color:#bf616a;">verbs</span><span>:
</span><span> - </span><span style="color:#a3be8c;">update
</span><span> - </span><span style="color:#bf616a;">apiGroups</span><span>:
</span><span> - </span><span style="color:#a3be8c;">traefik.containo.us
</span><span> </span><span style="color:#bf616a;">resources</span><span>:
</span><span> - </span><span style="color:#a3be8c;">middlewares
</span><span> - </span><span style="color:#a3be8c;">ingressroutes
</span><span> - </span><span style="color:#a3be8c;">traefikservices
</span><span> - </span><span style="color:#a3be8c;">ingressroutetcps
</span><span> - </span><span style="color:#a3be8c;">ingressrouteudps
</span><span> - </span><span style="color:#a3be8c;">tlsoptions
</span><span> - </span><span style="color:#a3be8c;">tlsstores
</span><span> </span><span style="color:#bf616a;">verbs</span><span>:
</span><span> - </span><span style="color:#a3be8c;">get
</span><span> - </span><span style="color:#a3be8c;">list
</span><span> - </span><span style="color:#a3be8c;">watch
</span><span>---
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ClusterRoleBinding
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">rbac.authorization.k8s.io/v1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-controller
</span><span style="color:#bf616a;">roleRef</span><span>:
</span><span> </span><span style="color:#bf616a;">apiGroup</span><span>: </span><span style="color:#a3be8c;">rbac.authorization.k8s.io
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ClusterRole
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-controller
</span><span style="color:#bf616a;">subjects</span><span>:
</span><span>- </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ServiceAccount
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-controller
</span><span> </span><span style="color:#bf616a;">namespace</span><span>: </span><span style="color:#a3be8c;">traefik2
</span></code></pre>
<p>Nous pouvons alors songer à déployer Traefik V2 sous la forme d'un <code>Deployment</code>. Mais avant de produire le fichier, ce qu'il faut savoir ici :</p>
<ul>
<li>lorsque cert-manager fait une demande de certificat, il crée un ressource de type <code>Ingress</code>. Dès lors, il faut activer les deux providers kubernetes disponibles avec Traefik V2 : <code>KubernetesCRD</code> et <code>KubernetesIngress</code>. Le premier provider permettra de profiter des nouveaux objets fournis par la CRD et le second permet que Traefik gère les Ingress traditionnelles de Kubernetes et notamment celles de cert-manager.</li>
<li>Contrairement à la version 1 de Traefik, le provider <code>KubernetesIngress</code> ne supporte pas les annotations</li>
<li>En activant le provider <code>KubernetesIngress</code>, on se simplifie aussi la migration d'un socle Traefik V1 vers V2, au support des annotations près.</li>
</ul>
<p><code>traefik2/deployment.yml</code> :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">apps/v1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Deployment
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-controller
</span><span> </span><span style="color:#bf616a;">labels</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-lb
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">replicas</span><span>: </span><span style="color:#d08770;">2
</span><span> </span><span style="color:#bf616a;">selector</span><span>:
</span><span> </span><span style="color:#bf616a;">matchLabels</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-lb
</span><span> </span><span style="color:#bf616a;">template</span><span>:
</span><span> </span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">labels</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-lb
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-lb
</span><span> </span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">serviceAccountName</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-controller
</span><span> </span><span style="color:#bf616a;">terminationGracePeriodSeconds</span><span>: </span><span style="color:#d08770;">60
</span><span> </span><span style="color:#bf616a;">containers</span><span>:
</span><span> - </span><span style="color:#bf616a;">image</span><span>: </span><span style="color:#a3be8c;">traefik:2.1.1
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-lb
</span><span> </span><span style="color:#bf616a;">ports</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">web
</span><span> </span><span style="color:#bf616a;">containerPort</span><span>: </span><span style="color:#d08770;">80
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">admin
</span><span> </span><span style="color:#bf616a;">containerPort</span><span>: </span><span style="color:#d08770;">8080
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">secure
</span><span> </span><span style="color:#bf616a;">containerPort</span><span>: </span><span style="color:#d08770;">443
</span><span> </span><span style="color:#bf616a;">readinessProbe</span><span>:
</span><span> </span><span style="color:#bf616a;">httpGet</span><span>:
</span><span> </span><span style="color:#bf616a;">path</span><span>: </span><span style="color:#a3be8c;">/ping
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#a3be8c;">admin
</span><span> </span><span style="color:#bf616a;">failureThreshold</span><span>: </span><span style="color:#d08770;">1
</span><span> </span><span style="color:#bf616a;">initialDelaySeconds</span><span>: </span><span style="color:#d08770;">10
</span><span> </span><span style="color:#bf616a;">periodSeconds</span><span>: </span><span style="color:#d08770;">10
</span><span> </span><span style="color:#bf616a;">successThreshold</span><span>: </span><span style="color:#d08770;">1
</span><span> </span><span style="color:#bf616a;">timeoutSeconds</span><span>: </span><span style="color:#d08770;">2
</span><span> </span><span style="color:#bf616a;">livenessProbe</span><span>:
</span><span> </span><span style="color:#bf616a;">httpGet</span><span>:
</span><span> </span><span style="color:#bf616a;">path</span><span>: </span><span style="color:#a3be8c;">/ping
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#a3be8c;">admin
</span><span> </span><span style="color:#bf616a;">failureThreshold</span><span>: </span><span style="color:#d08770;">3
</span><span> </span><span style="color:#bf616a;">initialDelaySeconds</span><span>: </span><span style="color:#d08770;">10
</span><span> </span><span style="color:#bf616a;">periodSeconds</span><span>: </span><span style="color:#d08770;">10
</span><span> </span><span style="color:#bf616a;">successThreshold</span><span>: </span><span style="color:#d08770;">1
</span><span> </span><span style="color:#bf616a;">timeoutSeconds</span><span>: </span><span style="color:#d08770;">2
</span><span> </span><span style="color:#bf616a;">args</span><span>:
</span><span> - </span><span style="color:#a3be8c;">--entryPoints.web.address=:80
</span><span> - </span><span style="color:#a3be8c;">--entryPoints.secure.address=:443
</span><span> - </span><span style="color:#a3be8c;">--entryPoints.traefik.address=:8080
</span><span> - </span><span style="color:#a3be8c;">--api.dashboard=true
</span><span> - </span><span style="color:#a3be8c;">--api.insecure=true
</span><span> - </span><span style="color:#a3be8c;">--ping=true
</span><span> - </span><span style="color:#a3be8c;">--providers.kubernetescrd
</span><span> - </span><span style="color:#a3be8c;">--providers.kubernetesingress
</span><span> - </span><span style="color:#a3be8c;">--log.level=DEBUG
</span></code></pre>
<p>Pour permettre au cluster d'accéder aux différents ports, il faut définir un service via le fichier <code>traefik2/service.yml</code> :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Service
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">v1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-service-clusterip
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">selector</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-lb
</span><span> </span><span style="color:#bf616a;">ports</span><span>:
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">80
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">web
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">8080
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">admin
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">443
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">secure
</span><span> </span><span style="color:#bf616a;">type</span><span>: </span><span style="color:#a3be8c;">ClusterIP
</span></code></pre>
<p>Et pour avoir un accès de l'extérieur, il faut instancier un load-balancer via le fichier <code>traefik/traefik-service-loadbalancer.yml</code></p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Service
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">v1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-service-lb
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">selector</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-lb
</span><span> </span><span style="color:#bf616a;">ports</span><span>:
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">80
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">web
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">443
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">secure
</span><span> </span><span style="color:#bf616a;">type</span><span>: </span><span style="color:#a3be8c;">LoadBalancer
</span></code></pre>
<p>Pour donner l'accès au dashboard via une url sécurisée par un certificat Let's Encrypt, il faut déclarer un Ingress, dans le fichier <code>traefik2/api-ingress.yml</code> :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us/v1alpha1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">IngressRoute
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-web-ui
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">entryPoints</span><span>:
</span><span> - </span><span style="color:#a3be8c;">secure
</span><span> </span><span style="color:#bf616a;">routes</span><span>:
</span><span> - </span><span style="color:#bf616a;">match</span><span>: </span><span style="color:#a3be8c;">Host(`traefik2.k8s.cerenit.fr`)
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Rule
</span><span> </span><span style="color:#bf616a;">services</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-service-clusterip
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">8080
</span><span> </span><span style="color:#bf616a;">tls</span><span>:
</span><span> </span><span style="color:#bf616a;">secretName</span><span>: </span><span style="color:#a3be8c;">traefik2-cert
</span><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us/v1alpha1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">IngressRoute
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-web-ui-http
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">entryPoints</span><span>:
</span><span> - </span><span style="color:#a3be8c;">web
</span><span> </span><span style="color:#bf616a;">routes</span><span>:
</span><span> - </span><span style="color:#bf616a;">match</span><span>: </span><span style="color:#a3be8c;">Host(`traefik2.k8s.cerenit.fr`)
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Rule
</span><span> </span><span style="color:#bf616a;">services</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-service-clusterip
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">8080
</span></code></pre>
<p>L'idée est donc de rentre le dashboard accessible via l'url traefik2.k8s.cerenit.fr.</p>
<p>La section <code>tls</code> de l'ingress indique le nom d'hôte pour lequel le certificat va être disponible et le nom du secret contenant le certificat du site que nous n'avons pas encore créé.</p>
<p>Il nous faut donc créer ce certificat :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">cert-manager.io/v1alpha2
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Certificate
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-cert
</span><span> </span><span style="color:#bf616a;">namespace</span><span>: </span><span style="color:#a3be8c;">traefik2
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">secretName</span><span>: </span><span style="color:#a3be8c;">traefik2-cert
</span><span> </span><span style="color:#bf616a;">issuerRef</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">letsencrypt-prod
</span><span> </span><span style="color:#bf616a;">commonName</span><span>: </span><span style="color:#a3be8c;">traefik2.k8s.cerenit.fr
</span><span> </span><span style="color:#bf616a;">dnsNames</span><span>:
</span><span> - </span><span style="color:#a3be8c;">traefik2.k8s.cerenit.fr
</span></code></pre>
<p>Il ne reste plus qu'à faire pour instancier le tout :</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>kubectl apply -f traefik2/
</span></code></pre>
<p>Pour la génération du certificat, il conviendra de vérifier la sortie de</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">kubectl</span><span> describe certificate traefik2-cert
</span></code></pre>
<p>A ce stade, il nous manque :</p>
<ul>
<li>L'authentification au niveau accès</li>
<li>La redirection https</li>
</ul>
<p>C'est là que les <a rel="noopener" target="_blank" href="https://docs.traefik.io/middlewares/overview/">Middlewares</a> rentrent en jeu.</p>
<p>Pour la redirection https: <code>traefik2/middleware-redirect-https.yml</code></p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us/v1alpha1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Middleware
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">https-only
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">redirectScheme</span><span>:
</span><span> </span><span style="color:#bf616a;">scheme</span><span>: </span><span style="color:#a3be8c;">https
</span></code></pre>
<p>Pour l'authentification : <code>traefik2/middleware-auth.yml</code></p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us/v1alpha1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Middleware
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">auth-traefik-webui
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">basicAuth</span><span>:
</span><span> </span><span style="color:#bf616a;">secret</span><span>: </span><span style="color:#a3be8c;">traefik-auth
</span></code></pre>
<p>Il faut alors créer un secret kubernetes qui contient une variable <code>users</code> contenant la/les ligne(s) d'authentification :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">v1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Secret
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-auth
</span><span> </span><span style="color:#bf616a;">namespace</span><span>: </span><span style="color:#a3be8c;">traefik2
</span><span style="color:#bf616a;">data</span><span>:
</span><span> </span><span style="color:#bf616a;">users</span><span>: </span><span style="color:#b48ead;">|</span><span style="color:#d08770;">2
</span><span style="color:#a3be8c;"> dGVzdDokYXByMSRINnVza2trVyRJZ1hMUDZld1RyU3VCa1RycUU4d2ovCnRlc3QyOiRhcHIxJGQ5aHI5SEJCJDRIeHdnVWlyM0hQNEVzZ2dQL1FObzAK
</span></code></pre>
<p>Cela correspond à 2 comptes <code>test/test</code> et <code>test2/test2</code>, encodés en base64 et avec un mot de passe chiffré via htpasswd.</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/
</span><span>test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0
</span></code></pre>
<p>On peut alors mettre à jour notre fichier <code>traefik2/api-ingress.yml</code> et rajouter les deux middlewares que nous venons de définir :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us/v1alpha1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">IngressRoute
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-web-ui
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">entryPoints</span><span>:
</span><span> - </span><span style="color:#a3be8c;">secure
</span><span> </span><span style="color:#bf616a;">routes</span><span>:
</span><span> - </span><span style="color:#bf616a;">match</span><span>: </span><span style="color:#a3be8c;">Host(`traefik2.k8s.cerenit.fr`)
</span><span> </span><span style="color:#bf616a;">middlewares</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">auth-traefik-webui
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Rule
</span><span> </span><span style="color:#bf616a;">services</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-service-clusterip
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">8080
</span><span> </span><span style="color:#bf616a;">tls</span><span>:
</span><span> </span><span style="color:#bf616a;">secretName</span><span>: </span><span style="color:#a3be8c;">traefik2-cert
</span><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">traefik.containo.us/v1alpha1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">IngressRoute
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-web-ui-http
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">entryPoints</span><span>:
</span><span> - </span><span style="color:#a3be8c;">web
</span><span> </span><span style="color:#bf616a;">routes</span><span>:
</span><span> - </span><span style="color:#bf616a;">match</span><span>: </span><span style="color:#a3be8c;">Host(`traefik2.k8s.cerenit.fr`)
</span><span> </span><span style="color:#bf616a;">middlewares</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">https-only
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Rule
</span><span> </span><span style="color:#bf616a;">services</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik2-ingress-service-clusterip
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">8080
</span></code></pre>
<p>Et pour le prendre en compte:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">kubectl</span><span> apply</span><span style="color:#bf616a;"> -f</span><span> traefik2/
</span></code></pre>
<p>Vous devez alors avoir une redirection automatique vers le endpoint en https et une mire d'authentification.</p>
<p>Pour ceux qui font une migration dans le même cluster de Traefik V1 vers Traefik V2 :</p>
<ul>
<li>Si vous avez chaque instance Traefik avec son LoadBalancer et donc son IP dédiée, alors pour que les demandes de certificats ne soient pas interceptées par Traefik V1, il faudra personnaliser l'<code>ingressClass</code> de Traefik et créer un issuer cert-manager qui utilise cette même <code>ingressClass</code>.</li>
<li>Si vous utilisiez les annotations pour générer vos certificats, il vous faut passer par un object <code>Certificate</code></li>
<li>Comme dit plus haut, en activant le provider kubernetesIngress, vous pouvez directement migrer sur un socle Traefik v2 puis migrer progressivement vos Ingress vers des IngressRoute. Pas besoin de faire une migration en mode big bang.</li>
</ul>
<p>Sources utiles:</p>
<ul>
<li><a rel="noopener" target="_blank" href="https://docs.traefik.io/">Docs Traefik</a></li>
<li><a rel="noopener" target="_blank" href="https://blog.nobugware.com/post/2019/traefik-2-0-with-kubernetes/">Traefik 2.0 with Kubernetes</a></li>
<li><a rel="noopener" target="_blank" href="https://blog.nobugware.com/post/2019/advanced-traefik-2-0-with-kubernetes/">Advanced Traefik 2.0 with Kubernetes</a></li>
</ul>
Kubernetes @ OVH - Traefik et Cert Manager pour le stockage des certificats en secrets
2019-01-27T21:00:00+01:00
2019-01-27T21:00:00+01:00
Unknown
https://cerenit.fr/blog/kubernetes-ovh-traefik-cert-manager-secrets/
<p>L'objectif est de s'appuyer sur <a rel="noopener" target="_blank" href="https://cert-manager.readthedocs.io/">Cert-Manager</a> pour la génération et le stockage des certificats Let's Encrypt qui seront utilisés par Traefik. L'idée est de stocker ces certificats sous la forme de secrets et de ne plus avoir à provisionner un volume pour les stocker.</p>
<p>Installons déjà cert-manager :</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#65737e;"># Install the CustomResourceDefinition resources separately
</span><span style="color:#bf616a;">kubectl</span><span> apply</span><span style="color:#bf616a;"> --validate</span><span>=false</span><span style="color:#bf616a;"> -f</span><span> https://raw.githubusercontent.com/jetstack/cert-manager/release-0.11/deploy/manifests/00-crds.yaml
</span><span>
</span><span style="color:#65737e;"># Create the namespace for cert-manager
</span><span style="color:#bf616a;">kubectl</span><span> create namespace cert-manager
</span><span>
</span><span style="color:#65737e;"># Add the Jetstack Helm repository
</span><span style="color:#bf616a;">helm</span><span> repo add jetstack https://charts.jetstack.io
</span><span>
</span><span style="color:#65737e;"># Update your local Helm chart repository cache
</span><span style="color:#bf616a;">helm</span><span> repo update
</span><span>
</span><span style="color:#65737e;"># Install the cert-manager Helm chart
</span><span style="color:#bf616a;">helm</span><span> install \
</span><span style="color:#bf616a;"> --name</span><span> cert-manager \
</span><span style="color:#bf616a;"> --namespace</span><span> cert-manager \
</span><span style="color:#bf616a;"> --version</span><span> v0.11.0 \
</span><span> jetstack/cert-manager
</span></code></pre>
<p>Nous allons ensuite devoir créer un <a rel="noopener" target="_blank" href="https://cert-manager.readthedocs.io/en/latest/reference/issuers.html">Issuer</a> dans chaque namespace pour avoir un générateur de certificats propre à chaque namespace. Cela est notamment du au fait que Traefik s'attend à ce que le secret et l'ingress utilisant ce secret soient dans le même namespace. Nous spécifions également que nous utiliserons traefik comme ingress pour la génération des certificats.</p>
<p><code>cert-manager/issuer.yml</code>:</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">cert-manager.io/v1alpha2
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Issuer
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">letsencrypt-prod
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">acme</span><span>:
</span><span> </span><span style="color:#65737e;"># The ACME server URL
</span><span> </span><span style="color:#bf616a;">server</span><span>: </span><span style="color:#a3be8c;">https://acme-v02.api.letsencrypt.org/directory
</span><span> </span><span style="color:#65737e;"># Email address used for ACME registration
</span><span> </span><span style="color:#bf616a;">email</span><span>: </span><span style="color:#a3be8c;">user@example.com
</span><span> </span><span style="color:#65737e;"># Name of a secret used to store the ACME account private key
</span><span> </span><span style="color:#bf616a;">privateKeySecretRef</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">letsencrypt-prod
</span><span> </span><span style="color:#65737e;"># Enable HTTP01 validations
</span><span> </span><span style="color:#bf616a;">solvers</span><span>:
</span><span> - </span><span style="color:#bf616a;">selector</span><span>: {}
</span><span> </span><span style="color:#bf616a;">http01</span><span>:
</span><span> </span><span style="color:#bf616a;">ingress</span><span>:
</span><span> </span><span style="color:#bf616a;">class</span><span>: </span><span style="color:#a3be8c;">traefik
</span></code></pre>
<p>Puis créons le "issuer" dans la/les namespace(s) voulu(s) :</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#65737e;"># Create issuer in a given namespace
</span><span style="color:#bf616a;">kubectl</span><span> create</span><span style="color:#bf616a;"> -n </span><span><namespace> -f issuer.yml
</span></code></pre>
<p>Notre contexte de déploiement utilisant Traefik comme ingress, je remets ci-dessous la configuration que j'utilise avec les ajustements nécessaires pour l'utilisation de cert-manager. Il n'est en effet plus possible et il devient désormais inutile de déclarer la section "acme" dans traefik.toml. J'ai aussi supprimé la redirect automatique http vers https, il faudra la gérer au niveau des ingress.</p>
<p>Créons le namespace traefik :</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#65737e;"># Create namespace
</span><span style="color:#bf616a;">kubectl</span><span> create ns traefik
</span><span style="color:#65737e;"># Change context to this namespace so that all commands are by default run for this namespace
</span><span style="color:#65737e;"># see https://github.com/ahmetb/kubectx
</span><span style="color:#bf616a;">kubens</span><span> traefik
</span></code></pre>
<p>Commençons par <code>traefik/rbac.yml</code> - le fichier défini le compte de service (<code>Service Account</code>), le rôle au niveau du cluster (<code>Cluster Role</code>) et la liaison entre le rôle et le compte de service (<code>Cluster Role Binding</code>)</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">v1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ServiceAccount
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span> </span><span style="color:#bf616a;">namespace</span><span>: </span><span style="color:#a3be8c;">traefik
</span><span>---
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ClusterRole
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">rbac.authorization.k8s.io/v1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span style="color:#bf616a;">rules</span><span>:
</span><span> - </span><span style="color:#bf616a;">apiGroups</span><span>:
</span><span> - ""
</span><span> </span><span style="color:#bf616a;">resources</span><span>:
</span><span> - </span><span style="color:#a3be8c;">services
</span><span> - </span><span style="color:#a3be8c;">endpoints
</span><span> - </span><span style="color:#a3be8c;">secrets
</span><span> </span><span style="color:#bf616a;">verbs</span><span>:
</span><span> - </span><span style="color:#a3be8c;">get
</span><span> - </span><span style="color:#a3be8c;">list
</span><span> - </span><span style="color:#a3be8c;">watch
</span><span> - </span><span style="color:#bf616a;">apiGroups</span><span>:
</span><span> - </span><span style="color:#a3be8c;">extensions
</span><span> </span><span style="color:#bf616a;">resources</span><span>:
</span><span> - </span><span style="color:#a3be8c;">ingresses
</span><span> </span><span style="color:#bf616a;">verbs</span><span>:
</span><span> - </span><span style="color:#a3be8c;">get
</span><span> - </span><span style="color:#a3be8c;">list
</span><span> - </span><span style="color:#a3be8c;">watch
</span><span> - </span><span style="color:#bf616a;">apiGroups</span><span>:
</span><span> - </span><span style="color:#a3be8c;">extensions
</span><span> </span><span style="color:#bf616a;">resources</span><span>:
</span><span> - </span><span style="color:#a3be8c;">ingresses/status
</span><span> </span><span style="color:#bf616a;">verbs</span><span>:
</span><span> - </span><span style="color:#a3be8c;">update
</span><span>---
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ClusterRoleBinding
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">rbac.authorization.k8s.io/v1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span style="color:#bf616a;">roleRef</span><span>:
</span><span> </span><span style="color:#bf616a;">apiGroup</span><span>: </span><span style="color:#a3be8c;">rbac.authorization.k8s.io
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ClusterRole
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span style="color:#bf616a;">subjects</span><span>:
</span><span>- </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ServiceAccount
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span> </span><span style="color:#bf616a;">namespace</span><span>: </span><span style="color:#a3be8c;">traefik
</span><span>---
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ClusterRoleBinding
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">rbac.authorization.k8s.io/v1beta1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span style="color:#bf616a;">roleRef</span><span>:
</span><span> </span><span style="color:#bf616a;">apiGroup</span><span>: </span><span style="color:#a3be8c;">rbac.authorization.k8s.io
</span><span> </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ClusterRole
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span style="color:#bf616a;">subjects</span><span>:
</span><span>- </span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ServiceAccount
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span> </span><span style="color:#bf616a;">namespace</span><span>: </span><span style="color:#a3be8c;">traefik
</span></code></pre>
<p>Ensuite, pour Traefik, j'ai besoin d'un fichier <code>traefik.toml</code> avec la configuration que je mets à disposition sous la forme d'une <code>ConfigMap</code> dans un fichier <code>traefik/traefik-toml-configmap.yml</code> :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">v1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">ConfigMap
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-conf
</span><span style="color:#bf616a;">data</span><span>:
</span><span> </span><span style="color:#bf616a;">traefik.toml</span><span>: </span><span style="color:#b48ead;">|
</span><span style="color:#a3be8c;"> defaultEntryPoints = ["http", "https"]
</span><span style="color:#a3be8c;">
</span><span style="color:#a3be8c;"> logLevel = "INFO"
</span><span style="color:#a3be8c;">
</span><span style="color:#a3be8c;"> insecureSkipVerify = true
</span><span style="color:#a3be8c;">
</span><span style="color:#a3be8c;"> [entryPoints]
</span><span style="color:#a3be8c;"> [entryPoints.http]
</span><span style="color:#a3be8c;"> address = ":80"
</span><span style="color:#a3be8c;"> [entryPoints.https]
</span><span style="color:#a3be8c;"> address = ":443"
</span><span style="color:#a3be8c;"> [entryPoints.https.tls]
</span><span style="color:#a3be8c;"> [entryPoints.api]
</span><span style="color:#a3be8c;"> address = ":8080"
</span><span style="color:#a3be8c;">
</span><span style="color:#a3be8c;"> [api]
</span><span style="color:#a3be8c;"> entryPoint = "api"
</span><span style="color:#a3be8c;"> dashboard = true
</span><span style="color:#a3be8c;"> debug = false
</span><span style="color:#a3be8c;">
</span><span style="color:#a3be8c;"> [kubernetes]
</span></code></pre>
<p>Le dashboard est à protéger par une authentification pour éviter tout accès non souhaité. Je l'ai supprimé de la configuration par simplicité.</p>
<p>Je peux donc enfin déployer Traefik via le fichier <code>traefik/traefik-deployment.yml</code> :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Deployment
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">apps/v1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span> </span><span style="color:#bf616a;">labels</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-lb
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">replicas</span><span>: </span><span style="color:#d08770;">1
</span><span> </span><span style="color:#bf616a;">selector</span><span>:
</span><span> </span><span style="color:#bf616a;">matchLabels</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-lb
</span><span> </span><span style="color:#bf616a;">template</span><span>:
</span><span> </span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">labels</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-lb
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-lb
</span><span> </span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">serviceAccountName</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-controller
</span><span> </span><span style="color:#bf616a;">terminationGracePeriodSeconds</span><span>: </span><span style="color:#d08770;">60
</span><span> </span><span style="color:#bf616a;">containers</span><span>:
</span><span> - </span><span style="color:#bf616a;">image</span><span>: </span><span style="color:#a3be8c;">traefik:1.7.16
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-lb
</span><span> </span><span style="color:#bf616a;">volumeMounts</span><span>:
</span><span> - </span><span style="color:#bf616a;">mountPath</span><span>: </span><span style="color:#a3be8c;">/config
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-config
</span><span> </span><span style="color:#bf616a;">ports</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">http
</span><span> </span><span style="color:#bf616a;">containerPort</span><span>: </span><span style="color:#d08770;">80
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">admin
</span><span> </span><span style="color:#bf616a;">containerPort</span><span>: </span><span style="color:#d08770;">8080
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">secure
</span><span> </span><span style="color:#bf616a;">containerPort</span><span>: </span><span style="color:#d08770;">443
</span><span> </span><span style="color:#bf616a;">args</span><span>:
</span><span> - </span><span style="color:#a3be8c;">--configfile=/config/traefik.toml
</span><span> </span><span style="color:#bf616a;">volumes</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-config
</span><span> </span><span style="color:#bf616a;">configMap</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-conf
</span></code></pre>
<p>Nous déployons donc :</p>
<ul>
<li>Traefik en Deployment</li>
<li>Les ports 80, 443 et 8080 sont définis</li>
<li>La configuration est une ConfigMap</li>
</ul>
<p>Pour permettre au cluster d'accéder aux différents ports, il faut définir un service via le fichier <code>traefik-service-clusterip.yml</code> :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Service
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">v1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-service-clusterip
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">selector</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-lb
</span><span> </span><span style="color:#bf616a;">ports</span><span>:
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">80
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">web
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">8080
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">admin
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">443
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">secure
</span><span> </span><span style="color:#bf616a;">type</span><span>: </span><span style="color:#a3be8c;">ClusterIP
</span></code></pre>
<p>Et pour avoir un accès de l'extérieur, il faut instancier un load-balancer via le fichier <code>traefik/traefik-service-loadbalancer.yml</code></p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Service
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">v1
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-service-lb
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">selector</span><span>:
</span><span> </span><span style="color:#bf616a;">k8s-app</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-lb
</span><span> </span><span style="color:#bf616a;">ports</span><span>:
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">80
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">web
</span><span> - </span><span style="color:#bf616a;">protocol</span><span>: </span><span style="color:#a3be8c;">TCP
</span><span> </span><span style="color:#bf616a;">port</span><span>: </span><span style="color:#d08770;">443
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">secure
</span><span> </span><span style="color:#bf616a;">type</span><span>: </span><span style="color:#a3be8c;">LoadBalancer
</span></code></pre>
<p>Pour donner l'accès au dashboard via une url sécurisée par un certificat Let's Encrypt, il faut déclarer un Ingress, dans le fichier <code>traefik/traefik-api-ingress.yml</code> :</p>
<pre data-lang="yaml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yaml "><code class="language-yaml" data-lang="yaml"><span>---
</span><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">extensions/v1beta1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Ingress
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">annotations</span><span>:
</span><span> </span><span style="color:#bf616a;">kubernetes.io/ingress.class</span><span>: </span><span style="color:#a3be8c;">traefik
</span><span> </span><span style="color:#bf616a;">cert-manager.io/issuer</span><span>: </span><span style="color:#a3be8c;">letsencrypt-prod
</span><span> </span><span style="color:#bf616a;">traefik.ingress.kubernetes.io/redirect-entry-point</span><span>: </span><span style="color:#a3be8c;">https
</span><span> </span><span style="color:#bf616a;">traefik.ingress.kubernetes.io/redirect-permanent</span><span>: "</span><span style="color:#a3be8c;">true</span><span>"
</span><span> </span><span style="color:#bf616a;">ingress.kubernetes.io/ssl-redirect</span><span>: "</span><span style="color:#a3be8c;">true</span><span>"
</span><span> </span><span style="color:#bf616a;">ingress.kubernetes.io/ssl-temporary-redirect</span><span>: "</span><span style="color:#a3be8c;">false</span><span>"
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">traefik-web-ui
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">rules</span><span>:
</span><span> - </span><span style="color:#bf616a;">host</span><span>: </span><span style="color:#a3be8c;">traefik.k8s.cerenit.fr
</span><span> </span><span style="color:#bf616a;">http</span><span>:
</span><span> </span><span style="color:#bf616a;">paths</span><span>:
</span><span> - </span><span style="color:#bf616a;">path</span><span>: </span><span style="color:#a3be8c;">/
</span><span> </span><span style="color:#bf616a;">backend</span><span>:
</span><span> </span><span style="color:#bf616a;">serviceName</span><span>: </span><span style="color:#a3be8c;">traefik-ingress-service-clusterip
</span><span> </span><span style="color:#bf616a;">servicePort</span><span>: </span><span style="color:#a3be8c;">admin
</span><span> </span><span style="color:#bf616a;">tls</span><span>:
</span><span> - </span><span style="color:#bf616a;">hosts</span><span>:
</span><span> - </span><span style="color:#a3be8c;">traefik.k8s.cerenit.fr
</span><span> </span><span style="color:#bf616a;">secretName</span><span>: </span><span style="color:#a3be8c;">traefik-cert
</span></code></pre>
<p>L'idée est donc de rentre le dashboard accessible via l'url traefik.k8s.cerenit.fr.</p>
<p>La section <code>tls</code> de l'ingress indique le nom d'hôte pour lequel le certificat va être disponible et le nom du secret contenant le certificat du site que nous n'avons pas encore créé.</p>
<p>Les <a rel="noopener" target="_blank" href="https://docs.traefik.io/v1.7/configuration/backends/kubernetes/#annotations">annotations</a> permettent :</p>
<ul>
<li>de déclarer le type d'ingress à utiliser ; ici: traefik</li>
<li>de déclarer que le certificat qui doit être fourni par cert-manager est un certificat de type Let's Encrypt</li>
<li>de faire une redirection http vers https systématique.</li>
</ul>
<p>Les deux premières annotations permettent de ne pas avoir à déclarer soi même le certificat - il est automatiquement généré via <a rel="noopener" target="_blank" href="https://docs.cert-manager.io/en/latest/tasks/issuing-certificates/ingress-shim.html">ingress-shim</a>. Cela vous fait donc un objet kubernetes en moins à gérer dans votre configuration. Si vous ne souhaitez pas vous appuyer sur ce méchanisme d'ingress-shim, il vous faudra ne pas utiliser ces annotations et gérer vous même un objet "Certificate".</p>
<p>Il ne reste plus qu'à faire pour instancier le tout :</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>kubectl create -f traefik/
</span></code></pre>
<p>Pour la génération du certificat, il conviendra de vérifier la sortie de</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">kubectl</span><span> describe certificate traefik-cert
</span></code></pre>
<p>Et voilà - maintenant que le problème des certificats est corrigé, je vais pouvoir passer dans un contexte de déploiement multi-nodes.</p>