Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 63 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,70 @@ CRDs are located in `chart/crds/` and are installed automatically. The API group

### TLS Certificates (cert-manager)

The chart creates a self-signed cert-manager `Issuer` and two `Certificate` resources automatically:
The chart manages two cert-manager `Certificate` resources:

- **Serving certificate** — TLS for the webhook endpoint (stored in Secret `webhook-server-certificate`)
- **Metrics certificate** — TLS for the metrics endpoint (stored in Secret `metrics-server-cert`)
- **Serving certificate** — TLS for the webhook endpoint (Secret `webhook-server-certificate`). Only rendered when `webhooks.enabled=true`.
- **Metrics certificate** — TLS for the metrics endpoint (Secret `metrics-server-cert`). Always rendered.

Both certificates use the built-in self-signed issuer deployed by the chart. No external issuer is required. These resources are not configurable via `values.yaml`.
#### Self-signed Issuer

| Parameter | Description | Default |
|-----------|-------------|---------|
| `selfSignedIssuer.enabled` | Create a self-signed cert-manager `Issuer` (named `<fullname>-selfsigned-issuer`) and use it as the default issuer for both certificates. Set to `false` when bringing your own issuer. | `true` |

When `selfSignedIssuer.enabled=true` and no explicit `issuerRef` is configured on a certificate, the chart automatically points that certificate at the built-in self-signed issuer. When `selfSignedIssuer.enabled=false`, an `issuerRef` **must** be provided for each certificate that is rendered, otherwise the chart will fail with a descriptive error.

#### Metrics Certificate (`metricsCert`)

| Parameter | Description | Default |
|-----------|-------------|---------|
| `metricsCert.issuerRef` | cert-manager issuer reference. Overrides `selfSignedIssuer` for this certificate. | self-signed issuer |
| `metricsCert.issuerRef.kind` | Issuer kind (`Issuer` or `ClusterIssuer`) | — |
| `metricsCert.issuerRef.name` | Issuer name | — |
| `metricsCert.issuerRef.group` | Issuer API group (optional) | — |
| `metricsCert.duration` | Certificate validity duration (e.g. `2160h0m0s`) | cert-manager default |
| `metricsCert.renewBefore` | How long before expiry cert-manager renews the certificate (e.g. `360h0m0s`) | cert-manager default |
| `metricsCert.privateKey.algorithm` | Private key algorithm (`RSA`, `ECDSA`, `Ed25519`) | cert-manager default |
| `metricsCert.privateKey.size` | Private key size in bits | cert-manager default |
| `metricsCert.privateKey.encoding` | Private key encoding (`PKCS1`, `PKCS8`) | cert-manager default |
| `metricsCert.privateKey.rotationPolicy` | Key rotation policy (`Never`, `Always`) | cert-manager default |
| `metricsCert.subject` | X.509 subject fields (e.g. `organizations`, `countries`) | — |

#### Serving Certificate (`servingCert`)

| Parameter | Description | Default |
|-----------|-------------|---------|
| `servingCert.issuerRef` | cert-manager issuer reference. Overrides `selfSignedIssuer` for this certificate. | self-signed issuer |
| `servingCert.issuerRef.kind` | Issuer kind (`Issuer` or `ClusterIssuer`) | — |
| `servingCert.issuerRef.name` | Issuer name | — |
| `servingCert.issuerRef.group` | Issuer API group (optional) | — |
| `servingCert.duration` | Certificate validity duration (e.g. `2160h0m0s`) | cert-manager default |
| `servingCert.renewBefore` | How long before expiry cert-manager renews the certificate (e.g. `360h0m0s`) | cert-manager default |
| `servingCert.privateKey.algorithm` | Private key algorithm (`RSA`, `ECDSA`, `Ed25519`) | cert-manager default |
| `servingCert.privateKey.size` | Private key size in bits | cert-manager default |
| `servingCert.privateKey.encoding` | Private key encoding (`PKCS1`, `PKCS8`) | cert-manager default |
| `servingCert.privateKey.rotationPolicy` | Key rotation policy (`Never`, `Always`) | cert-manager default |
| `servingCert.subject` | X.509 subject fields (e.g. `organizations`, `countries`) | — |
| `servingCert.usages` | Key usages (e.g. `server auth`, `client auth`) | — |

