Browse Source

Add support for cert-manager managed webhook certs (#2394)

* Add support for cert-manager managed webhook certs

Signed-off-by: Eric Stokes <fernferret@gmail.com>

* Ran make helm.docs to update README.md

Signed-off-by: Eric Stokes <fernferret@gmail.com>

* Added unittests for chart

Signed-off-by: Eric Stokes <fernferret@gmail.com>

* tidy: Fixed trailing whitespace

Signed-off-by: Eric Stokes <fernferret@gmail.com>

---------

Signed-off-by: Eric Stokes <fernferret@gmail.com>
Eric 2 years ago
parent
commit
86aad7d8ab

+ 7 - 0
deploy/charts/external-secrets/README.md

@@ -152,6 +152,13 @@ The command removes all the Kubernetes components associated with the chart and
 | webhook.affinity | object | `{}` |  |
 | webhook.affinity | object | `{}` |  |
 | webhook.certCheckInterval | string | `"5m"` | Specifices the time to check if the cert is valid |
 | webhook.certCheckInterval | string | `"5m"` | Specifices the time to check if the cert is valid |
 | webhook.certDir | string | `"/tmp/certs"` |  |
 | webhook.certDir | string | `"/tmp/certs"` |  |
+| webhook.certManager.addInjectorAnnotations | bool | `true` | Automatically add the cert-manager.io/inject-ca-from annotation to the webhooks and CRDs. As long as you have the cert-manager CA Injector enabled, this will automatically setup your webhook's CA to the one used by cert-manager. See https://cert-manager.io/docs/concepts/ca-injector |
+| webhook.certManager.cert.annotations | object | `{}` | Add extra annotations to the Certificate resource. |
+| webhook.certManager.cert.create | bool | `true` | Create a certificate resource within this chart. See https://cert-manager.io/docs/usage/certificate/ |
+| webhook.certManager.cert.duration | string | `""` | Set the requested duration (i.e. lifetime) of the Certificate. See https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec |
+| webhook.certManager.cert.issuerRef | object | `{"group":"cert-manager.io","kind":"Issuer","name":"my-issuer"}` | For the Certificate created by this chart, setup the issuer. See https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.IssuerSpec |
+| webhook.certManager.cert.renewBefore | string | `""` | How long before the currently issued certificate’s expiry cert-manager should renew the certificate. See https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec Note that renewBefore should be greater than .webhook.lookaheadInterval since the webhook will check this far in advance that the certificate is valid. |
+| webhook.certManager.enabled | bool | `false` | Enabling cert-manager support will disable the built in secret and switch to using cert-manager (installed separately) to automatically issue and renew the webhook certificate. This chart does not install cert-manager for you, See https://cert-manager.io/docs/ |
 | webhook.create | bool | `true` | Specifies whether a webhook deployment be created. |
 | webhook.create | bool | `true` | Specifies whether a webhook deployment be created. |
 | webhook.deploymentAnnotations | object | `{}` | Annotations to add to Deployment |
 | webhook.deploymentAnnotations | object | `{}` | Annotations to add to Deployment |
 | webhook.extraArgs | object | `{}` |  |
 | webhook.extraArgs | object | `{}` |  |

+ 8 - 0
deploy/charts/external-secrets/templates/validatingwebhook.yaml

@@ -8,6 +8,10 @@ metadata:
     {{- with .Values.commonLabels }}
     {{- with .Values.commonLabels }}
     {{ toYaml . | nindent 4 }}
     {{ toYaml . | nindent 4 }}
     {{- end }}
     {{- end }}
+  {{- if and .Values.webhook.certManager.enabled .Values.webhook.certManager.addInjectorAnnotations }}
+  annotations:
+    cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "external-secrets.fullname" . }}-webhook
+  {{- end }}
 webhooks:
 webhooks:
 - name: "validate.secretstore.external-secrets.io"
 - name: "validate.secretstore.external-secrets.io"
   rules:
   rules:
@@ -50,6 +54,10 @@ metadata:
     {{- with .Values.commonLabels }}
     {{- with .Values.commonLabels }}
     {{ toYaml . | nindent 4 }}
     {{ toYaml . | nindent 4 }}
     {{- end }}
     {{- end }}
