Skip to content

Commit 1beac7b

Browse files
authored
feat!: restructure config/secret handling, harden chart, and add CI (v6.0.0) (#78)
* feat(chart)!: split config into ConfigMap + Secret and harden defaults BREAKING CHANGE: `secret.enabled` and `secret.useExisting` are removed. Non-sensitive settings now always render into a ConfigMap and sensitive ones (admin password/token, cookie signing key, S3 keys, OAuth2 client secret) into a Secret, both mounted into the pod. Use `secret.existingSecret` to bring your own Secret (e.g. SOPS-encrypted). - Move the cookie signing key into the Secret; allow sourcing it from an existing Secret via kellnr.registry.cookieSigningKeySecretRef (#67) - Mount ConfigMap and Secret simultaneously; add extraEnvVars / extraEnvVarsCM / extraEnvVarsSecret escape hatches (#68, #61) - Add startup/liveness/readiness probes against /api/v1/health - Disable ServiceAccount token automount by default - Expose registry download* and s3 *Timeout settings - Add values.schema.json and a `helm test` connection hook - Bump chart to 6.0.0 and document the upgrade * ci: validate charts on PRs and modernize the release workflow - Add lint-test workflow running chart-testing lint plus a kind-based install that exercises the new `helm test` hook on pull requests - Add .github/ct.yaml (target-branch, chart-dirs, skip maintainer check) - Scope release triggers to main, apply least-privilege per-job permissions, and add a concurrency group - Bump chart-releaser-action v1.2.1->v1.7.0, create-pull-request v6->v8, setup-helm v4->v5, checkout v4->v6 * ci: add yamllint config matching the chart comment style ct lint runs yamllint, whose comments rule requires two spaces before inline comments; the chart uses the `value # default` one-space style throughout. Add a yamllint config (relaxed comments rule) and point ct at it via lint-conf. * docs: document the v6.0.0 ConfigMap/Secret split in the README Add a "Configuration storage (ConfigMap and Secret)" section covering secret.existingSecret and pointing to the extra-env settings. * docs: link the v6.0.0 blog post from the upgrade notes
1 parent f0e3ebc commit 1beac7b

13 files changed

Lines changed: 542 additions & 60 deletions

File tree

.github/ct.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Configuration for helm/chart-testing (ct), used by the lint-test workflow.
2+
target-branch: main
3+
chart-dirs:
4+
- charts
5+
# The chart intentionally ships without a maintainers field; don't fail on it.
6+
validate-maintainers: false
7+
# yamllint config matching the chart's inline-comment style.
8+
lint-conf: .github/lintconf.yaml

.github/lintconf.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
# yamllint configuration used by chart-testing (ct) via .github/ct.yaml.
3+
# Based on chart-testing's default, with the inline-comment spacing relaxed to
4+
# one space to match the chart's `value # default` documentation style.
5+
rules:
6+
braces:
7+
level: error
8+
min-spaces-inside: 0
9+
max-spaces-inside: 0
10+
brackets:
11+
level: error
12+
min-spaces-inside: 0
13+
max-spaces-inside: 0
14+
colons:
15+
level: error
16+
max-spaces-before: 0
17+
max-spaces-after: 1
18+
commas:
19+
level: error
20+
max-spaces-before: 0
21+
min-spaces-after: 1
22+
max-spaces-after: 1
23+
comments:
24+
level: error
25+
require-starting-space: true
26+
min-spaces-from-content: 1
27+
comments-indentation: disable
28+
document-end: disable
29+
document-start: disable
30+
empty-lines:
31+
level: error
32+
max: 2
33+
max-start: 0
34+
max-end: 0
35+
hyphens:
36+
level: error
37+
max-spaces-after: 1
38+
indentation:
39+
level: error
40+
spaces: consistent
41+
indent-sequences: true
42+
check-multi-line-strings: false
43+
key-duplicates: enable
44+
line-length: disable
45+
new-line-at-end-of-file: enable
46+
new-lines:
47+
type: unix
48+
trailing-spaces: enable
49+
truthy: disable

.github/workflows/ci.yaml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,31 @@ name: Release Charts
22

33
on:
44
push:
5-
pull_request:
65
branches:
76
- main
87
repository_dispatch:
98
types:
109
- kellnr_release
1110

11+
# Least-privilege by default; jobs elevate as needed.
1212
permissions:
13-
contents: write
14-
pull-requests: write
13+
contents: read
14+
15+
concurrency:
16+
group: ${{ github.workflow }}-${{ github.ref }}
17+
cancel-in-progress: false
1518

1619
jobs:
1720
update-chart-on-dispatch:
1821
name: Update chart versions on kellnr release
1922
if: github.event_name == 'repository_dispatch' && github.repository_owner == 'kellnr'
2023
runs-on: ubuntu-latest
24+
permissions:
25+
contents: write
26+
pull-requests: write
2127
steps:
2228
- name: Checkout
23-
uses: actions/checkout@v4
29+
uses: actions/checkout@v6
2430

2531
- name: Extract version
2632
id: v
@@ -62,7 +68,7 @@ jobs:
6268
echo "Bumped chart version $CURRENT_CHART_VERSION -> $NEXT_CHART_VERSION"
6369
6470
- name: Create Pull Request
65-
uses: peter-evans/create-pull-request@v6
71+
uses: peter-evans/create-pull-request@v8
6672
with:
6773
token: ${{ secrets.GITHUB_TOKEN }}
6874
branch: chore/bump-kellnr-${{ steps.v.outputs.version }}
@@ -82,9 +88,11 @@ jobs:
8288
release:
8389
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository_owner == 'kellnr'
8490
runs-on: ubuntu-latest
91+
permissions:
92+
contents: write
8593
steps:
8694
- name: Checkout
87-
uses: actions/checkout@v4
95+
uses: actions/checkout@v6
8896
with:
8997
fetch-depth: 0
9098

@@ -94,11 +102,11 @@ jobs:
94102
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
95103
96104
- name: Install Helm
97-
uses: azure/setup-helm@v4
105+
uses: azure/setup-helm@v5
98106
with:
99107
version: v3.16.3
100108

101109
- name: Run chart-releaser
102-
uses: helm/chart-releaser-action@v1.2.1
110+
uses: helm/chart-releaser-action@v1.7.0
103111
env:
104112
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

.github/workflows/lint-test.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Lint and Test Chart
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
lint-test:
14+
name: Lint and install
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v6
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Set up Helm
23+
uses: azure/setup-helm@v5
24+
with:
25+
version: v3.16.3
26+
27+
- name: Set up Python
28+
uses: actions/setup-python@v5
29+
with:
30+
python-version: "3.x"
31+
check-latest: true
32+
33+
- name: Set up chart-testing
34+
uses: helm/chart-testing-action@v2.8.0
35+
36+
- name: Run chart-testing (list-changed)
37+
id: list-changed
38+
run: |
39+
changed="$(ct list-changed --config .github/ct.yaml)"
40+
if [ -n "$changed" ]; then
41+
echo "changed=true" >> "$GITHUB_OUTPUT"
42+
fi
43+
44+
- name: Run chart-testing (lint)
45+
run: ct lint --config .github/ct.yaml
46+
47+
- name: Create kind cluster
48+
if: steps.list-changed.outputs.changed == 'true'
49+
uses: helm/kind-action@v1.14.0
50+
51+
- name: Run chart-testing (install)
52+
if: steps.list-changed.outputs.changed == 'true'
53+
run: ct install --config .github/ct.yaml --helm-extra-args "--timeout 600s"

README.md

Lines changed: 109 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,60 @@ helm upgrade kellnr kellnr/kellnr
5656

5757
### Upgrade Notes
5858

59+
#### Chart version 6.0.0
60+
61+
**Breaking change: configuration is now split into a ConfigMap and a Secret.**
62+
63+
> For background on what changed and why, see the blog post:
64+
> [A Safer Kellnr Helm Chart: Splitting Config and Secrets](https://kellnr.io/blog/helm-chart-v6).
65+
66+
Previously, `secret.enabled` switched the *entire* configuration between a ConfigMap
67+
(default) and a Secret. The chart now always renders **both**: non-sensitive settings
68+
go into a ConfigMap and sensitive ones (admin password and token, cookie signing key,
69+
S3 keys, OAuth2 client secret) go into a Secret. Both are mounted into the pod, so
70+
sensitive values are no longer stored in a plaintext ConfigMap.
71+
72+
Migration:
73+
74+
- `secret.enabled` and `secret.useExisting` have been **removed**.
75+
- If you used `secret.enabled: true` only to keep config out of a ConfigMap, no
76+
action is needed — sensitive values now live in a Secret automatically.
77+
- If you used `secret.useExisting: true` with a self-managed (e.g. SOPS-encrypted)
78+
Secret, set `secret.existingSecret: <your-secret-name>` instead. The chart then
79+
mounts your Secret in place of its own. Note that the Secret only needs to carry
80+
the sensitive `KELLNR_*` variables; non-sensitive ones come from the ConfigMap.
81+
- New escape hatches: `extraEnvVars` (raw `EnvVar` list), `extraEnvVarsCM` and
82+
`extraEnvVarsSecret` (names of existing ConfigMaps/Secrets) let you inject arbitrary
83+
environment variables or mount your own config/secret alongside the chart's.
84+
- The cookie signing key can now be sourced from an existing Secret via
85+
`kellnr.registry.cookieSigningKeySecretRef`. See [Cookie signing key](#cookie-signing-key).
86+
87+
Other notable changes in this release:
88+
89+
- **Health probes are now enabled by default**, hitting Kellnr's `/api/v1/health`
90+
endpoint (startup, liveness, readiness). Tune or disable them via the
91+
`startupProbe`/`livenessProbe`/`readinessProbe` values.
92+
- **The ServiceAccount token is no longer mounted** (`serviceAccount.automountServiceAccountToken: false`),
93+
since Kellnr does not use the Kubernetes API. Set it back to `true` if you rely on it.
94+
- New tuning settings exposed: `kellnr.registry.downloadTimeoutSeconds`,
95+
`downloadMaxConcurrent`, `downloadCounterFlushSeconds`, and
96+
`kellnr.s3.connectTimeoutSeconds`/`requestTimeoutSeconds`.
97+
- A `values.schema.json` now validates values at install/template time (e.g. it
98+
requires `kellnr.origin.hostname`).
99+
59100
#### Chart version 5.0.0
60101

61102
The default data directory changed from `/opt/kdata` to `/var/lib/kellnr` to align with the new Kellnr Docker image defaults. If you're upgrading an existing installation and were using the default data directory, explicitly set `kellnr.registry.dataDir=/opt/kdata` in your values to maintain compatibility with your existing persistent volume.
62103

104+
## Testing
105+
106+
After installing or upgrading, you can run the chart's built-in smoke test, which
107+
checks that Kellnr's `/api/v1/health` endpoint is reachable through its Service:
108+
109+
```bash
110+
helm test kellnr
111+
```
112+
63113
## Configuration
64114

65115
All settings can be set with the `--set name=value` flag on `helm install`. Some settings are required and have to be provided other are recommended for security reasons.
@@ -68,28 +118,79 @@ All settings can be set with the `--set name=value` flag on `helm install`. Some
68118

69119
Check the [documentation](https://kellnr.io/documentation) and the [values.yaml](./charts/kellnr/values.yaml) for possible configuration values.
70120

121+
#### Configuration storage (ConfigMap and Secret)
122+
123+
The chart renders Kellnr's configuration into two objects, both mounted into the pod
124+
via `envFrom`:
125+
126+
- a **ConfigMap** (`configMap.name`) holding the non-sensitive settings, and
127+
- a **Secret** (`secret.name`) holding the sensitive ones: the admin password and
128+
token, the cookie signing key, the S3 keys, and the OAuth2 client secret.
129+
130+
| Setting | Required | Description | Default |
131+
|-----------------------|----------|---------------------------------------------------------------------------------------------------|-----------------|
132+
| configMap.name | No | Name of the ConfigMap holding non-sensitive configuration. | "kellnr-config" |
133+
| secret.name | No | Name of the Secret holding sensitive configuration. | "kellnr-secret" |
134+
| secret.existingSecret | No | Use an existing Secret (e.g. SOPS-managed) instead of creating one. The chart then mounts yours. | "" |
135+
136+
To add your own variables or mount additional ConfigMaps/Secrets, see
137+
[Extra environment variables](#extra-environment-variables).
138+
71139
#### Cookie signing key
72140

73-
Kellnr uses a cookie signing key to sign its session cookie.
141+
Kellnr uses a cookie signing key to sign its session cookie. Setting it is recommended
142+
for multi-replica setups so every replica shares the same key (otherwise users are
143+
logged out when routed to a different replica). The key is sensitive and is stored in
144+
the chart-managed Secret.
74145

75-
| Setting | Required | Description | Default |
76-
|----------------------------------|----------|-------------------------------------------------------------------------------------------------------------------|---------|
77-
| kellnr.registry.cookieSigningKey | No | Cookie signing key used for `KELLNR_REGISTRY__COOKIE_SIGNING_KEY`. Must be at least 64 characters. | "" |
146+
| Setting | Required | Description | Default |
147+
|-----------------------------------------------|----------|------------------------------------------------------------------------------------------------------|--------------------|
148+
| kellnr.registry.cookieSigningKey | No | Inline cookie signing key for `KELLNR_REGISTRY__COOKIE_SIGNING_KEY`. Must be at least 64 characters. | "" |
149+
| kellnr.registry.cookieSigningKeySecretRef.name | No | Name of an existing Secret holding the key. Takes precedence over the inline value when set. | "" |
150+
| kellnr.registry.cookieSigningKeySecretRef.key | No | Key within that Secret. | "cookieSigningKey" |
78151

79152
Notes:
80153

81-
- If `secret.enabled: true` and `kellnr.registry.cookieSigningKey` is empty, the chart will **not** set `KELLNR_REGISTRY__COOKIE_SIGNING_KEY`.
82-
83-
- If `secret.enabled: false` (ConfigMap mode), you should set `kellnr.registry.cookieSigningKey` explicitly (otherwise the env var is not set).
154+
- If neither value is set, Kellnr generates a random key on startup (per pod).
155+
- Provide the key inline to have the chart store it in its Secret, **or** point
156+
`cookieSigningKeySecretRef` at a Secret you manage yourself.
84157

85-
Example:
158+
Inline example:
86159

87160
````yaml
88161
kellnr:
89162
registry:
90163
cookieSigningKey: "<at least 64 characters>"
91164
````
92165

166+
Existing-secret example:
167+
168+
````yaml
169+
kellnr:
170+
registry:
171+
cookieSigningKeySecretRef:
172+
name: my-cookie-secret
173+
key: cookieSigningKey
174+
````
175+
176+
#### Extra environment variables
177+
178+
To inject arbitrary environment variables or mount your own ConfigMap/Secret alongside
179+
the chart's, use the `extraEnvVars*` settings.
180+
181+
| Setting | Required | Description | Default |
182+
|---------------------|----------|--------------------------------------------------------------------|---------|
183+
| extraEnvVars | No | List of raw Kubernetes `EnvVar` objects (supports `valueFrom`). | [] |
184+
| extraEnvVarsCM | No | Name of an existing ConfigMap to load via `envFrom`. | "" |
185+
| extraEnvVarsSecret | No | Name of an existing Secret to load via `envFrom`. | "" |
186+
187+
````yaml
188+
extraEnvVars:
189+
- name: AWS_REGION
190+
value: "eu-central-1"
191+
extraEnvVarsSecret: my-aws-credentials
192+
````
193+
93194

94195
### Service
95196

charts/kellnr/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type: application
1313
# This is the chart version. This version number should be incremented each time you make changes
1414
# to the chart and its templates, including the app version.
1515
# Versions are expected to follow Semantic Versioning (https://semver.org/)
16-
version: 5.0.6
16+
version: 6.0.0
1717
# This is the version number of the application being deployed. This version number should be
1818
# incremented each time you make changes to the application. Versions are not expected to
1919
# follow Semantic Versioning. They should reflect the version the application is using.

0 commit comments

Comments
 (0)