connaisseur
connaisseur copied to clipboard
CertManager integration for the AdmissionController certificate
Describe the feature The Kubernetes validating and mutating admission webhooks require a self signed certificate. Until now the certificate is generated automatically when the helm chart is installed but the lifecycle has to be managed manually.
In case the cluster have already installed the cert-manager utility, the certificate management can be delegated to it.
Cert manager can that inject the caBundle
inside the MutatingWebhookConfiguration
.
Optional: Is your feature request related to a problem? Please describe. <A clear and concise description of what the problem is.>
Optional: Implementation ideas
certificate_webhook-conf.yaml
file:
{{- $k8sMinor := (include "k8s-version-minor" .) -}}
{{- $altNames := list -}}
{{- $altNames = append $altNames (printf "%s-svc" .Chart.Name) -}}
{{- $altNames = append $altNames (printf "%s-svc.%s" .Chart.Name .Release.Namespace) -}}
{{- $altNames = append $altNames (printf "%s-svc.%s.svc" .Chart.Name .Release.Namespace) -}}
{{- $altNames = append $altNames (printf "%s-svc.%s.svc.cluster.local" .Chart.Name .Release.Namespace) -}}
{{- $certs := genSelfSignedCert (printf "%s-svc.%s.svc" .Chart.Name .Release.Namespace) nil $altNames 36500 -}}
{{- if .Values.admissionWebhook.certManager.useCertManager }}
{{- if .Values.admissionWebhook.certManager.newCertificate }}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ .Chart.Name }}-certificate
namespace: {{ .Release.Namespace }}
spec:
commonName: "{{ .Chart.Name }}-svc.{{ .Release.Namespace }}.svc"
dnsNames:
- {{ .Chart.Name }}-svc.{{ .Release.Namespace }}.svc.cluster.local
- {{ .Chart.Name }}-svc.{{ .Release.Namespace }}.svc
issuerRef:
kind: {{ .Values.admissionWebhook.certManager.newCertificate.issuerRef.kind }}
name: {{ .Values.admissionWebhook.certManager.newCertificate.issuerRef.name }}
secretName: {{ .Chart.Name }}-tls
{{- end }}
{{- else }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ .Chart.Name }}-tls
namespace: {{ .Release.Namespace }}
labels:
{{- include "helm.labels" . | nindent 4 }}
type: Opaque
data:
tls.crt: {{ default ($certs.Cert | b64enc) (include "getInstalledTLSCert" .) }}
tls.key: {{ default ($certs.Key | b64enc) (include "getInstalledTLSKey" .) }}
{{- end}}
---
{{ if lt ($k8sMinor | int) 17 }}
apiVersion: admissionregistration.k8s.io/v1beta1
{{ else }}
apiVersion: admissionregistration.k8s.io/v1
{{ end }}
kind: MutatingWebhookConfiguration
metadata:
name: {{ .Chart.Name }}-webhook
labels:
{{- include "helm.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-delete
"helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed
{{- if .Values.admissionWebhook.certManager.useCertManager }}
{{- if .Values.admissionWebhook.certManager.existingCertificate }}
cert-manager.io/inject-ca-from: {{ .Values.admissionWebhook.certManager.existingCertificate.namespace }}/{{ .Values.admissionWebhook.certManager.existingCertificate.name }}
{{- else }} # new certificate
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ .Chart.Name }}-certificate
{{- end }}
{{- end }}
webhooks:
- name: {{ .Chart.Name }}-svc.{{ .Release.Namespace }}.svc
failurePolicy: Ignore
reinvocationPolicy: {{ .Values.deployment.reinvocationPolicy | default "Never" }}
clientConfig:
service:
name: {{ .Chart.Name }}-svc
namespace: {{ .Release.Namespace }}
path: /mutate
{{- if not .Values.admissionWebhook.certManager.useCertManager }}
caBundle: {{ default ($certs.Cert | b64enc) (include "getInstalledTLSCert" .) }}
{{- end }}
rules: []
sideEffects: None
{{- if lt ($k8sMinor | int) 17 }}
admissionReviewVersions: ["v1beta1"]
{{- else }}
admissionReviewVersions: ["v1"]
{{- end }}
---
{{ if lt ($k8sMinor | int) 17 -}}
apiVersion: admissionregistration.k8s.io/v1beta1
{{ else -}}
apiVersion: admissionregistration.k8s.io/v1
{{ end -}}
kind: MutatingWebhookConfiguration
metadata:
name: {{ .Chart.Name }}-webhook
labels:
{{- include "helm.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-install, post-upgrade, post-rollback
{{- if .Values.admissionWebhook.certManager.useCertManager }}
{{- if .Values.admissionWebhook.certManager.existingCertificate }}
cert-manager.io/inject-ca-from: {{ .Values.admissionWebhook.certManager.existingCertificate.namespace }}/{{ .Values.admissionWebhook.certManager.existingCertificate.name }}
{{- else }} # new certificate
cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ .Chart.Name }}-certificate
{{- end }}
{{- end }}
webhooks:
- name: {{ .Chart.Name }}-svc.{{ .Release.Namespace }}.svc
failurePolicy: {{ .Values.deployment.failurePolicy | default "Fail" }}
reinvocationPolicy: {{ .Values.deployment.reinvocationPolicy | default "Never" }}
clientConfig:
service:
name: {{ .Chart.Name }}-svc
namespace: {{ .Release.Namespace }}
path: /mutate
{{- if not .Values.admissionWebhook.certManager.useCertManager }}
caBundle: {{ default ($certs.Cert | b64enc) (include "getInstalledTLSCert" .) }}
{{- end }}
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: ["*"]
apiVersions: ["*"]
{{- if .Values.automaticChildApproval }}
{{- if .Values.automaticChildApproval.enabled }}
resources: ["pods", "deployments", "replicationcontrollers", "replicasets", "daemonsets", "statefulsets", "jobs", "cronjobs"]
{{- else }}
resources: ["pods"]
{{- end }}
{{- else }}
resources: ["pods", "deployments", "replicationcontrollers", "replicasets", "daemonsets", "statefulsets", "jobs", "cronjobs"]
{{- end }}
sideEffects: None
{{- if gt ($k8sMinor | int) 13 }}
timeoutSeconds: 30
{{- end }}
{{- if lt ($k8sMinor | int) 17 }}
admissionReviewVersions: ["v1beta1"]
{{- else }}
admissionReviewVersions: ["v1"]
{{- end }}
{{- if .Values.namespacedValidation }}
{{- if .Values.namespacedValidation.enabled }}
namespaceSelector:
matchExpressions:
- key: securesystemsengineering.connaisseur/webhook
{{- if not .Values.namespacedValidation.mode}}
operator: NotIn
values:
- ignore
{{- else if eq .Values.namespacedValidation.mode "ignore"}}
operator: NotIn
values:
- ignore
{{- else if eq .Values.namespacedValidation.mode "validate"}}
operator: In
values:
- validate
{{- end }}
{{- end }}
{{- end }}
Example of values.yaml
structure:
admissionWebhook:
certManager:
useCertManager: true
# existingCertificate:
# name: validating-webhook-cert
# namespace: kube-system
newCertificate:
issuerRef:
kind: ClusterIssuer
name: ca-issuer
This requires and already installed CA. This is an example of a self signed ca created with cert manager:
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: root-ca-certificate
namespace: cert-manager
spec:
isCA: true
commonName: connaisseur.test.com
secretName: root-ca-secret
privateKey:
algorithm: ECDSA
size: 256
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: ca-issuer
spec:
ca:
secretName: root-ca-secret
Optional: Additional context <Add any other context or screenshots about the feature request here.>
Let me know if you think that this can be useful so that I will create a pull request. Thank you.
@andreee94 I think this is a great idea that somehow relates to the earlier issue #225 to allow specifying your own cert. I am not a pro in certManager, but would think that externalizing the management of TLS certs would be a great feature. We'd probably have to make sure that cert renewal restarts Connaisseur and does not break the install (we have experienced issues in the past), but I'd be up for implementing this. Would have to understand the details a bit better though... @phbelitz might have more feedback on this.
thanks for the awesome idea :pray: