From 8fa80a570691e38ed1455836505ae5e03a72d2ee Mon Sep 17 00:00:00 2001 From: bluezzydev Date: Wed, 1 Apr 2026 08:24:57 +0200 Subject: [PATCH] [koptan] add cert-manager, webhook, and RBAC resources to helm chart Closes #8 New templates: - certificate.yaml: cert-manager Certificates for webhook (serving-cert) and metrics (metrics-certs), gated on certManager.enabled + respective flags - issuer.yaml: self-signed cert-manager Issuer, gated on certManager.enabled - webhook-service.yaml: Service port 443->9443 for admission webhooks, gated on webhook.enabled - metrics-service.yaml: Service port 8443 for secure metrics, gated on metrics.secure + certManager.enabled - mutatingwebhookconfiguration.yaml: MutatingWebhookConfiguration for goapps, javaapps, slipways, voyages, dotnetapps with cert-manager CA injection annotation, gated on webhook.enabled + certManager.enabled - validatingwebhookconfiguration.yaml: ValidatingWebhookConfiguration for the same resources, same gates - leader-election-role.yaml: namespaced Role for coordination.k8s.io/leases, configmaps, and events (required for --leader-elect) - leader-election-rolebinding.yaml: binds leader election Role to service account - metrics-auth-clusterrole.yaml: ClusterRole + ClusterRoleBinding for tokenreviews and subjectaccessreviews (secure metrics auth), gated on metrics.secure + certManager.enabled - .gitignore: exclude .claude/ directory Updated templates: - deployment.yaml: conditionally expose webhook port 9443 and metrics port 8443, mount webhook-server-cert and metrics-server-cert volumes, and pass --webhook-cert-path / --metrics-cert-path / --metrics-bind-address args. Uses $webhookCerts/$metricsCerts variables to avoid empty volumes block. - values.yaml: add webhook.enabled (false), certManager.enabled (false, with install note), metrics.secure (false), metrics.port (8443) All new resources default to disabled (false) so the chart installs safely on clusters without cert-manager CRDs. Verified on Docker Desktop cluster: - cert-manager Issuer, Certificates, and TLS secrets created successfully - CA bundle injected into both webhook configurations (1504 chars) - Metrics server running on :8443 with TLS - Leader election working (no RBAC errors after Role addition) --- .gitignore | 1 + charts/koptan/templates/certificate.yaml | 38 ++++++ charts/koptan/templates/deployment.yaml | 56 ++++++++- charts/koptan/templates/issuer.yaml | 11 ++ .../templates/leader-election-role.yaml | 39 ++++++ .../leader-election-rolebinding.yaml | 15 +++ .../templates/metrics-auth-clusterrole.yaml | 36 ++++++ charts/koptan/templates/metrics-service.yaml | 17 +++ .../mutatingwebhookconfiguration.yaml | 113 ++++++++++++++++++ .../validatingwebhookconfiguration.yaml | 113 ++++++++++++++++++ charts/koptan/templates/webhook-service.yaml | 16 +++ charts/koptan/values.yaml | 12 ++ 12 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 charts/koptan/templates/certificate.yaml create mode 100644 charts/koptan/templates/issuer.yaml create mode 100644 charts/koptan/templates/leader-election-role.yaml create mode 100644 charts/koptan/templates/leader-election-rolebinding.yaml create mode 100644 charts/koptan/templates/metrics-auth-clusterrole.yaml create mode 100644 charts/koptan/templates/metrics-service.yaml create mode 100644 charts/koptan/templates/mutatingwebhookconfiguration.yaml create mode 100644 charts/koptan/templates/validatingwebhookconfiguration.yaml create mode 100644 charts/koptan/templates/webhook-service.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c5f206 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.claude/ diff --git a/charts/koptan/templates/certificate.yaml b/charts/koptan/templates/certificate.yaml new file mode 100644 index 0000000..93fa552 --- /dev/null +++ b/charts/koptan/templates/certificate.yaml @@ -0,0 +1,38 @@ +{{- if .Values.certManager.enabled }} +{{- if .Values.webhook.enabled }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "koptan.fullname" . }}-serving-cert + namespace: {{ .Release.Namespace }} + labels: + {{- include "koptan.labels" . | nindent 4 }} +spec: + dnsNames: + - {{ include "koptan.fullname" . }}-webhook-service.{{ .Release.Namespace }}.svc + - {{ include "koptan.fullname" . }}-webhook-service.{{ .Release.Namespace }}.svc.cluster.local + issuerRef: + kind: Issuer + name: {{ include "koptan.fullname" . }}-selfsigned-issuer + secretName: webhook-server-cert +{{- end }} +{{- if .Values.metrics.secure }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "koptan.fullname" . }}-metrics-certs + namespace: {{ .Release.Namespace }} + labels: + {{- include "koptan.labels" . | nindent 4 }} +spec: + dnsNames: + - {{ include "koptan.fullname" . }}-metrics-service.{{ .Release.Namespace }}.svc + - {{ include "koptan.fullname" . }}-metrics-service.{{ .Release.Namespace }}.svc.cluster.local + issuerRef: + kind: Issuer + name: {{ include "koptan.fullname" . }}-selfsigned-issuer + secretName: metrics-server-cert +{{- end }} +{{- end }} diff --git a/charts/koptan/templates/deployment.yaml b/charts/koptan/templates/deployment.yaml index b7e4cd5..65af400 100644 --- a/charts/koptan/templates/deployment.yaml +++ b/charts/koptan/templates/deployment.yaml @@ -1,3 +1,5 @@ +{{- $webhookCerts := and .Values.webhook.enabled .Values.certManager.enabled }} +{{- $metricsCerts := and .Values.metrics.secure .Values.certManager.enabled }} apiVersion: apps/v1 kind: Deployment metadata: @@ -28,12 +30,31 @@ spec: args: - --leader-elect - --health-probe-bind-address=:8081 + {{- if .Values.metrics.secure }} + - --metrics-bind-address=:{{ .Values.metrics.port }} + {{- end }} + {{- if $webhookCerts }} + - --webhook-cert-path=/tmp/k8s-webhook-server/serving-certs + {{- end }} + {{- if $metricsCerts }} + - --metrics-cert-path=/tmp/k8s-metrics-server/metrics-certs + {{- end }} image: "{{ .Values.controller.image.repository }}:{{ .Values.controller.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.controller.image.pullPolicy }} ports: - name: http containerPort: 8080 protocol: TCP + {{- if .Values.webhook.enabled }} + - name: webhook-server + containerPort: 9443 + protocol: TCP + {{- end }} + {{- if .Values.metrics.secure }} + - name: metrics + containerPort: {{ .Values.metrics.port }} + protocol: TCP + {{- end }} resources: limits: cpu: 500m @@ -59,4 +80,37 @@ spec: port: 8081 initialDelaySeconds: 5 periodSeconds: 10 - volumes: [] + {{- if or $webhookCerts $metricsCerts }} + volumeMounts: + {{- if $webhookCerts }} + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: webhook-certs + readOnly: true + {{- end }} + {{- if $metricsCerts }} + - mountPath: /tmp/k8s-metrics-server/metrics-certs + name: metrics-certs + readOnly: true + {{- end }} + {{- end }} + {{- if or $webhookCerts $metricsCerts }} + volumes: + {{- if $webhookCerts }} + - name: webhook-certs + secret: + secretName: webhook-server-cert + {{- end }} + {{- if $metricsCerts }} + - name: metrics-certs + secret: + secretName: metrics-server-cert + optional: false + items: + - key: ca.crt + path: ca.crt + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + {{- end }} + {{- end }} diff --git a/charts/koptan/templates/issuer.yaml b/charts/koptan/templates/issuer.yaml new file mode 100644 index 0000000..3d8ff73 --- /dev/null +++ b/charts/koptan/templates/issuer.yaml @@ -0,0 +1,11 @@ +{{- if .Values.certManager.enabled }} +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "koptan.fullname" . }}-selfsigned-issuer + namespace: {{ .Release.Namespace }} + labels: + {{- include "koptan.labels" . | nindent 4 }} +spec: + selfSigned: {} +{{- end }} diff --git a/charts/koptan/templates/leader-election-role.yaml b/charts/koptan/templates/leader-election-role.yaml new file mode 100644 index 0000000..2bd0ebe --- /dev/null +++ b/charts/koptan/templates/leader-election-role.yaml @@ -0,0 +1,39 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "koptan.fullname" . }}-leader-election-role + namespace: {{ .Release.Namespace }} + labels: + {{- include "koptan.labels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/charts/koptan/templates/leader-election-rolebinding.yaml b/charts/koptan/templates/leader-election-rolebinding.yaml new file mode 100644 index 0000000..ffb2009 --- /dev/null +++ b/charts/koptan/templates/leader-election-rolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "koptan.fullname" . }}-leader-election-rolebinding + namespace: {{ .Release.Namespace }} + labels: + {{- include "koptan.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "koptan.fullname" . }}-leader-election-role +subjects: + - kind: ServiceAccount + name: {{ include "koptan.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/charts/koptan/templates/metrics-auth-clusterrole.yaml b/charts/koptan/templates/metrics-auth-clusterrole.yaml new file mode 100644 index 0000000..92f970e --- /dev/null +++ b/charts/koptan/templates/metrics-auth-clusterrole.yaml @@ -0,0 +1,36 @@ +{{- if and .Values.metrics.secure .Values.certManager.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "koptan.fullname" . }}-metrics-auth-role + labels: + {{- include "koptan.labels" . | nindent 4 }} +rules: + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "koptan.fullname" . }}-metrics-auth-rolebinding + labels: + {{- include "koptan.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "koptan.fullname" . }}-metrics-auth-role +subjects: + - kind: ServiceAccount + name: {{ include "koptan.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/koptan/templates/metrics-service.yaml b/charts/koptan/templates/metrics-service.yaml new file mode 100644 index 0000000..f36d662 --- /dev/null +++ b/charts/koptan/templates/metrics-service.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.metrics.secure .Values.certManager.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "koptan.fullname" . }}-metrics-service + namespace: {{ .Release.Namespace }} + labels: + {{- include "koptan.labels" . | nindent 4 }} +spec: + ports: + - name: https + port: {{ .Values.metrics.port }} + protocol: TCP + targetPort: {{ .Values.metrics.port }} + selector: + {{- include "koptan.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/koptan/templates/mutatingwebhookconfiguration.yaml b/charts/koptan/templates/mutatingwebhookconfiguration.yaml new file mode 100644 index 0000000..ca9989b --- /dev/null +++ b/charts/koptan/templates/mutatingwebhookconfiguration.yaml @@ -0,0 +1,113 @@ +{{- if and .Values.webhook.enabled .Values.certManager.enabled }} +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ include "koptan.fullname" . }}-mutating-webhook-configuration + labels: + {{- include "koptan.labels" . | nindent 4 }} + {{- if .Values.certManager.enabled }} + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "koptan.fullname" . }}-serving-cert + {{- end }} +webhooks: + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /mutate-koptan-felukka-sh-v1alpha-goapp + failurePolicy: Fail + name: mgoapp-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - goapps + sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /mutate-koptan-felukka-sh-v1alpha-javaapp + failurePolicy: Fail + name: mjavaapp-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - javaapps + sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /mutate-koptan-felukka-sh-v1alpha-slipway + failurePolicy: Fail + name: mslipway-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - slipways + sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /mutate-koptan-felukka-sh-v1alpha-voyage + failurePolicy: Fail + name: mvoyage-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - voyages + sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /mutate-koptan-felukka-sh-v1alpha-dotnetapp + failurePolicy: Fail + name: mdotnetapp-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - dotnetapps + sideEffects: None +{{- end }} diff --git a/charts/koptan/templates/validatingwebhookconfiguration.yaml b/charts/koptan/templates/validatingwebhookconfiguration.yaml new file mode 100644 index 0000000..69e80d2 --- /dev/null +++ b/charts/koptan/templates/validatingwebhookconfiguration.yaml @@ -0,0 +1,113 @@ +{{- if and .Values.webhook.enabled .Values.certManager.enabled }} +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: {{ include "koptan.fullname" . }}-validating-webhook-configuration + labels: + {{- include "koptan.labels" . | nindent 4 }} + {{- if .Values.certManager.enabled }} + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "koptan.fullname" . }}-serving-cert + {{- end }} +webhooks: + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-koptan-felukka-sh-v1alpha-goapp + failurePolicy: Fail + name: vgoapp-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - goapps + sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-koptan-felukka-sh-v1alpha-javaapp + failurePolicy: Fail + name: vjavaapp-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - javaapps + sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-koptan-felukka-sh-v1alpha-slipway + failurePolicy: Fail + name: vslipway-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - slipways + sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-koptan-felukka-sh-v1alpha-voyage + failurePolicy: Fail + name: vvoyage-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - voyages + sideEffects: None + - admissionReviewVersions: + - v1 + clientConfig: + service: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-koptan-felukka-sh-v1alpha-dotnetapp + failurePolicy: Fail + name: vdotnetapp-v1alpha.kb.io + rules: + - apiGroups: + - koptan.felukka.sh + apiVersions: + - v1alpha + operations: + - CREATE + - UPDATE + resources: + - dotnetapps + sideEffects: None +{{- end }} diff --git a/charts/koptan/templates/webhook-service.yaml b/charts/koptan/templates/webhook-service.yaml new file mode 100644 index 0000000..6d1c41e --- /dev/null +++ b/charts/koptan/templates/webhook-service.yaml @@ -0,0 +1,16 @@ +{{- if .Values.webhook.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "koptan.fullname" . }}-webhook-service + namespace: {{ .Release.Namespace }} + labels: + {{- include "koptan.labels" . | nindent 4 }} +spec: + ports: + - port: 443 + protocol: TCP + targetPort: 9443 + selector: + {{- include "koptan.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/koptan/values.yaml b/charts/koptan/values.yaml index 9783f83..bb1744f 100644 --- a/charts/koptan/values.yaml +++ b/charts/koptan/values.yaml @@ -60,3 +60,15 @@ volumeMounts: [] nodeSelector: {} tolerations: [] affinity: {} + +webhook: + enabled: false + +certManager: + # Requires cert-manager CRDs to be installed in the cluster. + # See https://cert-manager.io/docs/installation/ + enabled: false + +metrics: + secure: false + port: 8443