Add ArgoCD GitOps bootstrap contract for railiance01

Define platform-owned AppProjects, root app-of-apps, repository registration
templates, and tenant onboarding docs so issue-core can deploy via ArgoCD.
Ignore encrypted repository secrets locally and cross-link OpenBao delivery
guidance with the new GitOps contract.
This commit is contained in:
2026-06-19 21:05:12 +02:00
parent cb45f29fb2
commit 64d7c18c3f
13 changed files with 655 additions and 1 deletions

4
.gitignore vendored
View File

@@ -10,5 +10,9 @@ helm/*.yaml
!helm/*-networkpolicies.yaml
!helm/*-databases.yaml
# ArgoCD repository credentials — encrypt locally, never commit
argocd/repositories/*.repository.sops.yaml
!argocd/repositories/*.repository.sops.yaml.template
# Kubeconfig
*.kubeconfig

View File

@@ -0,0 +1,18 @@
# Railiance ArgoCD Tenant Applications
This directory is synced by the `railiance-apps-root` ArgoCD Application.
Tenant teams author a thin ArgoCD `Application` manifest against the contract
in `docs/argocd-gitops.md`. Platform review merges that manifest here after
checking namespace, repository, sync policy, and secret-delivery shape.
Workload manifests stay in the owning tenant repo. The default source path for
tenant workloads is:
```text
k8s/railiance/
```
Do not commit Kubernetes Secret values, ArgoCD repository credentials, OpenBao
tokens, deploy keys, or API keys here.

View File

@@ -0,0 +1,27 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: issue-core
namespace: argocd
labels:
app.kubernetes.io/part-of: railiance-gitops
railiance.io/domain: issue-core
annotations:
argocd.argoproj.io/sync-wave: "10"
spec:
project: railiance-tenants
source:
repoURL: https://gitea.coulomb.social/coulomb/issue-core.git
targetRevision: main
path: k8s/railiance
destination:
server: https://kubernetes.default.svc
namespace: issue-core
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ApplyOutOfSyncOnly=true
- PruneLast=true

View File

@@ -0,0 +1,22 @@
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: railiance-bootstrap
namespace: argocd
labels:
app.kubernetes.io/part-of: railiance-gitops
railiance-platform/component: gitops
spec:
description: Platform-owned ArgoCD bootstrap project for Railiance app-of-apps.
sourceRepos:
- https://gitea.coulomb.social/coulomb/railiance-platform.git
destinations:
- server: https://kubernetes.default.svc
namespace: argocd
clusterResourceWhitelist: []
namespaceResourceWhitelist:
- group: argoproj.io
kind: Application
orphanedResources:
warn: true

View File

@@ -0,0 +1,52 @@
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: railiance-tenants
namespace: argocd
labels:
app.kubernetes.io/part-of: railiance-gitops
railiance-platform/component: gitops
spec:
description: Guardrails for Railiance tenant applications deployed by ArgoCD.
sourceRepos:
- https://gitea.coulomb.social/coulomb/*.git
destinations:
- server: https://kubernetes.default.svc
namespace: "*"
clusterResourceWhitelist:
- group: ""
kind: Namespace
namespaceResourceWhitelist:
- group: ""
kind: ConfigMap
- group: ""
kind: PersistentVolumeClaim
- group: ""
kind: Secret
- group: ""
kind: Service
- group: ""
kind: ServiceAccount
- group: apps
kind: Deployment
- group: apps
kind: StatefulSet
- group: autoscaling
kind: HorizontalPodAutoscaler
- group: batch
kind: CronJob
- group: batch
kind: Job
- group: external-secrets.io
kind: ExternalSecret
- group: networking.k8s.io
kind: Ingress
- group: networking.k8s.io
kind: NetworkPolicy
- group: traefik.io
kind: IngressRoute
- group: traefik.io
kind: Middleware
orphanedResources:
warn: true

View File

@@ -0,0 +1,26 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: railiance-apps-root
namespace: argocd
labels:
app.kubernetes.io/part-of: railiance-gitops
railiance-platform/component: gitops
spec:
project: railiance-bootstrap
source:
repoURL: https://gitea.coulomb.social/coulomb/railiance-platform.git
targetRevision: main
path: argocd/applications
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=false
- ApplyOutOfSyncOnly=true
- PruneLast=true

View File

@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- 00-railiance-bootstrap-project.yaml
- 01-railiance-tenants-project.yaml
- 10-railiance-apps-root.application.yaml

View File

@@ -0,0 +1,23 @@
# ArgoCD Repository Registration
ArgoCD discovers Git repositories from Kubernetes Secrets in the `argocd`
namespace with `argocd.argoproj.io/secret-type: repository`.
Use the templates in this directory to create SOPS-encrypted, non-plaintext
repository Secret files. Credentials must be sourced from the approved
operator/OpenBao path and must never be committed in plaintext.
Recommended OpenBao path:
```text
platform/operators/argocd/repositories/<repo-name>
```
After creating an encrypted file such as
`argocd/repositories/railiance-platform.repository.sops.yaml`, apply it with:
```bash
ARGOCD_REPOSITORY_SECRET=argocd/repositories/railiance-platform.repository.sops.yaml \
make argocd-repo-apply
```

View File

@@ -0,0 +1,21 @@
# Copy to issue-core.repository.sops.yaml, fill from the approved
# operator/OpenBao path, then encrypt with:
# sops -e -i argocd/repositories/issue-core.repository.sops.yaml
#
# Do not commit plaintext credentials.
apiVersion: v1
kind: Secret
metadata:
name: issue-core-repository
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
app.kubernetes.io/part-of: railiance-gitops
railiance-platform/component: gitops
stringData:
type: git
project: railiance-tenants
url: https://gitea.coulomb.social/coulomb/issue-core.git
username: CHANGE_ME
password: CHANGE_ME

View File

@@ -0,0 +1,21 @@
# Copy to railiance-platform.repository.sops.yaml, fill from the approved
# operator/OpenBao path, then encrypt with:
# sops -e -i argocd/repositories/railiance-platform.repository.sops.yaml
#
# Do not commit plaintext credentials.
apiVersion: v1
kind: Secret
metadata:
name: railiance-platform-repository
namespace: argocd
labels:
argocd.argoproj.io/secret-type: repository
app.kubernetes.io/part-of: railiance-gitops
railiance-platform/component: gitops
stringData:
type: git
project: railiance-bootstrap
url: https://gitea.coulomb.social/coulomb/railiance-platform.git
username: CHANGE_ME
password: CHANGE_ME

176
docs/argocd-gitops.md Normal file
View File

@@ -0,0 +1,176 @@
# ArgoCD GitOps Contract
Railiance ArgoCD is the cluster sync engine. This repo owns only the shared
platform contract around GitOps trust, guardrails, and OpenBao-backed secret
delivery. Application workload manifests remain in the owning application
repos.
## Ownership Boundary
`railiance-platform` owns:
- ArgoCD AppProject guardrails for Railiance tenant workloads.
- The root app-of-apps entrypoint.
- Repository credential registration templates.
- Secret delivery conventions through OpenBao and External Secrets Operator.
Tenant repos own:
- Container images.
- Workload manifests under `k8s/railiance/`.
- The proposed ArgoCD `Application` manifest for platform review.
- Application config that contains no secret values.
Cluster/runtime ownership remains outside this repo: installing or upgrading
ArgoCD itself belongs with the cluster layer.
## Bootstrap Layout
```text
argocd/bootstrap/
00-railiance-bootstrap-project.yaml
01-railiance-tenants-project.yaml
10-railiance-apps-root.application.yaml
argocd/applications/
*.application.yaml
argocd/repositories/
*.repository.sops.yaml
```
The bootstrap is applied once by an operator. If the Git source is private,
apply the encrypted `railiance-platform` repository Secret first so the root
Application can sync this repo:
```bash
ARGOCD_REPOSITORY_SECRET=argocd/repositories/railiance-platform.repository.sops.yaml \
make argocd-repo-apply
make argocd-bootstrap-dry-run
make argocd-bootstrap-deploy
make argocd-status
```
After that, `railiance-apps-root` syncs tenant Application manifests from
`argocd/applications/`.
## Repository Registration
Every Git source repo used by ArgoCD must be registered in the `argocd`
namespace with an ArgoCD repository Secret. Use one read-only deploy token or
deploy key per repo unless an operator approves a narrower shared credential
model.
Repository credentials are operator credentials, not workload secrets. Store
their source material in OpenBao under:
```text
platform/operators/argocd/repositories/<repo-name>
```
Create an encrypted repository Secret from the matching template:
```bash
cp argocd/repositories/issue-core.repository.sops.yaml.template \
argocd/repositories/issue-core.repository.sops.yaml
sops -e -i argocd/repositories/issue-core.repository.sops.yaml
```
Apply only encrypted files:
```bash
ARGOCD_REPOSITORY_SECRET=argocd/repositories/issue-core.repository.sops.yaml \
make argocd-repo-apply
```
Do not commit plaintext deploy tokens, passwords, SSH private keys, OpenBao
tokens, or ArgoCD API tokens.
## Tenant Application Contract
Tenant Applications are thin routing manifests reviewed into
`argocd/applications/`. The workload source remains in the tenant repo,
normally:
```text
k8s/railiance/
```
Default Application shape:
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: example-service
namespace: argocd
spec:
project: railiance-tenants
source:
repoURL: https://gitea.coulomb.social/coulomb/example-service.git
targetRevision: main
path: k8s/railiance
destination:
server: https://kubernetes.default.svc
namespace: example-service
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ApplyOutOfSyncOnly=true
- PruneLast=true
```
Use sync waves only for real dependency ordering. Secret delivery resources
should sync before Deployments that consume them.
## Secret Delivery
OpenBao is the canonical runtime secret custody authority.
Default pattern:
1. Store workload secret material in OpenBao.
2. Use External Secrets Operator to materialize a Kubernetes Secret in the
workload namespace.
3. Reference that Kubernetes Secret from the Deployment, Job, or CronJob.
Path convention:
```text
platform/workloads/<namespace>/<service-account>/<secret-name>
```
Use CSI-mounted files only for workloads that need file references, sharper
mount boundaries, or refresh behavior that should not rewrite application
manifests. Do not use the OpenBao injector in the current deployment.
For `issue-core`, the expected custody shape is:
```text
platform/workloads/issue-core/issue-core/issue-core-runtime
```
with properties such as:
```text
ISSUE_CORE_API_KEY
GITEA_BACKEND_TOKEN
```
The exact ExternalSecret manifest belongs with `issue-core` workload
manifests, because it is part of that service's runtime deployment.
## AppProject Guardrails
`railiance-bootstrap` allows the root app to manage ArgoCD `Application`
objects in the `argocd` namespace.
`railiance-tenants` allows ordinary namespaced workload resources and namespace
creation. It does not allow tenant Applications to create CRDs, ClusterRoles,
ClusterRoleBindings, or other cluster-admin resources.
If a tenant needs a cluster-scoped platform resource, create a new
platform-owned workplan instead of broadening the tenant project by default.

View File

@@ -374,7 +374,8 @@ platform/operators/
platform/operators/inter-hub/
```
Workload delivery choice:
Workload delivery choice (see also `docs/argocd-gitops.md` for the GitOps
tenant contract):
- Prefer External Secrets Operator for values that should become Kubernetes
Secrets consumed by ordinary Helm charts.

View File

@@ -0,0 +1,256 @@
---
id: RAILIANCE-WP-0004
type: workplan
title: "Establish ArgoCD GitOps bootstrap contract"
domain: railiance
repo: railiance-platform
status: blocked
owner: codex
topic_slug: railiance
planning_priority: high
planning_order: 4
created: "2026-06-19"
updated: "2026-06-19"
---
# RAILIANCE-WP-0004 - Establish ArgoCD GitOps Bootstrap Contract
## Goal
Establish the minimal platform-owned ArgoCD GitOps contract needed for
Railiance application teams to deploy through the already-installed ArgoCD
instance on `railiance01`.
This work responds to the `issue-core` dependency message from 2026-06-18:
ArgoCD is installed and healthy on `railiance01`, but unused. `issue-core`
will be the first tenant Application and needs platform decisions before it
can author its workload deployment.
## Intent Alignment
`INTENT.md` defines this repo as the shared platform-services layer:
stateful services, secret custody, stable interfaces, and recoverable
operational contracts.
ArgoCD itself is not an application, database, or secret store. The work in
this repo is therefore intentionally limited to the platform contract around
GitOps:
- repository trust and credential registration for ArgoCD;
- AppProject guardrails that keep tenant syncs inside expected boundaries;
- a root app-of-apps entrypoint that provides a stable onboarding surface;
- the OpenBao-backed runtime secret delivery convention tenants must use.
Application workloads, container images, per-service manifests, and business
logic remain owned by the tenant repos.
## Scope
In scope:
- Define the bootstrap manifests for ArgoCD AppProjects and the root
app-of-apps Application.
- Define how Git source repositories are registered without committing
credentials.
- Define where tenant Application manifests are placed and how they point
back to tenant-owned workload manifests.
- Confirm the runtime secret delivery pattern: OpenBao custody delivered to
Kubernetes via External Secrets Operator by default; CSI-mounted files only
when a workload requires file references; OpenBao injector remains disabled.
- Provide an `issue-core` pilot Application example so that repo can author
its final manifest against a concrete contract.
Out of scope:
- Installing or upgrading ArgoCD itself; that is cluster/runtime ownership.
- Moving S5 application workload manifests into this repo.
- Storing ArgoCD repository credentials, API tokens, or application secrets in
Git, workplans, State Hub, or chat.
- Applying live manifests that require operator-owned credentials.
## Decisions
### D-01 - Bootstrap Layout
Use this repo only for the platform-owned GitOps bootstrap:
```text
argocd/bootstrap/ AppProjects and root app-of-apps Application
argocd/applications/ thin tenant Application manifests reviewed by platform
argocd/repositories/ SOPS templates for ArgoCD repository Secret objects
docs/argocd-gitops.md GitOps contract and onboarding guidance
```
The root Application syncs `argocd/applications/` from this repo. Tenant
Application manifests in that directory point to workload manifests in each
tenant repo, normally `k8s/railiance/`.
### D-02 - AppProject Model
Create two AppProjects:
- `railiance-bootstrap` only allows the root app to manage ArgoCD
`Application` objects in the `argocd` namespace.
- `railiance-tenants` allows tenant Applications to sync ordinary namespaced
workload resources into their own namespaces, plus namespace creation. It
does not grant CRD, ClusterRole, ClusterRoleBinding, or arbitrary
cluster-admin authority.
### D-03 - Sync Policy
Default tenant Applications use automated sync with prune and self-heal
enabled after platform review. Recommended sync options are:
```yaml
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ApplyOutOfSyncOnly=true
- PruneLast=true
```
Sync waves are reserved for dependency ordering. Platform services and secret
delivery resources should sync before workloads that consume them.
### D-04 - Secret Delivery
OpenBao remains the canonical runtime secret custody service. For ordinary
Kubernetes workloads, use External Secrets Operator to materialize OpenBao
values as Kubernetes Secrets. Do not use the OpenBao injector in the current
deployment.
Runtime path convention:
```text
platform/workloads/<namespace>/<service-account>/<secret-name>
```
ArgoCD repository credentials are operator credentials, not workload secrets,
and should live under:
```text
platform/operators/argocd/repositories/<repo-name>
```
## Current Evidence
- State Hub inbox message `d7a18ff9-e6c6-4e44-a39e-78369e530dfc` reports
ArgoCD is installed and healthy on `railiance01`, with zero Applications,
zero ApplicationSets, zero registered repositories, and only the stock
`default` AppProject.
- `INTENT.md` and `SCOPE.md` keep this repo focused on shared platform
services and secret custody. This work therefore creates a bootstrap
contract and secret-delivery convention, not app workload ownership.
- `docs/openbao.md` already states the preferred delivery pattern:
External Secrets Operator for values that become Kubernetes Secrets, CSI for
file-reference workloads, and no OpenBao injector in the current deployment.
## Target State
- `argocd/bootstrap/` contains the two AppProjects and root app-of-apps
Application.
- `argocd/applications/` documents the tenant Application contract and includes
an `issue-core` example manifest.
- `argocd/repositories/` contains non-secret SOPS templates for ArgoCD
repository registration.
- `docs/argocd-gitops.md` answers the four questions raised by `issue-core`:
repository registration, source layout, sync policy, and secret delivery.
- Make targets exist for dry-run, deploy, status, and SOPS-backed repository
secret application.
- `issue-core` can author its final Application and workload manifests against
this contract without waiting for more platform design.
## Tasks
### T01 - Review intent and scope boundary
```task
id: RAILIANCE-WP-0004-T01
status: done
priority: high
```
Review `INTENT.md`, `SCOPE.md`, existing OpenBao delivery docs, and the
`issue-core` inbox request. Capture the boundary that ArgoCD bootstrap belongs
here only as a platform trust and secret-delivery contract.
### T02 - Add ArgoCD bootstrap manifests
```task
id: RAILIANCE-WP-0004-T02
status: done
priority: high
```
Add AppProject manifests and the root app-of-apps Application under
`argocd/bootstrap/`.
Done when the manifests can be rendered by `kubectl apply -k` and avoid secret
material.
### T03 - Define tenant onboarding and repository registration
```task
id: RAILIANCE-WP-0004-T03
status: done
priority: high
```
Add documentation and templates for tenant Applications, per-repo ArgoCD
repository Secret registration, and the `issue-core` pilot example.
### T04 - Confirm OpenBao-backed secret delivery
```task
id: RAILIANCE-WP-0004-T04
status: done
priority: high
```
Document that OpenBao remains the runtime custody authority, External Secrets
Operator is the default Kubernetes delivery mechanism, CSI is reserved for
file-reference workloads, and the OpenBao injector remains disabled.
### T05 - Operator live bootstrap
```task
id: RAILIANCE-WP-0004-T05
status: blocked
priority: high
```
Apply the bootstrap and repository credentials to live ArgoCD after these repo
changes are merged to the Git source ArgoCD reads and, if the source repo is
private, after an operator provides or materializes read-only repository
credentials through the approved OpenBao/operator path.
Blocked until the bootstrap files are available on the remote branch ArgoCD
syncs and operator-owned repository credentials exist outside Git when needed.
Do not paste credentials into the workplan, State Hub, or chat.
Expected command sequence after credentials are available:
```bash
ARGOCD_REPOSITORY_SECRET=argocd/repositories/railiance-platform.repository.sops.yaml \
make argocd-repo-apply
make argocd-bootstrap-dry-run
make argocd-bootstrap-deploy
make argocd-status
```
### T06 - Notify first tenant
```task
id: RAILIANCE-WP-0004-T06
status: done
priority: medium
```
Reply to `issue-core` with the GitOps contract pointer and confirm that it owns
the final `issue-core` Application proposal and workload manifests. Include the
OpenBao path convention for `ISSUE_CORE_API_KEY` and the Gitea backend token.
State Hub reply: `56df276d-77d0-427f-92a5-a99cacc1290f`.