Prepare railiance01 delivery: dynamic leases, migrate Job, operator runbook
VaultDynamicSecret pulls database/creds/* so a rotating lease is not frozen into KV. Runtime sets AUDIT_CORE_AUTO_MIGRATE=0; schema is a Job with the migration lease. Image base is digest-pinned. Namespace and NetworkPolicies are on the cluster; Deployment waits for the attended OpenBao ESO token.
This commit is contained in:
parent
bbf86b8373
commit
3a7d63e18f
18 changed files with 826 additions and 33 deletions
19
deploy/README.md
Normal file
19
deploy/README.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# railiance01 package
|
||||
|
||||
Target: railiance01 only. The workstation kubeconfig that talks to that API
|
||||
is the `k3s-api-railiance01` tunnel (local port **16444**).
|
||||
`~/.kube/config-hosteurope` currently points at 16443 (coulombcore); rewrite
|
||||
the server port or export a copy before applying.
|
||||
|
||||
Apply order is documented in `docs/operator-runbook.md`. Do not apply the
|
||||
Deployment until:
|
||||
|
||||
1. The image digest is pinned (not `REPLACE_AT_RELEASE`).
|
||||
2. Secrets `audit-core-database`, `audit-core-database-migrate`, and
|
||||
`audit-core-senders` exist.
|
||||
3. Job `audit-core-migrate` has completed.
|
||||
|
||||
```bash
|
||||
make image-build
|
||||
make deploy-dry-run
|
||||
```
|
||||
|
|
@ -93,6 +93,10 @@ spec:
|
|||
# to the development store.
|
||||
- name: AUDIT_CORE_REQUIRE_CUSTODY_CLASS
|
||||
value: archive
|
||||
# Runtime role cannot CREATE TABLE. Schema changes are a Job
|
||||
# with the migration lease (deploy/migrate-job.yaml).
|
||||
- name: AUDIT_CORE_AUTO_MIGRATE
|
||||
value: "0"
|
||||
- name: AUDIT_CORE_DATABASE_SCHEMA
|
||||
value: audit_core
|
||||
- name: AUDIT_CORE_THREADS
|
||||
|
|
|
|||
31
deploy/clustersecretstore.yaml
Normal file
31
deploy/clustersecretstore.yaml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Template of the railiance-platform add-on store. Prefer applying from:
|
||||
# ~/railiance-platform/argocd/platform-addons/openbao-secretstore/openbao-audit-core.clustersecretstore.yaml
|
||||
#
|
||||
# Do not apply until Secret external-secrets/openbao-audit-core-eso-token exists
|
||||
# (scripts/openbao-eso-token-apply.sh). This store is KV-only: sender registry
|
||||
# lives at platform/workloads/audit-core/senders. Database leases are dynamic
|
||||
# and come from VaultDynamicSecret, not this store.
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ClusterSecretStore
|
||||
metadata:
|
||||
name: openbao-audit-core
|
||||
labels:
|
||||
app.kubernetes.io/part-of: railiance-gitops
|
||||
railiance-platform/component: external-secrets
|
||||
app.kubernetes.io/name: audit-core
|
||||
spec:
|
||||
provider:
|
||||
vault:
|
||||
# In-cluster OpenBao on railiance01, not the public bao.coulomb.social UI.
|
||||
server: http://openbao.openbao.svc:8200
|
||||
path: platform
|
||||
version: v2
|
||||
auth:
|
||||
tokenSecretRef:
|
||||
name: openbao-audit-core-eso-token
|
||||
namespace: external-secrets
|
||||
key: token
|
||||
conditions:
|
||||
- namespaces:
|
||||
- audit-core
|
||||
|
|
@ -1,14 +1,12 @@
|
|||
# Credential delivery for audit-core (AUDIT-WP-0005-T02).
|
||||
#
|
||||
# Follows the ClusterSecretStore -> ExternalSecret -> Secret pattern already in
|
||||
# use by activity-core and rapp-qonto. audit-core never holds a credential in
|
||||
# its own configuration; it reads whatever is currently mounted.
|
||||
# Two sources, because they are two kinds of secret:
|
||||
# - database leases: VaultDynamicSecret -> ExternalSecret (this file)
|
||||
# - sender registry: ClusterSecretStore openbao-audit-core -> ExternalSecret
|
||||
#
|
||||
# PREREQUISITE (rapp-postgres / railiance-platform, not this repo):
|
||||
# - a ClusterSecretStore named openbao-audit-core, scoped to this namespace
|
||||
# - the OpenBao database role rapp-postgres/audit-core-runtime issuing leases
|
||||
# against the audit_core_app group role
|
||||
# Apply order: ClusterSecretStore, then this, then the Deployment.
|
||||
# audit-core never holds a credential in its own configuration; it reads
|
||||
# whatever is currently mounted. Apply order: namespace, ESO token,
|
||||
# ClusterSecretStore, VaultDynamicSecret, this, migrate Job, Deployment.
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
|
|
@ -19,9 +17,6 @@ spec:
|
|||
# Shorter than the platform default of 1h: these are dynamic leases, and the
|
||||
# refresh interval bounds how long a revoked lease can remain mounted.
|
||||
refreshInterval: 15m
|
||||
secretStoreRef:
|
||||
kind: ClusterSecretStore
|
||||
name: openbao-audit-core
|
||||
target:
|
||||
name: audit-core-database
|
||||
creationPolicy: Owner
|
||||
|
|
@ -37,15 +32,38 @@ spec:
|
|||
host: platform-pg-rw.databases.svc.cluster.local
|
||||
port: "5432"
|
||||
dbname: audit_core
|
||||
data:
|
||||
- secretKey: username
|
||||
remoteRef:
|
||||
key: platform/workloads/audit-core/database/audit-core-runtime
|
||||
property: username
|
||||
- secretKey: password
|
||||
remoteRef:
|
||||
key: platform/workloads/audit-core/database/audit-core-runtime
|
||||
property: password
|
||||
dataFrom:
|
||||
- sourceRef:
|
||||
generatorRef:
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: VaultDynamicSecret
|
||||
name: audit-core-runtime
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: audit-core-database-migrate
|
||||
namespace: audit-core
|
||||
spec:
|
||||
refreshInterval: 15m
|
||||
target:
|
||||
name: audit-core-database-migrate
|
||||
creationPolicy: Owner
|
||||
deletionPolicy: Retain
|
||||
template:
|
||||
engineVersion: v2
|
||||
data:
|
||||
username: "{{ .username }}"
|
||||
password: "{{ .password }}"
|
||||
host: platform-pg-rw.databases.svc.cluster.local
|
||||
port: "5432"
|
||||
dbname: audit_core
|
||||
dataFrom:
|
||||
- sourceRef:
|
||||
generatorRef:
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: VaultDynamicSecret
|
||||
name: audit-core-migration
|
||||
---
|
||||
apiVersion: external-secrets.io/v1
|
||||
kind: ExternalSecret
|
||||
|
|
@ -71,5 +89,6 @@ spec:
|
|||
# between, so there is no delivery gap.
|
||||
- secretKey: senders.json
|
||||
remoteRef:
|
||||
key: platform/workloads/audit-core/senders
|
||||
# CSS already mounts KV path `platform`; do not repeat the prefix.
|
||||
key: workloads/audit-core/senders
|
||||
property: senders.json
|
||||
|
|
|
|||
66
deploy/migrate-job.yaml
Normal file
66
deploy/migrate-job.yaml
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# One-shot schema apply (AUDIT-WP-0005-T02).
|
||||
#
|
||||
# Uses the migration lease, not the runtime lease. The runtime Deployment
|
||||
# sets AUDIT_CORE_AUTO_MIGRATE=0 so a leaked app credential cannot change
|
||||
# the schema. Re-apply after deleting the previous Job when a new migration
|
||||
# ships (Jobs are immutable).
|
||||
#
|
||||
# Image digest must match deploy/audit-core.yaml.
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: audit-core-migrate
|
||||
namespace: audit-core
|
||||
labels:
|
||||
app.kubernetes.io/name: audit-core
|
||||
app.kubernetes.io/component: migrate
|
||||
spec:
|
||||
backoffLimit: 6
|
||||
ttlSecondsAfterFinished: 86400
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: audit-core
|
||||
app.kubernetes.io/component: migrate
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: migrate
|
||||
image: forgejo.coulomb.social/coulomb/audit-core@sha256:REPLACE_AT_RELEASE
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: ["python", "-m", "audit_core", "migrate"]
|
||||
env:
|
||||
- name: AUDIT_CORE_CREDENTIAL_DIR
|
||||
value: /etc/audit-core/db
|
||||
- name: AUDIT_CORE_DATABASE_SCHEMA
|
||||
value: audit_core
|
||||
resources:
|
||||
requests:
|
||||
cpu: 25m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 250m
|
||||
memory: 128Mi
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
readOnlyRootFilesystem: true
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
- name: database-credential
|
||||
mountPath: /etc/audit-core/db
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
- name: database-credential
|
||||
secret:
|
||||
secretName: audit-core-database-migrate
|
||||
defaultMode: 0400
|
||||
41
deploy/vaultdynamicsecrets.yaml
Normal file
41
deploy/vaultdynamicsecrets.yaml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Dynamic PostgreSQL leases (AUDIT-WP-0005-T02).
|
||||
#
|
||||
# These are not KV secrets. Copying a lease into platform/workloads/... would
|
||||
# freeze a rotating credential and recreate the delivery-gap problem the
|
||||
# mounted directory exists to avoid. ESO's VaultDynamicSecret generator reads
|
||||
# database/creds/* on each refresh and writes username/password files that
|
||||
# audit-core re-reads on the next connection.
|
||||
#
|
||||
# Prerequisite: Secret external-secrets/openbao-audit-core-eso-token.
|
||||
---
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: VaultDynamicSecret
|
||||
metadata:
|
||||
name: audit-core-runtime
|
||||
namespace: audit-core
|
||||
spec:
|
||||
path: database/creds/audit-core-runtime
|
||||
method: GET
|
||||
provider:
|
||||
server: http://openbao.openbao.svc:8200
|
||||
auth:
|
||||
tokenSecretRef:
|
||||
name: openbao-audit-core-eso-token
|
||||
namespace: external-secrets
|
||||
key: token
|
||||
---
|
||||
apiVersion: generators.external-secrets.io/v1alpha1
|
||||
kind: VaultDynamicSecret
|
||||
metadata:
|
||||
name: audit-core-migration
|
||||
namespace: audit-core
|
||||
spec:
|
||||
path: database/creds/audit-core-migration
|
||||
method: GET
|
||||
provider:
|
||||
server: http://openbao.openbao.svc:8200
|
||||
auth:
|
||||
tokenSecretRef:
|
||||
name: openbao-audit-core-eso-token
|
||||
namespace: external-secrets
|
||||
key: token
|
||||
Loading…
Add table
Add a link
Reference in a new issue