From c0eb1acd38953342e4e2260972ef3592a9e8603d Mon Sep 17 00:00:00 2001 From: alwinmarkcf <36843382+alwinmarkcf@users.noreply.github.com> Date: Fri, 10 Aug 2018 16:43:29 +0200 Subject: [PATCH] [stable/traefik] Add KV Provider support in order to make Traefik HA (#6813) This will add: * the possibility to configure one of the supported KV Provider * switch to store acme certs in that KV Provider or not * A Kubernetes Job to create Keys and import certs from a given file into the KV, which can be Mounted threw any given claim, mounted like: ``` acme: persistence: enabled: true existingClaim: acme-certs-pvc ``` Fixes: #6772 Copycated a lot from: https://github.com/helm/charts/pull/5563 so many thanks to: @siwyd Signed-off-by: Alwin Mark --- stable/traefik/Chart.yaml | 2 +- stable/traefik/README.md | 64 ++++++++++++++++++- stable/traefik/templates/configmap.yaml | 64 +++++++++++++++++++ stable/traefik/templates/storeconfig-job.yaml | 43 +++++++++++++ stable/traefik/values.yaml | 54 ++++++++++++++++ 5 files changed, 223 insertions(+), 4 deletions(-) create mode 100644 stable/traefik/templates/storeconfig-job.yaml diff --git a/stable/traefik/Chart.yaml b/stable/traefik/Chart.yaml index 60125b85ca..743bb8c836 100755 --- a/stable/traefik/Chart.yaml +++ b/stable/traefik/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v1 name: traefik -version: 1.38.2 +version: 1.39.0 appVersion: 1.6.5 description: A Traefik based Kubernetes ingress controller with Let's Encrypt support keywords: diff --git a/stable/traefik/README.md b/stable/traefik/README.md index 08a3fda5bf..7d5c1573b2 100644 --- a/stable/traefik/README.md +++ b/stable/traefik/README.md @@ -131,6 +131,19 @@ The following table lists the configurable parameters of the Traefik chart and t | `acme.persistence.accessMode` | `ReadWriteOnce` or `ReadOnly` | `ReadWriteOnce` | | `acme.persistence.existingClaim` | An Existing PVC name | `nil` | | `acme.persistence.size` | Minimum size of the volume requested | `1Gi` | +| `kvprovider.storeAcme` | Store acme certificates in KV Provider (needed for [HA](https://docs.traefik.io/configuration/acme/#as-a-key-value-store-entry)) | false | +| `kvprovider.importAcme` | Import acme certificates from acme.json of a mounted pvc (see: acme.persistence.existingClaim) | false | +| `kvprovider.$name.endpoint` | Endpoint of the provider like \:\ | none | +| `kvprovider.$name.watch` | Wether traefik should watch for changes | true | +| `kvprovider.$name.prefix` | Prefix where traefik data will be stored | traefik | +| `kvprovider.$name.filename` | Advanced configuration. See: https://docs.traefik.io/ | provider default | +| `kvprovider.$name.username` | Optional username | none | +| `kvprovider.$name.password` | Optional password | none | +| `kvprovider.$name.tls.ca` | Optional TLS certificate authority | none | +| `kvprovider.$name.tls.cert` | Optional TLS certificate | none | +| `kvprovider.$name.tls.key` | Optional TLS keyfile | none | +| `kvprovider.$name.tls.insecureSkipVerify` | Optional Wether to skip verify | none | +| `kvprovider.etcd.useAPIV3 | Use V3 or use V2 API of ETCD | false | | `dashboard.enabled` | Whether to enable the Traefik dashboard | `false` | | `dashboard.domain` | Domain for the Traefik dashboard | `traefik.example.com` | | `dashboard.service.annotations` | Annotations for the Traefik dashboard Service definition, specified as a map | None | @@ -196,11 +209,56 @@ $ helm install --name my-release --namespace kube-system --values values.yaml st ### Clustering / High Availability -Currently it is possible to specify the number of `replicas` but the implementation is naive. +To enable cluster support, you need one of: +* etcd +* consul +* boltdb +* zookeeper -**Full Traefik clustering with leader election is not yet supported.** +as kvprovider, especially when you are using Let's Encrypt. +If you have already certificates stored as acme.json in an existing persistent volume claim, you can import it. + +Given you have: +* a running [etcd operator](https://github.com/helm/charts/tree/master/stable/etcd-operator): +* you have created a master chart requiring this traefik chart +* an existing pvc with an `acme.json` called `acme-certs-pvc` +* you have an etcd template like: + ``` + apiVersion: "etcd.database.coreos.com/v1beta2" + kind: "EtcdCluster" + metadata: + name: {{ .Values.etcdCluster.name }} + labels: + app: {{ .Values.etcdCluster.name }} + annotations: + etcd.database.coreos.com/scope: clusterwide + spec: + size: 3 + version: "3.1.8" + ``` +* and these values in your values.yaml + ``` + etcdCluster: + name: traefik-etcd-cluster + + traefik: + replicas: 3 + acme: + persistence: + enabled: true + existingClaim: acme-certs-pvc + kvprovider: + storeAcme: true + importAcme: true + etcd: + endpoint: "traefik-etcd-cluster-client:2379" + useAPIV3: false + watch: true + prefix: traefik + ``` + +Then you are good to migrate your old certs into the kvprovider and run traefik in HA/Cluster-Mode. -It is heavily advised to not set a value for `replicas` if you also have Let's Encrypt configured. While setting `replicas` will work for many cases, since no leader is elected it has the consequence that each node will end up requesting Let's Encrypt certificates if this is also configured. This will quickly cut into the very modest rate limit that Let's Encrypt enforces. Also, if using challenges, the challenges may fail, as the challenge request may hit a pod without the challenge certificate. [Basic auth](https://docs.traefik.io/toml/#api-backend) can be specified via `dashboard.auth.basic` as a map of usernames to passwords as below. See the linked Traefik documentation for accepted passwords encodings. diff --git a/stable/traefik/templates/configmap.yaml b/stable/traefik/templates/configmap.yaml index d73910037e..efd75adfbe 100644 --- a/stable/traefik/templates/configmap.yaml +++ b/stable/traefik/templates/configmap.yaml @@ -107,10 +107,74 @@ data: {{ printf "\"%s\" = \"%s\"" $header $action }} {{- end}} {{- end}} + {{- if .Values.kvprovider.etcd }} + [etcd] + endpoint = "{{ .Values.kvprovider.etcd.endpoint }}" + watch = {{ .Values.kvprovider.etcd.watch }} + prefix = "{{ .Values.kvprovider.etcd.prefix }}" + useAPIV3 = {{ .Values.kvprovider.etcd.useAPIV3 }} + {{- if .Values.kvprovider.etcd.username }}username = {{ .Values.kvprovider.etcd.username }}{{- end }} + {{- if .Values.kvprovider.etcd.password }}password = {{ .Values.kvprovider.etcd.password }}{{- end }} + {{- if .Values.kvprovider.etcd.tls }} + [etcd.tls] + {{- end }} + {{ range $key, $value := .Values.kvprovider.etcd.tls }} + {{ $key }} = {{ $value }} + {{ end }} + {{- end }} + {{- if .Values.kvprovider.consul }} + [consul] + endpoint = "{{ .Values.kvprovider.consul.endpoint }}" + watch = {{ .Values.kvprovider.consul.watch }} + prefix = {{ .Values.kvprovider.consul.prefix }} + {{- if .Values.kvprovider.consul.username }}username = {{ .Values.kvprovider.consul.username }}{{- end }} + {{- if .Values.kvprovider.consul.password }}password = {{ .Values.kvprovider.consul.password }}{{- end }} + {{- if .Values.kvprovider.consul.tls }} + [consul.tls] + {{- end }} + {{ range $key, $value := .Values.kvprovider.consul.tls }} + {{ $key }} = {{ $value }} + {{ end }} + {{- end }} + {{- if .Values.kvprovider.boltdb }} + [boltdb] + endpoint = "{{ .Values.kvprovider.boltdb.endpoint }}" + watch = {{ .Values.kvprovider.boltdb.watch }} + prefix = {{ .Values.kvprovider.boltdb.prefix }} + {{- if .Values.kvprovider.boltdb.username }}username = {{ .Values.kvprovider.boltdb.username }}{{- end }} + {{- if .Values.kvprovider.boltdb.password }}password = {{ .Values.kvprovider.boltdb.password }}{{- end }} + {{- if .Values.kvprovider.boltdb.tls }} + [boltdb.tls] + {{- end }} + {{ range $key, $value := .Values.kvprovider.boltdb.tls }} + {{ $key }} = {{ $value }} + {{ end }} + {{- end }} + {{- if .Values.kvprovider.zookeeper }} + [zookeeper] + endpoint = "{{ .Values.kvprovider.zookeeper.endpoint }}" + watch = {{ .Values.kvprovider.zookeeper.watch }} + prefix = {{ .Values.kvprovider.zookeeper.prefix }} + {{- if .Values.kvprovider.zookeeper.username }}username = {{ .Values.kvprovider.zookeeper.username }}{{- end }} + {{- if .Values.kvprovider.zookeeper.password }}password = {{ .Values.kvprovider.zookeeper.password }}{{- end }} + {{- if .Values.kvprovider.zookeeper.tls }} + [zookeeper.tls] + {{- end }} + {{ range $key, $value := .Values.kvprovider.zookeeper.tls }} + {{ $key }} = {{ $value }} + {{ end }} + {{- end }} {{- if .Values.acme.enabled }} [acme] email = "{{ .Values.acme.email }}" + {{- if .Values.kvprovider.storeAcme }} + storage = "traefik/acme/account" + {{- if .Values.kvprovider.importAcme }} + storageFile = "/acme/acme.json" + {{- end }} + {{- else }} storage = "/acme/acme.json" + {{- end }} entryPoint = "https" onHostRule = true {{- if .Values.acme.staging }} diff --git a/stable/traefik/templates/storeconfig-job.yaml b/stable/traefik/templates/storeconfig-job.yaml new file mode 100644 index 0000000000..a373726f50 --- /dev/null +++ b/stable/traefik/templates/storeconfig-job.yaml @@ -0,0 +1,43 @@ +{{- if .Values.kvprovider.storeAcme }} +apiVersion: batch/v1 +kind: Job +metadata: + name: "storeconfig-job" + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-delete-policy": hook-succeeded + labels: + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app: {{ template "traefik.name" . }} +spec: + template: + metadata: + name: "storeconfig-job" + labels: + app: {{ template "traefik.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + spec: + restartPolicy: Never + containers: + - name: storeconfig-job + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + args: + - storeconfig + - --configfile=/config/traefik.toml + volumeMounts: + - mountPath: /config + name: config + - mountPath: /acme + name: acme + volumes: + - name: config + configMap: + name: {{ template "traefik.fullname" . }} + - name: acme + {{- if .Values.acme.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.acme.persistence.existingClaim | default (printf "%s-acme" (include "traefik.fullname" .)) }} + {{- else }} + emptyDir: {} + {{- end }} +{{- end }} diff --git a/stable/traefik/values.yaml b/stable/traefik/values.yaml index f550212200..a4d68f71aa 100644 --- a/stable/traefik/values.yaml +++ b/stable/traefik/values.yaml @@ -55,6 +55,60 @@ ssl: # tlsMinVersion: VersionTLS12 defaultCert: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVtekNDQTRPZ0F3SUJBZ0lKQUpBR1FsTW1DMGt5TUEwR0NTcUdTSWIzRFFFQkJRVUFNSUdQTVFzd0NRWUQKVlFRR0V3SlZVekVSTUE4R0ExVUVDQk1JUTI5c2IzSmhaRzh4RURBT0JnTlZCQWNUQjBKdmRXeGtaWEl4RkRBUwpCZ05WQkFvVEMwVjRZVzF3YkdWRGIzSndNUXN3Q1FZRFZRUUxFd0pKVkRFV01CUUdBMVVFQXhRTktpNWxlR0Z0CmNHeGxMbU52YlRFZ01CNEdDU3FHU0liM0RRRUpBUllSWVdSdGFXNUFaWGhoYlhCc1pTNWpiMjB3SGhjTk1UWXgKTURJME1qRXdPVFV5V2hjTk1UY3hNREkwTWpFd09UVXlXakNCanpFTE1Ba0dBMVVFQmhNQ1ZWTXhFVEFQQmdOVgpCQWdUQ0VOdmJHOXlZV1J2TVJBd0RnWURWUVFIRXdkQ2IzVnNaR1Z5TVJRd0VnWURWUVFLRXd0RmVHRnRjR3hsClEyOXljREVMTUFrR0ExVUVDeE1DU1ZReEZqQVVCZ05WQkFNVURTb3VaWGhoYlhCc1pTNWpiMjB4SURBZUJna3EKaGtpRzl3MEJDUUVXRVdGa2JXbHVRR1Y0WVcxd2JHVXVZMjl0TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQwpBUThBTUlJQkNnS0NBUUVBdHVKOW13dzlCYXA2SDROdUhYTFB6d1NVZFppNGJyYTFkN1ZiRUJaWWZDSStZNjRDCjJ1dThwdTNhVTVzYXVNYkQ5N2pRYW95VzZHOThPUHJlV284b3lmbmRJY3RFcmxueGpxelUyVVRWN3FEVHk0bkEKNU9aZW9SZUxmZXFSeGxsSjE0VmlhNVFkZ3l3R0xoRTlqZy9jN2U0WUp6bmg5S1dZMnFjVnhEdUdEM2llaHNEbgphTnpWNFdGOWNJZm1zOHp3UHZPTk5MZnNBbXc3dUhUKzNiSzEzSUloeDI3ZmV2cXVWcENzNDFQNnBzdStWTG4yCjVIRHk0MXRoQkN3T0wrTithbGJ0ZktTcXM3TEFzM25RTjFsdHpITHZ5MGE1RGhkakpUd2tQclQrVXhwb0tCOUgKNFpZazErRUR0N09QbGh5bzM3NDFRaE4vSkNZK2RKbkFMQnNValFJREFRQUJvNEgzTUlIME1CMEdBMVVkRGdRVwpCQlJwZVc1dFhMdHh3TXJvQXM5d2RNbTUzVVVJTERDQnhBWURWUjBqQklHOE1JRzVnQlJwZVc1dFhMdHh3TXJvCkFzOXdkTW01M1VVSUxLR0JsYVNCa2pDQmp6RUxNQWtHQTFVRUJoTUNWVk14RVRBUEJnTlZCQWdUQ0VOdmJHOXkKWVdSdk1SQXdEZ1lEVlFRSEV3ZENiM1ZzWkdWeU1SUXdFZ1lEVlFRS0V3dEZlR0Z0Y0d4bFEyOXljREVMTUFrRwpBMVVFQ3hNQ1NWUXhGakFVQmdOVkJBTVVEU291WlhoaGJYQnNaUzVqYjIweElEQWVCZ2txaGtpRzl3MEJDUUVXCkVXRmtiV2x1UUdWNFlXMXdiR1V1WTI5dGdna0FrQVpDVXlZTFNUSXdEQVlEVlIwVEJBVXdBd0VCL3pBTkJna3EKaGtpRzl3MEJBUVVGQUFPQ0FRRUFjR1hNZms4TlpzQit0OUtCemwxRmw2eUlqRWtqSE8wUFZVbEVjU0QyQjRiNwpQeG5NT2pkbWdQcmF1SGI5dW5YRWFMN3p5QXFhRDZ0YlhXVTZSeENBbWdMYWpWSk5aSE93NDVOMGhyRGtXZ0I4CkV2WnRRNTZhbW13QzFxSWhBaUE2MzkwRDNDc2V4N2dMNm5KbzdrYnIxWVdVRzN6SXZveGR6OFlEclpOZVdLTEQKcFJ2V2VuMGxNYnBqSVJQNFhac25DNDVDOWdWWGRoM0xSZTErd3lRcTZoOVFQaWxveG1ENk5wRTlpbVRPbjJBNQovYkozVktJekFNdWRlVTZrcHlZbEpCemRHMXVhSFRqUU9Xb3NHaXdlQ0tWVVhGNlV0aXNWZGRyeFF0aDZFTnlXCnZJRnFhWng4NCtEbFNDYzkzeWZrL0dsQnQrU0tHNDZ6RUhNQjlocVBiQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K defaultKey: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBdHVKOW13dzlCYXA2SDROdUhYTFB6d1NVZFppNGJyYTFkN1ZiRUJaWWZDSStZNjRDCjJ1dThwdTNhVTVzYXVNYkQ5N2pRYW95VzZHOThPUHJlV284b3lmbmRJY3RFcmxueGpxelUyVVRWN3FEVHk0bkEKNU9aZW9SZUxmZXFSeGxsSjE0VmlhNVFkZ3l3R0xoRTlqZy9jN2U0WUp6bmg5S1dZMnFjVnhEdUdEM2llaHNEbgphTnpWNFdGOWNJZm1zOHp3UHZPTk5MZnNBbXc3dUhUKzNiSzEzSUloeDI3ZmV2cXVWcENzNDFQNnBzdStWTG4yCjVIRHk0MXRoQkN3T0wrTithbGJ0ZktTcXM3TEFzM25RTjFsdHpITHZ5MGE1RGhkakpUd2tQclQrVXhwb0tCOUgKNFpZazErRUR0N09QbGh5bzM3NDFRaE4vSkNZK2RKbkFMQnNValFJREFRQUJBb0lCQUhrTHhka0dxNmtCWWQxVAp6MkU4YWFENnhneGpyY2JSdGFCcTc3L2hHbVhuQUdaWGVWcE81MG1SYW8wbHZ2VUgwaE0zUnZNTzVKOHBrdzNmCnRhWTQxT1dDTk1PMlYxb1MvQmZUK3Zsblh6V1hTemVQa0pXd2lIZVZMdVdEaVVMQVBHaWl4emF2RFMyUnlQRmEKeGVRdVNhdE5pTDBGeWJGMG5Zd3pST3ZoL2VSa2NKVnJRZlZudU1melFkOGgyMzZlb1UxU3B6UnhSNklubCs5UApNc1R2Wm5OQmY5d0FWcFo5c1NMMnB1V1g3SGNSMlVnem5oMDNZWUZJdGtDZndtbitEbEdva09YWHBVM282aWY5ClRIenBleHdubVJWSmFnRG85bTlQd2t4QXowOW80cXExdHJoU1g1U2p1K0xyNFJvOHg5bytXdUF1VnVwb0lHd0wKMWVseERFRUNnWUVBNzVaWGp1enNJR09PMkY5TStyYVFQcXMrRHZ2REpzQ3gyZnRudk1WWVJKcVliaGt6YnpsVQowSHBCVnk3NmE3WmF6Umxhd3RGZ3ljMlpyQThpM0F3K3J6d1pQclNJeWNieC9nUVduRzZlbFF1Y0FFVWdXODRNCkdSbXhKUGlmOGRQNUxsZXdRalFjUFJwZVoxMzlYODJreGRSSEdma1pscHlXQnFLajBTWExRSEVDZ1lFQXcybkEKbUVXdWQzZFJvam5zbnFOYjBlYXdFUFQrbzBjZ2RyaENQOTZQK1pEekNhcURUblZKV21PeWVxRlk1eVdSSEZOLwpzbEhXU2lTRUFjRXRYZys5aGlMc0RXdHVPdzhUZzYyN2VrOEh1UUtMb2tWWEFUWG1NZG9xOWRyQW9INU5hV2lECmRSY3dEU2EvamhIN3RZV1hKZDA4VkpUNlJJdU8vMVZpbDBtbEk5MENnWUVBb2lsNkhnMFNUV0hWWDNJeG9raEwKSFgrK1ExbjRYcFJ5VEg0eldydWY0TjlhYUxxNTY0QThmZGNodnFiWGJHeEN6U3RxR1E2cW1peUU1TVpoNjlxRgoyd21zZEpxeE14RnEzV2xhL0lxSzM0cTZEaHk3cUNld1hKVGRKNDc0Z3kvY0twZkRmeXZTS1RGZDBFejNvQTZLCmhqUUY0L2lNYnpxUStQREFQR0YrVHFFQ2dZQmQ1YnZncjJMMURzV1FJU3M4MHh3MDBSZDdIbTRaQVAxdGJuNk8KK0IvUWVNRC92UXBaTWV4c1hZbU9lV2Noc3FCMnJ2eW1MOEs3WDY1NnRWdGFYay9nVzNsM3ZVNTdYSFF4Q3RNUwpJMVYvcGVSNHRiN24yd0ZncFFlTm1XNkQ4QXk4Z0xiaUZhRkdRSDg5QWhFa0dTd1d5cWJKc2NoTUZZOUJ5OEtUCkZaVWZsUUtCZ0V3VzJkVUpOZEJMeXNycDhOTE1VbGt1ZnJxbllpUTNTQUhoNFZzWkg1TXU0MW55Yi95NUUyMW4KMk55d3ltWGRlb3VJcFZjcUlVTXl0L3FKRmhIcFJNeVEyWktPR0QyWG5YaENNVlRlL0FQNDJod294Nm02QkZpQgpvemZFa2wwak5uZmREcjZrL1p2MlQ1TnFzaWxaRXJBQlZGOTBKazdtUFBIa0Q2R1ZMUUJ4Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== + +kvprovider: + ## If you want to run Traefik in HA mode, you will need to setup a KV Provider. Therefore you can choose one of + ## * etcd + ## * consul + ## * boltdb + ## * zookeeper + ## + ## ref: https://docs.traefik.io/user-guide/cluster/ + + ## storeAcme has to be enabled to support HA Support using acme, but at least one kvprovider is needed + storeAcme: false + importAcme: false + + # etcd: + # endpoint: etcd-service:2379 + # useAPIV3: false + # watch: true + # prefix: traefik + + ## Override default configuration template. + ## For advanced users :) + ## + ## Optional + # filename: consul.tmpl + # username: foo + # password: bar + # tls: + # ca: "/etc/ssl/ca.crt" + # cert: "/etc/ssl/consul.crt" + # key: "/etc/ssl/consul.key" + # insecureSkipVerify: true + # + # consul: + # endpoint: consul-service:8500 + # watch: true + # prefix: traefik + + ## Override default configuration template. + ## For advanced users :) + ## + ## Optional + # filename: consul.tmpl + # username: foo + # password: bar + # tls: + # ca: "/etc/ssl/ca.crt" + # cert: "/etc/ssl/consul.crt" + # key: "/etc/ssl/consul.key" + # insecureSkipVerify: true + + ## only relevant for etcd + + acme: enabled: false email: admin@example.com