+  {{- if and .Values.webhook.certManager.enabled .Values.webhook.certManager.addInjectorAnnotations }}
+  annotations:
+    cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "external-secrets.fullname" . }}-webhook
+  {{- end }}
 webhooks:
 webhooks:
 - name: "validate.externalsecret.external-secrets.io"
 - name: "validate.externalsecret.external-secrets.io"
   rules:
   rules:

+ 30 - 0
deploy/charts/external-secrets/templates/webhook-certificate.yaml

@@ -0,0 +1,30 @@
+{{- if and .Values.webhook.create .Values.webhook.certManager.enabled .Values.webhook.certManager.cert.create }}
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+  name: {{ include "external-secrets.fullname" . }}-webhook
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "external-secrets-webhook.labels" . | nindent 4 }}
+    external-secrets.io/component: webhook
+  {{- with .Values.webhook.certManager.cert.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  commonName: {{ include "external-secrets.fullname" . }}-webhook
+  dnsNames:
+    - {{ include "external-secrets.fullname" . }}-webhook
+    - {{ include "external-secrets.fullname" . }}-webhook.{{ .Release.Namespace }}
+    - {{ include "external-secrets.fullname" . }}-webhook.{{ .Release.Namespace }}.svc
+  issuerRef:
+    {{- toYaml .Values.webhook.certManager.cert.issuerRef | nindent 4 }}
+  {{- with .Values.webhook.certManager.cert.duration }}
+  duration: {{ . | quote }}
+  {{- end }}
+  {{- with .Values.webhook.certManager.cert.renewBefore }}
+  renewBefore: {{ . | quote }}
+  {{- end }}
+  secretName: {{ include "external-secrets.fullname" . }}-webhook
+{{- end }}

+ 1 - 1
deploy/charts/external-secrets/templates/webhook-secret.yaml

@@ -1,4 +1,4 @@
-{{- if .Values.webhook.create }}
+{{- if and .Values.webhook.create (not .Values.webhook.certManager.enabled) }}
 apiVersion: v1
 apiVersion: v1
 kind: Secret
 kind: Secret
 metadata:
 metadata:

+ 13 - 0
deploy/charts/external-secrets/tests/__snapshot__/webhook_test.yaml.snap

@@ -70,3 +70,16 @@ should match snapshot of default values:
             - name: certs
             - name: certs
               secret:
               secret:
                 secretName: RELEASE-NAME-external-secrets-webhook
                 secretName: RELEASE-NAME-external-secrets-webhook
+  2: |
+    apiVersion: v1
+    kind: Secret
+    metadata:
+      labels:
+        app.kubernetes.io/instance: RELEASE-NAME
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/name: external-secrets-webhook
+        app.kubernetes.io/version: v0.8.3
+        external-secrets.io/component: webhook
+        helm.sh/chart: external-secrets-0.8.3
+      name: RELEASE-NAME-external-secrets-webhook
+      namespace: NAMESPACE

+ 114 - 0
deploy/charts/external-secrets/tests/webhook_test.yaml

@@ -1,10 +1,18 @@
 suite: test webhook deployment
 suite: test webhook deployment
 templates:
 templates:
   - webhook-deployment.yaml
   - webhook-deployment.yaml
+  - webhook-secret.yaml
+  - webhook-certificate.yaml
+  - validatingwebhook.yaml
+  - crds/externalsecret.yaml
 tests:
 tests:
   - it: should match snapshot of default values
   - it: should match snapshot of default values
     asserts:
     asserts:
       - matchSnapshot: {}
       - matchSnapshot: {}
+    templates:
+      - webhook-deployment.yaml
+      - webhook-secret.yaml
+      # webhook-certificate.yaml is not rendered by default
   - it: should set imagePullPolicy to Always
   - it: should set imagePullPolicy to Always
     set:
     set:
       webhook.image.pullPolicy: Always
       webhook.image.pullPolicy: Always
@@ -12,11 +20,13 @@ tests:
       - equal:
       - equal:
           path: spec.template.spec.containers[0].imagePullPolicy
           path: spec.template.spec.containers[0].imagePullPolicy
           value: Always
           value: Always
+    template: webhook-deployment.yaml
   - it: should imagePullPolicy to be default value IfNotPresent
   - it: should imagePullPolicy to be default value IfNotPresent
     asserts:
     asserts:
       - equal:
       - equal:
           path: spec.template.spec.containers[0].imagePullPolicy
           path: spec.template.spec.containers[0].imagePullPolicy
           value: IfNotPresent
           value: IfNotPresent
+    template: webhook-deployment.yaml
   - it: should override securityContext
   - it: should override securityContext
     set:
     set:
       webhook.podSecurityContext:
       webhook.podSecurityContext:
@@ -40,6 +50,7 @@ tests:
             runAsUser: 3000
             runAsUser: 3000
             seccompProfile:
             seccompProfile:
               type: RuntimeDefault
               type: RuntimeDefault
+    template: webhook-deployment.yaml
   - it: should override hostNetwork
   - it: should override hostNetwork
     set:
     set:
       webhook.hostNetwork: true
       webhook.hostNetwork: true
@@ -47,3 +58,106 @@ tests:
       - equal:
       - equal:
           path: spec.template.spec.hostNetwork
           path: spec.template.spec.hostNetwork
           value: true
           value: true
+    template: webhook-deployment.yaml
+  - it: should create a certificate CRD
+    set:
+      webhook.certManager.enabled: true
+      webhook.certManager.cert.duration: "10d"
+      webhook.certManager.cert.renewBefore: "5d"
+    asserts:
+      - equal:
+          path: metadata.name
+          value: "RELEASE-NAME-external-secrets-webhook"
+      - equal:
+          path: spec.secretName
+          value: "RELEASE-NAME-external-secrets-webhook"
+      - equal:
+          path: spec.commonName
+          value: "RELEASE-NAME-external-secrets-webhook"
+      - equal:
+          path: spec.dnsNames[0]
+          value: "RELEASE-NAME-external-secrets-webhook"
+      - equal:
+          path: spec.issuerRef.group
+          value: "cert-manager.io"
+      - equal:
+          path: spec.issuerRef.kind
+          value: "Issuer"
+      - equal:
+          path: spec.issuerRef.name
+          value: "my-issuer"
+      - equal:
+          path: spec.duration
+          value: "10d"
+      - equal:
+          path: spec.renewBefore
+          value: "5d"
+      - hasDocuments:
+          count: 1
+    templates:
+      - webhook-certificate.yaml
+  - it: should not create the webhook secret
+    set:
+      webhook.certManager.enabled: true
+    asserts:
+      - hasDocuments:
+          count: 0
+    template: webhook-secret.yaml
+  - it: should not create the secret nor the certificate
+    set:
+      webhook.certManager.enabled: true
+      webhook.certManager.cert.create: false
+    asserts:
+      - hasDocuments:
+          count: 0
+    templates:
+      - webhook-secret.yaml
+      - webhook-certificate.yaml
+  - it: should
+    set:
+      webhook.certManager.enabled: true
+    asserts:
+      - equal:
+          path: metadata.name
+          value: "RELEASE-NAME-external-secrets-webhook"
+      - hasDocuments:
+          count: 1
+    template: webhook-certificate.yaml
+  - it: should allow using a cluster issuer
+    set:
+      webhook.certManager.enabled: true
+      webhook.certManager.cert.issuerRef.kind: ClusterIssuer
+      webhook.certManager.cert.issuerRef.name: my-other-issuer
+    asserts:
+      - equal:
+          path: spec.issuerRef.kind
+          value: "ClusterIssuer"
+      - equal:
+          path: spec.issuerRef.name
+          value: "my-other-issuer"
+    templates:
+      - webhook-certificate.yaml
+  - it: should add annotations to the webhook
+    set:
+      webhook.create: true
+      webhook.certManager.enabled: true
+      webhook.certManager.addInjectorAnnotations: true
+    asserts:
+      - equal:
+          path: metadata.annotations["cert-manager.io/inject-ca-from"]
+          value: "NAMESPACE/RELEASE-NAME-external-secrets-webhook"
+    templates:
+      - validatingwebhook.yaml
+      - crds/externalsecret.yaml
+  - it: should not add annotations to the webhook
+    set:
+      webhook.create: true
+      webhook.certManager.enabled: true
+      webhook.certManager.addInjectorAnnotations: false
+    asserts:
+      - isNull:
+          path: metadata.annotations["cert-manager.io/inject-ca-from"]
+          # value: "NAMESPACE/RELEASE-NAME-external-secrets-webhook"
+    templates:
+      - validatingwebhook.yaml
+      - crds/externalsecret.yaml

+ 34 - 0
deploy/charts/external-secrets/values.yaml

@@ -248,6 +248,40 @@ webhook:
     name: ""
     name: ""
   nodeSelector: {}
   nodeSelector: {}
 
 
+  certManager:
+    # -- Enabling cert-manager support will disable the built in secret and
+    # switch to using cert-manager (installed separately) to automatically issue
+    # and renew the webhook certificate. This chart does not install
+    # cert-manager for you, See https://cert-manager.io/docs/
+    enabled: false
+    # -- Automatically add the cert-manager.io/inject-ca-from annotation to the
+    # webhooks and CRDs. As long as you have the cert-manager CA Injector
+    # enabled, this will automatically setup your webhook's CA to the one used
+    # by cert-manager. See https://cert-manager.io/docs/concepts/ca-injector
+    addInjectorAnnotations: true
+    cert:
+      # -- Create a certificate resource within this chart. See
+      # https://cert-manager.io/docs/usage/certificate/
+      create: true
+      # -- For the Certificate created by this chart, setup the issuer. See
+      # https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.IssuerSpec
+      issuerRef:
+        group: cert-manager.io
+        kind: "Issuer"
+        name: "my-issuer"
+      # -- Set the requested duration (i.e. lifetime) of the Certificate. See
+      # https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec
+      duration: ""
+      # -- How long before the currently issued certificate’s expiry
+      # cert-manager should renew the certificate. See
+      # https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.CertificateSpec
+      # Note that renewBefore should be greater than .webhook.lookaheadInterval
+      # since the webhook will check this far in advance that the certificate is
+      # valid.
+      renewBefore: ""
+      # -- Add extra annotations to the Certificate resource.
+      annotations: {}
+
   tolerations: []
   tolerations: []
 
 
   topologySpreadConstraints: []
   topologySpreadConstraints: []

+ 1 - 1
hack/helm.generate.sh

@@ -31,7 +31,7 @@ for i in "${HELM_DIR}"/templates/crds/*.yml; do
   rm "$i.bkp"
   rm "$i.bkp"
   $SEDPRG -i 's/name: kubernetes/name: {{ include "external-secrets.fullname" . }}-webhook/g' "$i"
   $SEDPRG -i 's/name: kubernetes/name: {{ include "external-secrets.fullname" . }}-webhook/g' "$i"
   $SEDPRG -i 's/namespace: default/namespace: {{ .Release.Namespace | quote }}/g' "$i"
   $SEDPRG -i 's/namespace: default/namespace: {{ .Release.Namespace | quote }}/g' "$i"
-  $SEDPRG -i '0,/annotations/!b;//a\    {{- with .Values.crds.annotations }}\n    {{- toYaml . | nindent 4}}\n    {{- end }}' "$i"
+  $SEDPRG -i '0,/annotations/!b;//a\    {{- with .Values.crds.annotations }}\n    {{- toYaml . | nindent 4}}\n    {{- end }}\n    {{- if and .Values.crds.conversion.enabled .Values.webhook.certManager.enabled .Values.webhook.certManager.addInjectorAnnotations }}\n    cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "external-secrets.fullname" . }}-webhook\n    {{- end }}' "$i"
 
 
   $SEDPRG -i '/  conversion:/i{{- if .Values.crds.conversion.enabled }}' "$i"
   $SEDPRG -i '/  conversion:/i{{- if .Values.crds.conversion.enabled }}' "$i"
   echo "{{- end }}" >> "$i"
   echo "{{- end }}" >> "$i"