CérénIT - secrets
Le blog tech de Nicolas Steinmetz (Time Series, IoT, Web, Ops, Data)
Zola
2019-11-08T18:00:00+01:00
https://cerenit.fr/tags/secrets/atom.xml
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>