#### Example: Bring your own ClusterIssuer

```yaml
selfSignedIssuer:
enabled: false

metricsCert:
issuerRef:
kind: ClusterIssuer
name: letsencrypt-prod
duration: 8760h0m0s
renewBefore: 720h0m0s

servingCert:
issuerRef:
kind: ClusterIssuer
name: letsencrypt-prod
```

### Other

Expand Down Expand Up @@ -160,7 +218,7 @@ The chart deploys:
1. **Deployment** — The controller manager pod running `/manager` with webhook and health probe endpoints
2. **Services** — A metrics service (port 8443) and a webhook service (port 443 → 9443)
3. **RBAC** — ClusterRoles and bindings for the manager, leader election, metrics auth, and per-CRD admin/editor/viewer roles
4. **Certificates** — A self-signed Issuer, a serving certificate for the webhook endpoint, and a metrics certificate (all via cert-manager)
4. **Certificates** — An optional self-signed `Issuer` (controlled by `selfSignedIssuer.enabled`), a serving certificate for the webhook endpoint (when `webhooks.enabled=true`), and a metrics certificate all via cert-manager. Both certificates fall back to the built-in self-signed issuer unless a custom `issuerRef` is configured.
5. **ValidatingWebhookConfiguration** — Admission webhooks validating `Organization` and `Repository` resources on CREATE/UPDATE
6. **NetworkPolicy** — Allows webhook traffic from `kube-system` namespace to the controller on port 9443
7. **ServiceMonitor** — Prometheus ServiceMonitor for scraping `/metrics` from the controller
Expand Down
7 changes: 7 additions & 0 deletions templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ namespaceSelector:
{{- end }}
{{- end }}

{{/*
Name of the internal self-signed cert-manager Issuer.
*/}}
{{- define "git-hubby.selfSignedIssuerName" -}}
{{- printf "%s-selfsigned-issuer" (include "git-hubby.fullname" .) }}
{{- end }}

{{/*
WATCH_NAMESPACE value: joins watchedNamespaces list with commas.
*/}}
Expand Down
24 changes: 22 additions & 2 deletions templates/metrics-certs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,27 @@ spec:
}}.svc'
- '{{ include "git-hubby.fullname" . }}-controller-manager-metrics-service.{{ .Release.Namespace
}}.svc.{{ .Values.kubernetesClusterDomain }}'
secretName: metrics-server-cert
{{- with .Values.metricsCert.duration }}
duration: {{ . }}
{{- end }}
issuerRef:
{{- if .Values.metricsCert.issuerRef }}
{{- toYaml .Values.metricsCert.issuerRef | nindent 4 }}
{{- else if .Values.selfSignedIssuer.enabled }}
kind: Issuer
name: '{{ include "git-hubby.fullname" . }}-selfsigned-issuer'
secretName: metrics-server-cert
name: {{ include "git-hubby.selfSignedIssuerName" . }}
{{- else }}
{{- fail "metricsCert.issuerRef must be set when selfSignedIssuer.enabled is false" }}
{{- end }}
{{- with .Values.metricsCert.privateKey }}
privateKey:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.metricsCert.renewBefore }}
renewBefore: {{ . }}
{{- end }}
{{- with .Values.metricsCert.subject }}
subject:
{{- toYaml . | nindent 4 }}
{{- end }}
4 changes: 2 additions & 2 deletions templates/selfsigned-issuer.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{{- if .Values.webhooks.enabled }}
{{- if .Values.selfSignedIssuer.enabled }}
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: {{ include "git-hubby.fullname" . }}-selfsigned-issuer
name: {{ include "git-hubby.selfSignedIssuerName" . }}
labels:
{{- include "git-hubby.labels" . | nindent 4 }}
spec:
Expand Down
7 changes: 7 additions & 0 deletions templates/serving-cert.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ spec:
duration: {{ . }}
{{- end }}
issuerRef:
{{- if .Values.servingCert.issuerRef }}
{{- toYaml .Values.servingCert.issuerRef | nindent 4 }}
{{- else if .Values.selfSignedIssuer.enabled }}
kind: Issuer
name: {{ include "git-hubby.selfSignedIssuerName" . }}
{{- else }}
{{- fail "servingCert.issuerRef must be set when selfSignedIssuer.enabled is false" }}
{{- end }}
{{- with .Values.servingCert.privateKey }}
privateKey:
{{- toYaml . | nindent 4 }}
Expand Down
147 changes: 147 additions & 0 deletions tests/metrics_cert_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
suite: metrics-cert
templates:
- metrics-certs.yaml
release:
name: test-release
namespace: test-ns
tests:
- it: should render a Certificate resource
asserts:
- isKind:
of: Certificate
- equal:
path: apiVersion
value: cert-manager.io/v1
- equal:
path: metadata.name
value: test-release-git-hubby-metrics-certs
- equal:
path: spec.secretName
value: metrics-server-cert

