Skip to content

Commit 27af88d

Browse files
authored
Use Kubernetes Secrets for backend bootstrap authentication (#1275)
* Use Kubernetes Secrets for backend bootstrap authentication * Add safe Helm bootstrap for backend tokens * Fix backend secret auth test cleanup * Prevent backend token disclosure in deployment helpers * Resolve MCP and backend token chart integration * Address backend bootstrap review feedback * Replace backend bootstrap service image with kubectl hook * Run backend bootstrap with BusyBox ash * Fix optional token lookup and cache publication * Install kubectl in internal CI
1 parent b07f1d3 commit 27af88d

49 files changed

Lines changed: 2402 additions & 392 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/helm-chart-lint.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ jobs:
148148
if: matrix.chart == 'service'
149149
run: bash deployments/charts/service/ci/validate-mcp-chart.sh
150150

151+
- name: Chart-specific render tests
152+
run: |
153+
TEST_SCRIPT="deployments/charts/${{ matrix.chart }}/tests/render-tests.sh"
154+
if [ -f "$TEST_SCRIPT" ]; then
155+
bash "$TEST_SCRIPT"
156+
fi
157+
151158
- name: Validate unified OSMO chart
152159
if: matrix.chart == 'osmo'
153160
run: bash deployments/charts/osmo/tests/test_osmo_charts.sh osmo

.github/workflows/pr-checks.yaml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ jobs:
163163
ports:
164164
- 2375:2375
165165
steps:
166-
- name: Install Node.js, Docker CLI, and dependencies
166+
- name: Install Node.js, Docker CLI, kubectl, and dependencies
167167
run: |
168168
apt-get update
169169
apt-get install -y ca-certificates curl gnupg git-lfs
@@ -183,6 +183,15 @@ jobs:
183183
# Install Docker CLI (client only, connects to DinD service)
184184
apt-get install -y docker-ce-cli
185185
186+
# Install kubectl for deployment-script tests that render Secrets.
187+
KUBECTL_VERSION=v1.31.0
188+
curl -fsSLo /tmp/kubectl \
189+
"https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl"
190+
curl -fsSL "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl.sha256" \
191+
| awk '{print $1" /tmp/kubectl"}' | sha256sum -c -
192+
install -m 0755 /tmp/kubectl /usr/local/bin/kubectl
193+
rm -f /tmp/kubectl
194+
186195
# Remove Debian's nodejs package if present and install from NodeSource
187196
apt-get remove -y nodejs || true
188197
apt-get install -y nodejs=20.*
@@ -191,6 +200,7 @@ jobs:
191200
echo "Node.js version: $(node --version)"
192201
echo "npm version: $(npm --version)"
193202
echo "Docker version: $(docker --version)"
203+
kubectl version --client --output=yaml
194204
echo "Git LFS version: $(git-lfs --version)"
195205
196206
- name: Clean up stale LFS hooks

AGENTS.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Entry point: `service/core/service.py`. Framework: FastAPI + Uvicorn + OpenTelem
8585

8686
| Submodule | Purpose |
8787
|-----------|---------|
88-
| `auth/` | JWT token lifecycle, access token CRUD, user management, role assignment |
88+
| `auth/` | JWT token lifecycle, access token CRUD, user management, role assignment, and Kubernetes Secret-backed backend bootstrap authentication |
8989
| `workflow/` | Workflow submit/list/cancel, resource quota, pool allocation, task coordination, credential management |
9090
| `config/` | Service/workflow configuration CRUD with versioning and history. Pod templates, resource validation rules, pool/backend config. |
9191
| `data/` | Workflow data and storage operations built on multi-backend storage. |
@@ -94,6 +94,17 @@ Entry point: `service/core/service.py`. Framework: FastAPI + Uvicorn + OpenTelem
9494

9595
**Error types**: Defined in `lib/utils/` — see the `OSMOError` hierarchy for the full list.
9696

97+
Backend bootstrap authentication is implemented by
98+
`auth/backend_secret_auth.py`, which maps mounted Kubernetes Secret tokens to
99+
the fixed `osmo-backend` identity. The service Helm chart creates managed
100+
development credentials with a short-lived kubectl hook without rendering token
101+
material in Helm output. Changes to this authentication path must run:
102+
103+
```bash
104+
bazel test //src/service/core/auth/tests:test_backend_secret_auth
105+
bash deployments/charts/service/tests/render-tests.sh
106+
```
107+
97108
### Supporting Services
98109

99110
| Service | Purpose |

deployments/BUILD

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@ limitations under the License.
1515
1616
SPDX-License-Identifier: Apache-2.0
1717
"""
18+
19+
exports_files([
20+
"scripts/common.sh",
21+
"scripts/deploy-k8s.sh",
22+
])

deployments/README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ For users who already have Kubernetes infrastructure and want to deploy OSMO dir
100100
> - Kubernetes namespaces (`osmo-minimal`, `osmo-operator`, `osmo-workflows`)
101101
> - Database secrets (`db-secret` with PostgreSQL password)
102102
> - Redis secrets (`redis-secret` with Redis password)
103+
> - For production or multi-cluster installs, a backend bootstrap token Secret
104+
> copied to the control and compute clusters
103105
> - MEK ConfigMap (Master Encryption Key)
104106
> - The PostgreSQL database itself
105107
>
@@ -124,10 +126,10 @@ For a direct Helm install, deploy the charts in this order:
124126
```bash
125127
kubectl create namespace osmo --dry-run=client -o yaml | kubectl apply -f -
126128
kubectl create namespace osmo-test --dry-run=client -o yaml | kubectl apply -f -
127-
BACKEND_OPERATOR_PASSWORD=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d '\n=' | head -c 43)
128-
kubectl create secret generic backend-operator-password \
129+
LOCAL_ADMIN_PASSWORD=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d '\n=' | head -c 43)
130+
kubectl create secret generic local-admin-password \
129131
--namespace osmo \
130-
--from-literal=password="$BACKEND_OPERATOR_PASSWORD" \
132+
--from-literal=password="$LOCAL_ADMIN_PASSWORD" \
131133
--dry-run=client -o yaml | kubectl apply -f -
132134

133135
if ! kubectl get configmap mek-config --namespace osmo >/dev/null 2>&1; then
@@ -156,6 +158,11 @@ helm upgrade --install osmo-backend-operator osmo/backend-operator \
156158
--wait
157159
```
158160

161+
For the local quick-start only, the service values generate
162+
`backend-operator-token` during the first Helm install. Because the backend
163+
operator is installed in the same namespace, it consumes that Secret directly;
164+
no pre-created backend Secret is required.
165+
159166
After installing the CLI and logging in, set the demo pool and LocalStack data credential:
160167

161168
```bash

deployments/charts/README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,17 @@ The former quick-start values are preserved as chart-specific values files:
3232
- `service/quick-start-values.yaml`
3333
- `backend-operator/quick-start-values.yaml`
3434

35-
Create the namespaces, the local backend-operator password secret, and the MEK
36-
ConfigMap used by the service pods:
35+
Create the namespaces, the local admin password Secret, and the MEK ConfigMap
36+
used by the service pods. The service quick-start values create the shared
37+
backend bootstrap Secret through the chart-managed development mode:
3738

3839
```bash
3940
kubectl create namespace osmo --dry-run=client -o yaml | kubectl apply -f -
4041
kubectl create namespace osmo-test --dry-run=client -o yaml | kubectl apply -f -
41-
BACKEND_OPERATOR_PASSWORD=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d '\n=' | head -c 43)
42-
kubectl create secret generic backend-operator-password \
42+
LOCAL_ADMIN_PASSWORD=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d '\n=' | head -c 43)
43+
kubectl create secret generic local-admin-password \
4344
--namespace osmo \
44-
--from-literal=password="$BACKEND_OPERATOR_PASSWORD" \
45+
--from-literal=password="$LOCAL_ADMIN_PASSWORD" \
4546
--dry-run=client -o yaml | kubectl apply -f -
4647

4748
if ! kubectl get configmap mek-config --namespace osmo >/dev/null 2>&1; then
@@ -121,4 +122,9 @@ For production, use your environment-specific values instead of the local quick-
121122
- Provide managed PostgreSQL, Redis, and object storage settings or enable the chart-managed development dependencies only for non-production use.
122123
- Enable OAuth2/authz in the service chart when exposing OSMO to untrusted networks.
123124
- Configure `backend-operator.global.serviceUrl` to the service gateway URL reachable from the backend cluster.
124-
- Use `backend-operator.global.loginMethod` with either password or token credentials stored in Kubernetes Secrets.
125+
- Provision one backend bootstrap Secret per compute plane in both the control
126+
and compute clusters. Configure the service chart's
127+
`services.backendApiTokens.credentials[].existingSecret.name`
128+
and `backend-operator.global.accountTokenSecret` to consume the matching Secret.
129+
The service chart's `managedSecret` mode is intended only for single-cluster
130+
development where the backend operator can consume the namespace-local Secret.

deployments/charts/backend-operator/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ helm upgrade --install osmo-backend-operator osmo/backend-operator \
5757
| `global.enableClusterRoles` | Enable cluster roles | `true` |
5858
| `global.enableNonClusterRoles` | Enable non-cluster roles | `true` |
5959

60+
For Secret-backed bootstrap, set `global.loginMethod: token` and reference the
61+
copy of the credential that is also mounted by the control-plane service chart.
62+
The token volume is mounted as a directory so Kubernetes Secret projection
63+
updates are visible. During rotation, restart both backend deployments before
64+
the control plane stops accepting the previous token.
65+
6066
### Global NetworkPolicy Settings
6167

6268
When enabled, a `NetworkPolicy` is applied to the workflow namespace (`global.backendNamespace`) that allows unrestricted external internet egress while blocking cross-namespace cluster traffic except to explicitly allowlisted namespaces.

deployments/charts/backend-operator/quick-start-values.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
# SPDX-License-Identifier: Apache-2.0
1616

1717
# Local-development values preserved from the former quick-start install path.
18-
# Install after the service chart has created the backend-operator admin user.
18+
# Install after the service chart creates backend-operator-token through its
19+
# chart-managed backend credential mode.
1920

2021
global:
2122
osmoImageLocation: nvcr.io/nvidia/osmo
@@ -26,10 +27,9 @@ global:
2627
backendNamespace: default
2728
backendTestNamespace: osmo-test
2829
backendName: default
29-
accountUsername: backend-operator
30-
accountPasswordSecret: backend-operator-password
31-
accountPasswordSecretKey: password
32-
loginMethod: password
30+
accountTokenSecret: backend-operator-token
31+
accountTokenSecretKey: token
32+
loginMethod: token
3333
nodeSelector:
3434
node_group: service
3535

deployments/charts/backend-operator/templates/backend-listener.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,7 @@ spec:
138138
readOnly: true
139139
{{- else if eq .Values.global.loginMethod "token" }}
140140
- name: osmo-secret
141-
mountPath: /opt/osmo/secrets/token.txt
142-
subPath: token.txt
141+
mountPath: /opt/osmo/secrets
143142
readOnly: true
144143
{{- end }}
145144
{{- if .Values.services.backendListener.volumeMounts }}

deployments/charts/backend-operator/templates/backend-worker.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ spec:
136136
readOnly: true
137137
{{- else if eq .Values.global.loginMethod "token" }}
138138
- name: osmo-secret
139-
mountPath: /opt/osmo/secrets/token.txt
140-
subPath: token.txt
139+
mountPath: /opt/osmo/secrets
141140
readOnly: true
142141
{{- end }}
143142
{{- if .Values.backendTestRunner.enabled }}

0 commit comments

Comments
 (0)