- it: should set correct DNS names
asserts:
- contains:
path: spec.dnsNames
content: test-release-git-hubby-controller-manager-metrics-service.test-ns.svc
- contains:
path: spec.dnsNames
content: test-release-git-hubby-controller-manager-metrics-service.test-ns.svc.cluster.local

- it: should include chart labels
asserts:
- isSubset:
path: metadata.labels
content:
app.kubernetes.io/name: git-hubby
app.kubernetes.io/instance: test-release

- it: should use the internal self-signed issuer by default
asserts:
- equal:
path: spec.issuerRef.kind
value: Issuer
- equal:
path: spec.issuerRef.name
value: test-release-git-hubby-selfsigned-issuer

- it: should use a custom issuerRef when configured
set:
metricsCert:
issuerRef:
kind: ClusterIssuer
name: letsencrypt-prod
asserts:
- equal:
path: spec.issuerRef.kind
value: ClusterIssuer
- equal:
path: spec.issuerRef.name
value: letsencrypt-prod

- it: should use custom issuerRef even when selfSignedIssuer is enabled
set:
selfSignedIssuer.enabled: true
metricsCert:
issuerRef:
kind: ClusterIssuer
name: my-issuer
asserts:
- equal:
path: spec.issuerRef.name
value: my-issuer

- it: should use custom issuerRef when selfSignedIssuer is disabled
set:
selfSignedIssuer.enabled: false
metricsCert:
issuerRef:
kind: ClusterIssuer
name: letsencrypt-prod
asserts:
- equal:
path: spec.issuerRef.kind
value: ClusterIssuer
- equal:
path: spec.issuerRef.name
value: letsencrypt-prod

- it: should always render regardless of webhooks.enabled
set:
webhooks.enabled: false
asserts:
- hasDocuments:
count: 1

- it: should set optional duration
set:
metricsCert.duration: "8760h0m0s"
asserts:
- equal:
path: spec.duration
value: "8760h0m0s"

- it: should set optional renewBefore
set:
metricsCert.renewBefore: "720h0m0s"
asserts:
- equal:
path: spec.renewBefore
value: "720h0m0s"

- it: should set optional privateKey
set:
metricsCert:
privateKey:
algorithm: ECDSA
size: 256
asserts:
- equal:
path: spec.privateKey.algorithm
value: ECDSA
- equal:
path: spec.privateKey.size
value: 256

- it: should set optional subject
set:
metricsCert:
subject:
organizations:
- My Org
asserts:
- equal:
path: spec.subject.organizations[0]
value: My Org

- it: should not include optional fields when not set
asserts:
- notExists:
path: spec.duration
- notExists:
path: spec.renewBefore
- notExists:
path: spec.privateKey
- notExists:
path: spec.subject

24 changes: 23 additions & 1 deletion tests/selfsigned_issuer_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ release:
name: test-release
namespace: test-ns
tests:
- it: should render an Issuer resource
- it: should render an Issuer resource when selfSignedIssuer.enabled is true
asserts:
- isKind:
of: Issuer
Expand All @@ -19,3 +19,25 @@ tests:
path: spec.selfSigned
value: {}

- it: should include chart labels
asserts:
- isSubset:
path: metadata.labels
content:
app.kubernetes.io/name: git-hubby
app.kubernetes.io/instance: test-release

- it: should not render when selfSignedIssuer.enabled is false
set:
selfSignedIssuer.enabled: false
asserts:
- hasDocuments:
count: 0

- it: should include release name in issuer name to prevent collisions
release:
name: other-release
asserts:
- equal:
path: metadata.name
value: other-release-git-hubby-selfsigned-issuer
Loading