generated from coulomb/repo-seed
Add security architecture pattern infospace
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# ADR-0008 - Object Storage STS Credential Vending Boundary
|
||||
|
||||
**Status:** Accepted
|
||||
**Date:** 2026-05-18
|
||||
**Deciders:** Bernd Worsch, Codex
|
||||
|
||||
## Context
|
||||
|
||||
NetKingdom needs a canonical pattern for issuing short-lived
|
||||
object-storage credentials to platform and tenant workloads. The first
|
||||
known consumer is `artifact-store`, but the pattern must work for future
|
||||
S3-compatible consumers without making each application repo own identity,
|
||||
authorization, root object-store credentials, or backend-specific STS
|
||||
differences.
|
||||
|
||||
The backend landscape is not uniform. AWS S3, Ceph RGW, and MinIO/AIStor
|
||||
can use web-identity STS-style flows. Cloudflare R2 exposes temporary
|
||||
credentials through a provider API or local signing with parent access
|
||||
material. OpenBao is now part of the Railiance platform stack as runtime
|
||||
secret authority, but it is not an identity provider or authorization
|
||||
policy engine.
|
||||
|
||||
## Decision
|
||||
|
||||
NetKingdom will define a provider-neutral credential-vending interface
|
||||
backed by provider-native temporary credential mechanisms where possible.
|
||||
|
||||
The trust path is:
|
||||
|
||||
1. IAM Profile token proves the actor or workload.
|
||||
2. flex-auth decides whether the actor may receive credentials for the
|
||||
requested protected system, tenant, bucket, prefix, action set, TTL,
|
||||
and assurance level.
|
||||
3. The credential-vending service exchanges the approved request with
|
||||
the backend-specific temporary credential mechanism.
|
||||
4. OpenBao stores parent credentials, broker configuration, lease
|
||||
metadata, and audit evidence where useful, but it does not replace
|
||||
flex-auth authorization.
|
||||
5. Consumers receive normalized temporary credentials containing access
|
||||
key id, secret access key, session token, and expiration.
|
||||
|
||||
## Consequences
|
||||
|
||||
- `artifact-store` needs temporary credential support, especially
|
||||
`AWS_SESSION_TOKEN` and refresh behavior, before it can fully consume
|
||||
the production vending pattern.
|
||||
- Backend-specific differences are isolated in the vending service, not
|
||||
leaked into application policy.
|
||||
- OpenBao remains runtime secret infrastructure and audit support; it
|
||||
does not become the object-storage policy source.
|
||||
- Provider-native STS is preferred when available because it gives the
|
||||
storage backend direct lease/expiration semantics.
|
||||
- Cloudflare R2 requires a broker path that protects parent access
|
||||
material, most likely through OpenBao custody.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
### Give Applications Long-Lived Access Keys
|
||||
|
||||
This is simple but leaves applications holding durable credentials and
|
||||
pushes policy into ad hoc bucket configuration. It is acceptable only as
|
||||
a transitional bridge with scoped credentials and explicit rotation.
|
||||
|
||||
### Put Object-Storage Policy In Keycloak Or key-cape
|
||||
|
||||
Identity providers can assert who the actor is and coarse groups or
|
||||
roles, but they should not become the canonical source of bucket,
|
||||
prefix, action, TTL, and explanation semantics.
|
||||
|
||||
### Use OpenBao As The Credential Vending Policy Engine
|
||||
|
||||
OpenBao is valuable for secret custody, broker configuration, leases,
|
||||
and audit records. Making it the policy decision point would duplicate
|
||||
flex-auth, blur the platform/tenant boundary, and make authorization
|
||||
semantics backend-specific.
|
||||
|
||||
### Require One Backend Everywhere
|
||||
|
||||
A single backend would simplify implementation but does not match the
|
||||
platform direction. Railiance and NetKingdom need a stable security
|
||||
interface across AWS, self-hosted S3-compatible stores, and Cloudflare
|
||||
R2-like APIs.
|
||||
@@ -0,0 +1,482 @@
|
||||
# Object Storage STS Credential Vending
|
||||
|
||||
Status: architecture baseline for NK-WP-0007
|
||||
Date: 2026-05-18
|
||||
|
||||
## Purpose
|
||||
|
||||
This document defines the NetKingdom pattern for vending short-lived
|
||||
object-storage credentials from verified identity and policy decisions.
|
||||
It is provider-neutral at the NetKingdom boundary and provider-aware at
|
||||
the backend exchange boundary.
|
||||
|
||||
The goal is to let consumers such as `artifact-store` use S3-compatible
|
||||
temporary credentials without owning identity, authorization, secret
|
||||
custody, or object-storage root credentials.
|
||||
|
||||
## Ownership Boundary
|
||||
|
||||
| Capability | Owner |
|
||||
| --- | --- |
|
||||
| IAM Profile, issuer and claim requirements | NetKingdom |
|
||||
| Resource/action vocabulary and policy decision envelope | flex-auth, governed by NetKingdom architecture |
|
||||
| Delegated PDP runtime | Topaz first, behind flex-auth |
|
||||
| Runtime secret custody, broker configuration, audit, leases | OpenBao, deployed by Railiance platform |
|
||||
| Object-storage backend configuration | Railiance platform |
|
||||
| Artifact package behavior and S3 client refresh behavior | artifact-store |
|
||||
| Application deployment | Railiance apps or the owning application repo |
|
||||
|
||||
OpenBao may store parent credentials, broker configuration, or issued
|
||||
credential metadata where appropriate. It does not replace flex-auth as
|
||||
the authorization decision point and must not become the object-storage
|
||||
policy model.
|
||||
|
||||
## Core Flow
|
||||
|
||||
```text
|
||||
Human, service, or agent principal
|
||||
|
|
||||
v
|
||||
NetKingdom IAM Profile token
|
||||
key-cape lightweight mode or Keycloak expanded mode
|
||||
|
|
||||
v
|
||||
credential-vending service
|
||||
verifies issuer, audience, subject, assurance, tenant
|
||||
|
|
||||
v
|
||||
flex-auth decision
|
||||
tenant, protected-system, bucket, prefix, actions, TTL, obligations
|
||||
|
|
||||
v
|
||||
backend exchange
|
||||
AWS STS, Ceph RGW STS, MinIO/AIStor STS, Cloudflare R2 temp API,
|
||||
or OpenBao-assisted broker path
|
||||
|
|
||||
v
|
||||
temporary S3 credentials
|
||||
access key id, secret access key, session token, expiration
|
||||
|
|
||||
v
|
||||
consumer
|
||||
artifact-store, SDK, CLI, sidecar, controller, or batch job
|
||||
```
|
||||
|
||||
## Trust Boundaries
|
||||
|
||||
### Platform Control Plane
|
||||
|
||||
`tenant:platform` administers the credential-vending service, approved
|
||||
issuer list, flex-auth policy import pipeline, OpenBao mounts/auth
|
||||
methods, backend parent credentials, audit retention, and emergency
|
||||
recovery.
|
||||
|
||||
### Tenant Plane
|
||||
|
||||
`tenant:coulomb` and later tenants may request scoped credentials for
|
||||
registered tenant resources. Tenant administrators must not receive
|
||||
OpenBao root tokens, object-storage root credentials, global backend STS
|
||||
configuration, or platform policy import authority.
|
||||
|
||||
### Backend Boundary
|
||||
|
||||
The credential-vending service is the only component that exchanges an
|
||||
approved decision for provider-native credentials. Consumers receive only
|
||||
short-lived credentials scoped to the approved bucket, prefix, actions,
|
||||
and TTL.
|
||||
|
||||
## Token And Decision Flow
|
||||
|
||||
1. The caller authenticates through a NetKingdom IAM Profile
|
||||
implementation.
|
||||
2. The caller sends a request to the credential-vending service with a
|
||||
bearer token or a workload identity binding.
|
||||
3. The service validates issuer, audience, signature, expiration,
|
||||
subject, tenant claim, and assurance evidence.
|
||||
4. The service builds a flex-auth request with the protected-system id,
|
||||
resource, action set, requested TTL, tenant, actor, and context.
|
||||
5. flex-auth evaluates policy through its standalone evaluator or a
|
||||
delegated PDP such as Topaz.
|
||||
6. If denied, the service returns a deny envelope with a stable reason
|
||||
code and audit correlation id.
|
||||
7. If allowed, the service exchanges the approved request with the
|
||||
backend or OpenBao-assisted broker path.
|
||||
8. The service returns normalized temporary credentials and records
|
||||
identity, policy, backend, lease, and audit metadata.
|
||||
|
||||
## Resource Model
|
||||
|
||||
Every object-storage resource belongs to a protected system and tenant.
|
||||
|
||||
Suggested identifiers:
|
||||
|
||||
```text
|
||||
protected_system:object-storage:artifact-store-prod
|
||||
tenant:platform
|
||||
tenant:coulomb
|
||||
|
||||
bucket:artifact-store-prod
|
||||
prefix:tenant/coulomb/packages/
|
||||
object:tenant/coulomb/packages/<digest>
|
||||
```
|
||||
|
||||
The protected-system id names the storage integration boundary, not just
|
||||
the backend product. For example, a MinIO tenant and an AWS bucket used
|
||||
by the same application should still be distinct protected systems if
|
||||
their trust, audit, or policy lifecycle differs.
|
||||
|
||||
## flex-auth Vocabulary
|
||||
|
||||
| Resource | Example | Notes |
|
||||
| --- | --- | --- |
|
||||
| protected system | `object-storage:artifact-store-prod` | Required in every decision |
|
||||
| bucket | `bucket:artifact-store-prod` | Coarse storage boundary |
|
||||
| prefix | `prefix:tenant/coulomb/packages/` | Preferred grant boundary for workloads |
|
||||
| object | `object:tenant/coulomb/packages/a.tar.zst` | Use for exceptional single-object decisions |
|
||||
|
||||
Canonical action names:
|
||||
|
||||
| Action | Meaning |
|
||||
| --- | --- |
|
||||
| `s3:GetObject` | Read object data |
|
||||
| `s3:PutObject` | Create or replace object data |
|
||||
| `s3:DeleteObject` | Delete object data |
|
||||
| `s3:ListBucket` | List bucket or prefix contents |
|
||||
| `s3:GetObjectAttributes` | Read metadata, checksums, or object attributes |
|
||||
| `s3:AbortMultipartUpload` | Abort multipart state |
|
||||
| `s3:CreateMultipartUpload` | Start multipart upload |
|
||||
| `s3:UploadPart` | Upload multipart chunk |
|
||||
| `s3:CompleteMultipartUpload` | Complete multipart upload |
|
||||
|
||||
Required decision inputs:
|
||||
|
||||
- subject id, subject type, issuer, audience, and tenant;
|
||||
- protected-system id;
|
||||
- bucket and prefix or object;
|
||||
- requested action set;
|
||||
- requested TTL;
|
||||
- assurance level and MFA evidence where privileged or destructive
|
||||
actions are requested;
|
||||
- workload identity evidence for service or agent callers;
|
||||
- request purpose and audit correlation id when available.
|
||||
|
||||
Required decision outputs:
|
||||
|
||||
- allow or deny;
|
||||
- maximum TTL;
|
||||
- permitted actions;
|
||||
- permitted bucket and prefix/object scope;
|
||||
- obligations such as read-only, checksum-required, write-once, or
|
||||
audit-detail-required;
|
||||
- deny reason code;
|
||||
- explanation/audit correlation id;
|
||||
- backend exchange hint where policy deliberately restricts backend use.
|
||||
|
||||
TTL policy:
|
||||
|
||||
- default interactive TTL: 15 minutes;
|
||||
- default workload TTL: 30 minutes;
|
||||
- maximum normal TTL: 1 hour;
|
||||
- longer TTLs require explicit policy and should not exceed backend
|
||||
limits;
|
||||
- destructive or platform-scoped credentials should use shorter TTLs and
|
||||
MFA or dual-control obligations.
|
||||
|
||||
## IAM Profile Requirements
|
||||
|
||||
Accepted issuers:
|
||||
|
||||
- key-cape lightweight mode for local, sandbox, and small deployments;
|
||||
- Keycloak expanded mode for production and enterprise federation;
|
||||
- local-identity only for development or bootstrap contexts explicitly
|
||||
marked non-production.
|
||||
|
||||
Required token properties:
|
||||
|
||||
- `iss` matches an approved NetKingdom issuer;
|
||||
- `aud` targets the credential-vending service or an approved backend
|
||||
exchange audience;
|
||||
- `sub` is stable for the principal;
|
||||
- `exp`, `nbf`, and `iat` are present and within skew tolerance;
|
||||
- `tenant` or equivalent tenant mapping is present for tenant-scoped
|
||||
requests;
|
||||
- service accounts and agents are distinguishable from humans;
|
||||
- assurance/MFA claims are present when policy needs them;
|
||||
- groups or roles are mapped through IAM Profile semantics, not
|
||||
provider-specific bucket policy.
|
||||
|
||||
Local-dev restrictions:
|
||||
|
||||
- local issuers must only be accepted by explicitly configured dev
|
||||
vending instances;
|
||||
- local issuer tokens must not be trusted by production backends;
|
||||
- credentials minted from local issuers must be restricted to local or
|
||||
sandbox object stores.
|
||||
|
||||
Emergency principals:
|
||||
|
||||
- break-glass use is platform-control-plane access, not tenant access;
|
||||
- emergency credentials must be short-lived where possible;
|
||||
- every emergency vending event requires a post-event review record.
|
||||
|
||||
## Backend Assessment
|
||||
|
||||
| Backend | Temporary credential path | NetKingdom stance |
|
||||
| --- | --- | --- |
|
||||
| AWS S3 | AWS STS `AssumeRoleWithWebIdentity` returns access key id, secret access key, session token, and expiration | Best fit for AWS-native deployments. Use IAM OIDC provider and role trust policies, with flex-auth deciding before exchange. |
|
||||
| Ceph RGW | RGW implements a subset of STS, including `AssumeRoleWithWebIdentity` for OIDC-backed temporary credentials | Good fit for self-hosted S3-compatible storage when RGW IAM/STS maturity is acceptable for the deployment. |
|
||||
| MinIO/AIStor | MinIO STS supports `AssumeRoleWithWebIdentity` with OIDC JWTs and AWS-like response semantics | Strong fit for lightweight/self-hosted deployments if session-token support is wired through consumers. |
|
||||
| Cloudflare R2 | R2 temporary credentials are created through the R2 Temporary Credentials API or local signing with parent access material | Use a backend-specific broker. Store parent material in OpenBao; do not expose parent credentials to workloads. |
|
||||
| OpenBao | Can store parent credentials, broker dynamic material, record leases, and audit secret access | Runtime secret infrastructure and audit point, not the canonical object-storage authorization engine. |
|
||||
|
||||
Decision summary: prefer provider-native temporary credentials when the
|
||||
backend has a mature STS or temporary-credentials API. Keep the
|
||||
NetKingdom interface stable and normalize backend differences in the
|
||||
credential-vending service.
|
||||
|
||||
## OpenBao Role
|
||||
|
||||
OpenBao participates in credential vending only after flex-auth approval.
|
||||
Allowed OpenBao responsibilities:
|
||||
|
||||
- store backend parent credentials for Cloudflare R2 or other APIs that
|
||||
need privileged signing material;
|
||||
- store broker configuration and backend endpoint metadata;
|
||||
- issue or lease dynamic credentials where a supported backend plugin or
|
||||
controlled broker path exists;
|
||||
- provide audit records for parent credential access and broker
|
||||
operations;
|
||||
- deliver credential-vending service configuration through Kubernetes
|
||||
auth, CSI, or External Secrets Operator.
|
||||
|
||||
Prohibited OpenBao responsibilities:
|
||||
|
||||
- deciding whether a tenant may access a bucket or prefix;
|
||||
- storing tenant policy as the canonical object-storage authorization
|
||||
model;
|
||||
- exposing platform mounts, root tokens, unseal/recovery material, or
|
||||
parent credentials to tenants;
|
||||
- bypassing flex-auth because a backend secret path is readable.
|
||||
|
||||
## Interface Prototype
|
||||
|
||||
HTTP request:
|
||||
|
||||
```http
|
||||
POST /v1/object-storage/credentials
|
||||
Authorization: Bearer <iam-profile-token>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"protected_system_id": "object-storage:artifact-store-prod",
|
||||
"tenant_id": "tenant:coulomb",
|
||||
"bucket": "artifact-store-prod",
|
||||
"prefix": "tenant/coulomb/packages/",
|
||||
"actions": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"],
|
||||
"ttl_seconds": 1800,
|
||||
"purpose": "artifact-store package upload",
|
||||
"correlation_id": "01JYNETKINGDOMSTS000000000001"
|
||||
}
|
||||
```
|
||||
|
||||
Normalized response:
|
||||
|
||||
```json
|
||||
{
|
||||
"credentials": {
|
||||
"access_key_id": "AKIA...",
|
||||
"secret_access_key": "redacted-by-client-logging",
|
||||
"session_token": "token...",
|
||||
"expiration": "2026-05-18T16:45:00Z"
|
||||
},
|
||||
"scope": {
|
||||
"protected_system_id": "object-storage:artifact-store-prod",
|
||||
"tenant_id": "tenant:coulomb",
|
||||
"bucket": "artifact-store-prod",
|
||||
"prefix": "tenant/coulomb/packages/",
|
||||
"actions": ["s3:GetObject", "s3:PutObject", "s3:ListBucket"]
|
||||
},
|
||||
"lease": {
|
||||
"ttl_seconds": 1800,
|
||||
"renewable": false,
|
||||
"backend": "minio-assume-role-with-web-identity",
|
||||
"openbao_lease_id": null
|
||||
},
|
||||
"decision": {
|
||||
"decision_id": "dec_01JYNETKINGDOMSTS000000000001",
|
||||
"policy_package": "object-storage-artifact-store-prod@2026-05-18",
|
||||
"obligations": ["checksum-required"],
|
||||
"audit_correlation_id": "01JYNETKINGDOMSTS000000000001"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Deny response:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "credential_denied",
|
||||
"reason_code": "prefix_not_registered_for_tenant",
|
||||
"decision_id": "dec_01JYNETKINGDOMSTS000000000002",
|
||||
"audit_correlation_id": "01JYNETKINGDOMSTS000000000002"
|
||||
}
|
||||
```
|
||||
|
||||
`credential_process` output for SDK consumers:
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": 1,
|
||||
"AccessKeyId": "AKIA...",
|
||||
"SecretAccessKey": "...",
|
||||
"SessionToken": "...",
|
||||
"Expiration": "2026-05-18T16:45:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
CLI shape:
|
||||
|
||||
```bash
|
||||
netkingdom-object-creds vend \
|
||||
--protected-system object-storage:artifact-store-prod \
|
||||
--tenant tenant:coulomb \
|
||||
--bucket artifact-store-prod \
|
||||
--prefix tenant/coulomb/packages/ \
|
||||
--action s3:GetObject \
|
||||
--action s3:PutObject \
|
||||
--ttl 1800 \
|
||||
--credential-process
|
||||
```
|
||||
|
||||
## Audit Event
|
||||
|
||||
Each successful or denied request should emit one canonical audit event:
|
||||
|
||||
```json
|
||||
{
|
||||
"event_type": "object_storage_credential_vending",
|
||||
"outcome": "allowed",
|
||||
"actor": {
|
||||
"subject": "service:artifact-store",
|
||||
"issuer": "https://kc.coulomb.social",
|
||||
"tenant": "tenant:coulomb",
|
||||
"assurance": "workload"
|
||||
},
|
||||
"request": {
|
||||
"protected_system_id": "object-storage:artifact-store-prod",
|
||||
"bucket": "artifact-store-prod",
|
||||
"prefix": "tenant/coulomb/packages/",
|
||||
"actions": ["s3:GetObject", "s3:PutObject"],
|
||||
"ttl_seconds": 1800
|
||||
},
|
||||
"decision": {
|
||||
"decision_id": "dec_01JYNETKINGDOMSTS000000000001",
|
||||
"policy_package": "object-storage-artifact-store-prod@2026-05-18"
|
||||
},
|
||||
"backend": {
|
||||
"type": "minio-assume-role-with-web-identity",
|
||||
"credential_expiration": "2026-05-18T16:45:00Z",
|
||||
"openbao_lease_id": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
OpenBao audit events should be correlated when OpenBao parent material,
|
||||
broker config, dynamic secret engines, or delivery paths are used.
|
||||
|
||||
## Consumer Guidance
|
||||
|
||||
### artifact-store
|
||||
|
||||
`artifact-store` should consume temporary credentials without owning the
|
||||
vending authority.
|
||||
|
||||
Required consumer support:
|
||||
|
||||
- `AWS_ACCESS_KEY_ID`;
|
||||
- `AWS_SECRET_ACCESS_KEY`;
|
||||
- `AWS_SESSION_TOKEN`;
|
||||
- credential expiration awareness;
|
||||
- refresh before expiration, preferably with jitter;
|
||||
- env, file, sidecar, controller, or `credential_process` delivery.
|
||||
|
||||
The existing static bridge can remain transitional:
|
||||
|
||||
```bash
|
||||
export ARTIFACTSTORE_S3_ACCESS_KEY_REF=file:/run/secrets/artifactstore/s3-access-key
|
||||
export ARTIFACTSTORE_S3_SECRET_KEY_REF=file:/run/secrets/artifactstore/s3-secret-key
|
||||
```
|
||||
|
||||
Temporary credentials require either a session-token ref or a refresh
|
||||
pattern that updates all three credential values atomically:
|
||||
|
||||
```bash
|
||||
export ARTIFACTSTORE_S3_ACCESS_KEY_REF=file:/run/secrets/artifactstore/aws-access-key-id
|
||||
export ARTIFACTSTORE_S3_SECRET_KEY_REF=file:/run/secrets/artifactstore/aws-secret-access-key
|
||||
export ARTIFACTSTORE_S3_SESSION_TOKEN_REF=file:/run/secrets/artifactstore/aws-session-token
|
||||
export ARTIFACTSTORE_S3_CREDENTIAL_EXPIRATION_REF=file:/run/secrets/artifactstore/expiration
|
||||
```
|
||||
|
||||
Recommended deployment patterns:
|
||||
|
||||
- CLI or SDK `credential_process` for developer and batch use;
|
||||
- sidecar refresh process for pods that cannot call the vending API
|
||||
directly;
|
||||
- controller plus mounted files when platform operators need centralized
|
||||
refresh and audit;
|
||||
- direct vending API call only when the workload can protect its IAM
|
||||
token and handle refresh safely.
|
||||
|
||||
### Other S3 Consumers
|
||||
|
||||
Consumers must support the session token. Access-key/secret-key-only
|
||||
clients are limited to transitional static credentials and should not be
|
||||
used for production tenant workloads.
|
||||
|
||||
Prohibited patterns:
|
||||
|
||||
- object-store root credentials in application pods;
|
||||
- long-lived tenant access keys for normal workload traffic;
|
||||
- bucket policy managed by application repos as the source of truth;
|
||||
- storing parent R2/API credentials in tenant namespaces;
|
||||
- ignoring credential expiration and retrying indefinitely with expired
|
||||
credentials;
|
||||
- accepting local-identity tokens in production.
|
||||
|
||||
## Failure Modes
|
||||
|
||||
| Failure | Expected behavior |
|
||||
| --- | --- |
|
||||
| IAM token invalid or wrong audience | Deny before policy evaluation; emit audit event |
|
||||
| Tenant missing or mismatched | Deny with `tenant_scope_missing` or `tenant_mismatch` |
|
||||
| Prefix not registered | Deny with `prefix_not_registered_for_tenant` |
|
||||
| TTL too long | Reduce to policy maximum or deny, depending on policy |
|
||||
| flex-auth or Topaz unavailable | Fail closed except for explicitly documented emergency platform workflows |
|
||||
| Backend STS unavailable | Do not mint credentials; return retryable backend error |
|
||||
| OpenBao unavailable | Fail if parent material or broker config requires OpenBao; otherwise continue only for backend paths that do not depend on it |
|
||||
| Audit sink unavailable | Deny privileged/platform-scoped requests; allow low-risk tenant requests only if policy permits buffered audit |
|
||||
| Consumer refresh fails | Stop writes before expiration; retry vending with backoff; never fall back to root credentials |
|
||||
|
||||
## Readiness Checks
|
||||
|
||||
- IAM Profile token validation test passes for key-cape or Keycloak.
|
||||
- flex-auth has policy packages for platform and tenant scopes.
|
||||
- Topaz policy load and health are verified where delegated PDP is used.
|
||||
- Backend-specific STS or temporary credential path returns credentials
|
||||
with session token and expiration.
|
||||
- OpenBao parent credential access, lease metadata, and audit correlation
|
||||
work where OpenBao is in the path.
|
||||
- artifact-store or the consumer can refresh all credential fields before
|
||||
expiration.
|
||||
- Deny paths produce stable reason codes and audit records.
|
||||
- Break-glass operation is documented and post-event review is required.
|
||||
|
||||
## References
|
||||
|
||||
- [AWS STS AssumeRoleWithWebIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html)
|
||||
- [Ceph RGW STS](https://docs.ceph.com/en/latest/radosgw/STS/)
|
||||
- [MinIO AssumeRoleWithWebIdentity](https://min.io/docs/minio/linux/developers/security-token-service/AssumeRoleWithWebIdentity.html)
|
||||
- [Cloudflare R2 Temporary Credentials API](https://developers.cloudflare.com/api/resources/r2/subresources/temporary_credentials/)
|
||||
- [Cloudflare R2 temporary credential example](https://developers.cloudflare.com/r2/examples/authenticate-r2-temp-credentials/)
|
||||
@@ -0,0 +1,402 @@
|
||||
# Platform Identity and Security Architecture
|
||||
|
||||
Status: implemented architecture baseline for NetKingdom/Railiance/Coulomb
|
||||
Date: 2026-05-18
|
||||
|
||||
## Purpose
|
||||
|
||||
This document captures the production-oriented identity, authorization,
|
||||
MFA, credential, and bootstrap architecture for the platform we are
|
||||
building. It deliberately treats Coulomb as the first internal tenant and
|
||||
reference workload, not as the platform itself.
|
||||
|
||||
The architecture must be recursive: the same platform that protects
|
||||
future tenants also protects the services and repositories used to build
|
||||
and operate the platform. That recursion is useful, but it is also where
|
||||
many security designs accidentally collapse into self-administering root
|
||||
power. This document exists to prevent that.
|
||||
|
||||
## Core Model
|
||||
|
||||
```text
|
||||
Bootstrap plane
|
||||
establishes initial trust before normal platform services exist
|
||||
|
||||
Platform control plane
|
||||
operates identity, MFA, secrets, policy, audit, and authorization
|
||||
|
||||
Tenant planes
|
||||
run Coulomb and future customer/project/domain workloads
|
||||
```
|
||||
|
||||
Coulomb is the first internal tenant. It is also the reference tenant that
|
||||
helps validate the platform. It must not become the platform root of
|
||||
trust merely because it is first.
|
||||
|
||||
## Planes
|
||||
|
||||
### Bootstrap Plane
|
||||
|
||||
The bootstrap plane exists before the full platform is alive. It owns the
|
||||
minimal authority needed to create and recover the control plane.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- host provisioning and hardening
|
||||
- root age/SOPS material and emergency bundles
|
||||
- initial cluster access
|
||||
- initial identity service deployment
|
||||
- initial secret injection
|
||||
- break-glass recovery
|
||||
- transition to managed runtime authority
|
||||
|
||||
Owned primarily by `railiance-infra`, `railiance-cluster`, and the
|
||||
credential bootstrap work in `net-kingdom`.
|
||||
|
||||
### Platform Control Plane
|
||||
|
||||
The platform control plane owns shared security services.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- NetKingdom IAM Profile
|
||||
- lightweight identity mode through key-cape
|
||||
- expanded identity mode through Keycloak
|
||||
- MFA/token lifecycle through privacyIDEA where applicable
|
||||
- canonical authorization through flex-auth
|
||||
- delegated authorization runtime through Topaz first, with other PDPs as
|
||||
adapters
|
||||
- runtime secret authority through OpenBao
|
||||
- audit and explanation records
|
||||
- platform service secrets, dynamic credentials, leases, and rotation
|
||||
|
||||
Owned conceptually by `net-kingdom`; deployed through the Railiance stack.
|
||||
|
||||
### Tenant Plane
|
||||
|
||||
Tenant planes are where workloads live. Coulomb is tenant zero/reference
|
||||
tenant; later tenants may be projects, customers, domains, sandboxes, or
|
||||
isolated deployments.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- protected services and repositories
|
||||
- tenant-owned resources
|
||||
- tenant-specific groups, policies, and service accounts
|
||||
- local enforcement of authorization decisions
|
||||
- workload audit events and diagnostics
|
||||
|
||||
Tenant administrators may manage their tenant resources. They must not be
|
||||
able to alter platform root trust, global identity configuration,
|
||||
platform break-glass material, or the policy pipeline that governs the
|
||||
platform itself.
|
||||
|
||||
## Component Responsibilities
|
||||
|
||||
| Component | Primary role | Must not become |
|
||||
| --- | --- | --- |
|
||||
| `net-kingdom` | canonical security architecture, IAM Profile, SSO/MFA, credential bootstrap decisions | a deployment repo for every stack layer |
|
||||
| `key-cape` | lightweight IAM implementation of the NetKingdom IAM Profile | a general-purpose IAM platform or authorization engine |
|
||||
| Keycloak | expanded-mode IAM and optional Keycloak Authorization Services adapter | the canonical model for all platform authorization |
|
||||
| privacyIDEA | MFA/token authority, especially in lightweight/key-cape mode | a policy decision point for application resources |
|
||||
| OpenBao | runtime platform secrets service, dynamic credential broker, lease/revocation point, and audit source for secret access | the bootstrap root of trust or an application-specific configuration store |
|
||||
| `flex-auth` | authorization control plane, CARING descriptors, policy packages, decision envelopes, audit/explain | an identity provider or backend-specific wrapper |
|
||||
| Topaz | first delegated authorization runtime/PDP for flex-auth | the platform control plane or identity provider |
|
||||
| Railiance repos | converged infrastructure, cluster, platform services, enablement, and app deployment | the source of security policy semantics |
|
||||
|
||||
## Identity Path
|
||||
|
||||
```text
|
||||
Human/service/agent principal
|
||||
|
|
||||
v
|
||||
NetKingdom IAM Profile
|
||||
|
|
||||
+-- lightweight mode: key-cape
|
||||
| Authelia + LLDAP + privacyIDEA
|
||||
|
|
||||
+-- expanded mode: Keycloak
|
||||
Keycloak + LDAP/Entra federation + MFA integration
|
||||
```
|
||||
|
||||
Applications depend on the IAM Profile, not on the concrete provider.
|
||||
key-cape is the lightweight profile implementation. Keycloak is the
|
||||
expanded-mode profile implementation. privacyIDEA provides MFA/token
|
||||
capabilities where the deployment mode uses it.
|
||||
|
||||
Identity answers: who is this actor, how was the actor authenticated,
|
||||
what coarse claims are asserted, and what assurance evidence exists?
|
||||
|
||||
Identity does not answer final resource-specific authorization.
|
||||
|
||||
## Authorization Path
|
||||
|
||||
```text
|
||||
Identity claims from IAM Profile
|
||||
|
|
||||
v
|
||||
flex-auth
|
||||
resource registry
|
||||
policy packages
|
||||
CARING descriptors
|
||||
decision/audit/explain envelope
|
||||
|
|
||||
+-- standalone evaluator
|
||||
+-- Topaz delegated PDP
|
||||
+-- optional Keycloak AuthZ adapter
|
||||
+-- future OpenFGA/SpiceDB/OPA/Cedar adapters
|
||||
|
|
||||
v
|
||||
Protected service enforcement
|
||||
```
|
||||
|
||||
Authorization answers: may this actor perform this action on this
|
||||
resource in this context, and what explanation/audit/CARING metadata
|
||||
supports that answer?
|
||||
|
||||
Protected services enforce decisions locally. flex-auth is the canonical
|
||||
policy and decision boundary; delegated PDPs are runtime implementations
|
||||
behind it.
|
||||
|
||||
## Secret And Credential Path
|
||||
|
||||
```text
|
||||
Bootstrap SOPS/age material
|
||||
|
|
||||
v
|
||||
OpenBao platform secrets service
|
||||
KV v2 platform configuration
|
||||
dynamic database credentials
|
||||
Kubernetes auth / workload identity
|
||||
future object-storage credential brokering
|
||||
audit devices and lease/revocation records
|
||||
|
|
||||
+-- direct OpenBao clients
|
||||
+-- External Secrets Operator / synced Kubernetes Secrets
|
||||
+-- CSI-mounted secrets where appropriate
|
||||
|
|
||||
v
|
||||
Platform and tenant workloads
|
||||
```
|
||||
|
||||
SOPS/age remains the bootstrap and Git-at-rest protection mechanism. It
|
||||
can create the initial cluster secrets and emergency recovery bundles, but
|
||||
it should not become the long-lived runtime authority for every workload
|
||||
secret.
|
||||
|
||||
OpenBao is the runtime platform secrets service once the control plane is
|
||||
alive. It owns secret leases, revocation, audit, dynamic credentials, and
|
||||
workload-facing secret delivery patterns. Workloads should receive scoped
|
||||
secrets or short-lived credentials, not platform-root material. Tenant
|
||||
administrators may manage tenant-scoped secrets through approved policy
|
||||
paths; they must not gain access to OpenBao root tokens, unseal keys,
|
||||
platform mounts, or global secret engine configuration.
|
||||
|
||||
OpenBao does not replace identity or authorization. NetKingdom IAM
|
||||
identifies actors and workloads; flex-auth decides whether a credential
|
||||
or secret request is allowed; OpenBao stores, issues, audits, and revokes
|
||||
the resulting secret material.
|
||||
|
||||
## Recursive Trust Rule
|
||||
|
||||
Normal tenant administration must never be sufficient to alter the
|
||||
platform root of trust.
|
||||
|
||||
This applies even when the tenant is Coulomb. Coulomb can be a tenant and
|
||||
a reference workload, but platform-root actions require platform control
|
||||
plane authority and appropriate bootstrap/break-glass safeguards.
|
||||
|
||||
Examples of platform-root actions:
|
||||
|
||||
- changing IAM Profile semantics
|
||||
- rotating root bootstrap keys
|
||||
- changing break-glass access
|
||||
- changing global MFA requirements
|
||||
- activating authorization policy that governs platform administration
|
||||
- changing flex-auth/Topaz policy import pipelines
|
||||
- changing OpenBao root tokens, unseal policy, platform mounts, or global
|
||||
auth methods
|
||||
- changing audit retention or tamper-evidence settings
|
||||
|
||||
## Tenant Model
|
||||
|
||||
Every protected resource should belong to a tenant or to the platform
|
||||
control plane.
|
||||
|
||||
Suggested identifiers:
|
||||
|
||||
```text
|
||||
tenant:platform # platform control plane resources
|
||||
tenant:coulomb # first internal/reference tenant
|
||||
tenant:sandbox:<name> # sandbox tenants
|
||||
tenant:customer:<name> # future customer tenants
|
||||
```
|
||||
|
||||
Tenant membership and platform membership are distinct. A subject may be
|
||||
an administrator in `tenant:coulomb` without being a platform operator.
|
||||
|
||||
CARING descriptors should explicitly identify scope and tenant when the
|
||||
access is tenant-scoped. Platform-scoped descriptors should be rare,
|
||||
audited, and usually condition-bound.
|
||||
|
||||
## Bootstrap To Runtime Transition
|
||||
|
||||
Production setup should move through explicit trust states:
|
||||
|
||||
1. **Bare host trust** - provisioned and verified by Railiance infra.
|
||||
2. **Cluster trust** - Kubernetes runtime exists and is verified.
|
||||
3. **Bootstrap secret trust** - age/SOPS and emergency bundles are
|
||||
established.
|
||||
4. **Bootstrap identity trust** - local/bootstrap identity can operate
|
||||
enough to install full identity services.
|
||||
5. **Runtime secret trust** - OpenBao is deployed, initialized, unsealed,
|
||||
audited, backed up, and ready to issue scoped secrets.
|
||||
6. **Runtime identity trust** - key-cape or Keycloak becomes the normal
|
||||
IAM Profile issuer.
|
||||
7. **Runtime authorization trust** - flex-auth and Topaz are initialized
|
||||
with platform and tenant policies.
|
||||
8. **Tenant onboarding trust** - Coulomb and later tenants register
|
||||
resources and receive scoped authority.
|
||||
|
||||
Each transition needs a verification check and a rollback/recovery path.
|
||||
|
||||
## Production Topology
|
||||
|
||||
For an initial production-capable Coulomb deployment:
|
||||
|
||||
```text
|
||||
railiance-infra
|
||||
host baseline, SSH, age keys, emergency material
|
||||
|
||||
railiance-cluster
|
||||
Kubernetes, ingress, cert-manager, network policy
|
||||
|
||||
railiance-platform
|
||||
OpenBao, PostgreSQL, object storage, platform service secret delivery
|
||||
key-cape or Keycloak
|
||||
privacyIDEA where used
|
||||
flex-auth
|
||||
Topaz
|
||||
|
||||
railiance-apps
|
||||
Coulomb services as tenant:coulomb workloads
|
||||
```
|
||||
|
||||
`net-kingdom` owns the architecture and standards. Railiance owns the
|
||||
converged deployment layers. Component repos own their implementation
|
||||
contracts.
|
||||
|
||||
## Orchestration Implication
|
||||
|
||||
A future orchestration repo may be justified, but only after the state
|
||||
machine is clear. It should not own resources directly. It should own
|
||||
safe sequencing across repos.
|
||||
|
||||
Possible responsibilities:
|
||||
|
||||
- verify Railiance preconditions
|
||||
- initialize credential bootstrap
|
||||
- deploy or validate identity services
|
||||
- deploy or validate flex-auth and Topaz
|
||||
- run IAM Profile conformance checks
|
||||
- run authorization conformance checks
|
||||
- produce a platform security readiness report
|
||||
|
||||
This orchestration layer should build on Railiance capabilities rather
|
||||
than bypassing the Railiance stack boundaries.
|
||||
|
||||
ADR-0007 records the current decision: keep orchestration in Railiance
|
||||
playbooks for now, with NetKingdom defining the trust-state model,
|
||||
readiness checks, OpenBao boundaries, and security semantics.
|
||||
|
||||
## flex-auth And Topaz Implications
|
||||
|
||||
flex-auth work must preserve the recursive boundary between platform
|
||||
control-plane resources and tenant resources.
|
||||
|
||||
Required implications:
|
||||
|
||||
- CARING descriptors must include scope and tenant metadata for
|
||||
tenant-scoped access, and must mark rare platform-scoped access
|
||||
explicitly.
|
||||
- Policy packages must distinguish `tenant:platform` policy from
|
||||
tenant-local packages such as `tenant:coulomb`.
|
||||
- Decision envelopes must carry subject, issuer, audience, tenant,
|
||||
protected-system id, resource, action, requested TTL where relevant,
|
||||
assurance evidence, obligations, deny reasons, and audit correlation
|
||||
ids.
|
||||
- Topaz is a delegated PDP runtime behind flex-auth. It must not become
|
||||
the canonical policy model, identity provider, or platform control
|
||||
plane.
|
||||
- Audit and explain records must be durable enough to reconstruct why a
|
||||
platform-root, secret, credential, or tenant-administration decision was
|
||||
allowed or denied.
|
||||
- Platform-root guardrails must deny tenant administrators the ability to
|
||||
alter IAM Profile semantics, OpenBao platform mounts/auth methods,
|
||||
flex-auth policy import pipelines, Topaz runtime configuration, or
|
||||
platform audit retention.
|
||||
|
||||
OpenBao secret access and dynamic credential requests follow the same
|
||||
authorization rule: identity proves the actor or workload, flex-auth
|
||||
decides whether the request is permitted, and OpenBao stores, issues,
|
||||
leases, audits, and revokes the secret material.
|
||||
|
||||
## Coulomb Tenant Onboarding Path
|
||||
|
||||
The first Coulomb tenant onboarding path should be repeatable before it
|
||||
becomes automated:
|
||||
|
||||
1. Register `tenant:coulomb` as a tenant distinct from
|
||||
`tenant:platform`.
|
||||
2. Map Coulomb human, service, and agent principals to IAM Profile claims
|
||||
with issuer, audience, subject, group, tenant, and assurance evidence.
|
||||
3. Register Coulomb protected systems and resources in flex-auth with
|
||||
stable protected-system ids.
|
||||
4. Import tenant-scoped policy packages and CARING descriptors for
|
||||
Coulomb resources.
|
||||
5. Initialize the delegated PDP runtime, starting with Topaz, using only
|
||||
the policy packages approved for the tenant and platform boundary.
|
||||
6. Provision Coulomb workload secret paths, Kubernetes auth roles, or
|
||||
delivery mechanisms in OpenBao without granting access to platform
|
||||
mounts, unseal/recovery material, or global auth configuration.
|
||||
7. Run audit readiness checks before admitting production traffic:
|
||||
identity issuance, flex-auth decision envelope, Topaz health,
|
||||
OpenBao audit event, workload enforcement event, and correlation id.
|
||||
|
||||
The onboarding path is complete when a Coulomb workload can authenticate,
|
||||
receive a scoped authorization decision, obtain only the allowed secret or
|
||||
short-lived credential, enforce the decision locally, and produce an
|
||||
auditable record without receiving platform-root authority.
|
||||
|
||||
## Production Readiness Checks
|
||||
|
||||
Before the security platform is production-ready, each trust state needs
|
||||
an explicit check:
|
||||
|
||||
| Area | Readiness check |
|
||||
| --- | --- |
|
||||
| MFA and identity | key-cape or Keycloak issues IAM Profile-compatible tokens; privacyIDEA or the selected MFA provider enforces required assurance for privileged actions |
|
||||
| Bootstrap and recovery | age/SOPS material, emergency bundle, and break-glass credentials are present, tested, and separated from tenant administration |
|
||||
| OpenBao runtime secrets | OpenBao is initialized, unsealed or auto-unsealed by the approved mechanism, backed up, audited, and using scoped auth methods and mounts |
|
||||
| Secret rotation | service, database, OpenBao-issued, and break-glass rotation paths have documented blast radius and verification steps |
|
||||
| flex-auth policy state | platform and tenant policy packages are versioned, reviewable, imported, and explainable |
|
||||
| Topaz runtime | delegated PDP health, data freshness, policy load status, and fail-closed behavior are verified |
|
||||
| Tenant onboarding | `tenant:coulomb` resources, claims, policies, OpenBao paths, and audit correlation are registered and tested |
|
||||
| Audit sink | identity, flex-auth, Topaz, OpenBao, Kubernetes, and workload audit records land in durable storage with restore/drill coverage |
|
||||
| Break-glass | emergency access works when normal identity is unavailable and produces a post-event review record |
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Where is the durable audit log stored for platform-root decisions?
|
||||
- Where are OpenBao audit logs durably shipped, and how are they included
|
||||
in tamper-evidence and restore drills?
|
||||
- Which actions require dual control or human confirmation?
|
||||
- How is break-glass use recorded when normal identity is unavailable?
|
||||
- Which workloads consume OpenBao directly, via External Secrets Operator,
|
||||
or via CSI-mounted secrets?
|
||||
- Which tenant metadata is required before a service can register
|
||||
resources with flex-auth?
|
||||
- When does the platform switch from key-cape lightweight mode to
|
||||
Keycloak expanded mode?
|
||||
- Does Topaz run centrally for the platform, per tenant, or per service
|
||||
for the first production deployment?
|
||||
@@ -0,0 +1,207 @@
|
||||
# OpenBao - Platform Secrets Service
|
||||
|
||||
**Chart:** `openbao/openbao`
|
||||
**Chart version:** `0.28.2`
|
||||
**App version:** `v2.5.3`
|
||||
**Namespace:** `openbao`
|
||||
**Managed by:** `railiance-platform` (S3)
|
||||
**Workplan:** `RAIL-PL-WP-0002`
|
||||
**Initial target:** Railiance01 (`92.205.62.239`)
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
S5 workloads / operators
|
||||
-> openbao.openbao.svc.cluster.local:8200
|
||||
-> openbao-0
|
||||
-> integrated Raft storage on local-path PVC
|
||||
-> audit storage PVC mounted at /openbao/audit
|
||||
```
|
||||
|
||||
- OpenBao is the canonical Railiance S3 secrets service.
|
||||
- SOPS/age remains the Git-at-rest bootstrap mechanism.
|
||||
- The first Railiance01 deployment is single-replica Raft, not true HA.
|
||||
- Public ingress is disabled. Operators use `kubectl exec` or port-forwarding.
|
||||
- TLS is disabled inside the pod listener for this internal-only bootstrap. Add
|
||||
cert-manager-backed internal TLS before exposing OpenBao beyond cluster-local
|
||||
traffic.
|
||||
|
||||
## Deployment
|
||||
|
||||
The official OpenBao project recommends the Helm chart for Kubernetes
|
||||
deployments and warns to run Helm with `--dry-run` before install or upgrade.
|
||||
|
||||
From a host with kubeconfig access:
|
||||
|
||||
```bash
|
||||
make openbao-dry-run
|
||||
make openbao-deploy
|
||||
make openbao-status
|
||||
```
|
||||
|
||||
On Railiance01 directly:
|
||||
|
||||
```bash
|
||||
cd ~/railiance-platform
|
||||
sudo env KUBECONFIG=/etc/rancher/k3s/k3s.yaml make openbao-dry-run
|
||||
sudo env KUBECONFIG=/etc/rancher/k3s/k3s.yaml make openbao-deploy
|
||||
sudo env KUBECONFIG=/etc/rancher/k3s/k3s.yaml make openbao-status
|
||||
```
|
||||
|
||||
If the repo is not present on Railiance01 yet, copy only the non-secret values
|
||||
file and run Helm directly:
|
||||
|
||||
```bash
|
||||
scp helm/openbao-values.yaml tegwick@92.205.62.239:/tmp/openbao-values.yaml
|
||||
ssh tegwick@92.205.62.239 \
|
||||
'sudo env KUBECONFIG=/etc/rancher/k3s/k3s.yaml helm upgrade --install openbao openbao/openbao \
|
||||
--version 0.28.2 \
|
||||
--namespace openbao \
|
||||
--create-namespace \
|
||||
-f /tmp/openbao-values.yaml \
|
||||
--dry-run'
|
||||
```
|
||||
|
||||
Repeat without `--dry-run` to deploy.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
kubectl get pods,svc,pvc -n openbao -o wide
|
||||
kubectl exec -n openbao openbao-0 -- bao status
|
||||
```
|
||||
|
||||
Expected immediately after install:
|
||||
|
||||
- `openbao-0` is Running.
|
||||
- `openbao`, `openbao-active`, `openbao-internal`, and `openbao-ui` services
|
||||
exist as cluster-internal services.
|
||||
- data and audit PVCs are Bound.
|
||||
- `bao status` reports `Initialized: false` and `Sealed: true`.
|
||||
|
||||
That state is intentional until the bootstrap ceremony is completed.
|
||||
|
||||
## Bootstrap Ceremony
|
||||
|
||||
Do not initialize OpenBao in a casual shell session. Initialization emits the
|
||||
unseal keys and initial root token. Treat this as a break-glass event.
|
||||
|
||||
Recommended ceremony:
|
||||
|
||||
1. Confirm the Railiance01 backup posture first.
|
||||
2. Prepare three human escrow recipients for unseal shares.
|
||||
3. Run initialization once:
|
||||
|
||||
```bash
|
||||
kubectl exec -n openbao openbao-0 -- \
|
||||
bao operator init -key-shares=3 -key-threshold=2
|
||||
```
|
||||
|
||||
4. Give each unseal share to its escrow owner through an out-of-band channel.
|
||||
5. Unseal with two shares:
|
||||
|
||||
```bash
|
||||
kubectl exec -n openbao openbao-0 -- bao operator unseal
|
||||
```
|
||||
|
||||
6. Log in with the initial root token only long enough to create durable admin
|
||||
auth, enable audit, and prepare policies.
|
||||
7. Revoke or tightly escrow the initial root token.
|
||||
|
||||
## Initial Configuration After Unseal
|
||||
|
||||
Enable file audit:
|
||||
|
||||
```bash
|
||||
kubectl exec -n openbao openbao-0 -- \
|
||||
bao audit enable file file_path=/openbao/audit/openbao-audit.log
|
||||
```
|
||||
|
||||
Enable the first KV v2 mount:
|
||||
|
||||
```bash
|
||||
kubectl exec -n openbao openbao-0 -- \
|
||||
bao secrets enable -path=platform kv-v2
|
||||
```
|
||||
|
||||
Kubernetes auth, database dynamic credentials, PKI, CSI, and External Secrets
|
||||
integration are follow-up tasks in `RAIL-PL-WP-0002`. Do not migrate live
|
||||
application secrets until those policies and restore drills are documented.
|
||||
|
||||
## Artifact-Store Object Storage Handoff
|
||||
|
||||
`artifact-store` is the consumer-facing artifact preservation service for
|
||||
generated outputs, evidence packages, reports, logs, snapshots, exports, and
|
||||
release artifacts. It already has an S3-compatible backend with `env:NAME` and
|
||||
`file:/mounted/path` credential references, plus an
|
||||
`artifactstore storage verify --backend s3` smoke path.
|
||||
|
||||
Railiance should avoid building a parallel object-storage client or credential
|
||||
vending flow in OpenBao. The ownership split is:
|
||||
|
||||
- `railiance-platform` / OpenBao owns bootstrap secret custody, policy, audit,
|
||||
break-glass access, and workload secret delivery.
|
||||
- `artifact-store` owns artifact package manifests, the S3 backend, storage
|
||||
verification, and whether temporary credentials require backend refresh
|
||||
support or a sidecar/controller.
|
||||
- `net-kingdom` owns the identity issuer and role-claim model if object storage
|
||||
adopts STS with `AssumeRoleWithWebIdentity`.
|
||||
|
||||
Initial static-credential bridge, before STS is proven:
|
||||
|
||||
1. Create a scoped object-store access key limited to the artifact-store bucket
|
||||
and prefix. Do not use object-store root credentials.
|
||||
2. Store the key pair in OpenBao under a platform-owned path such as
|
||||
`platform/object-storage/artifact-store`.
|
||||
3. Deliver the values to the artifact-store pod through CSI or External Secrets
|
||||
as mounted files.
|
||||
4. Configure artifact-store with file references:
|
||||
|
||||
```bash
|
||||
export ARTIFACTSTORE_S3_ACCESS_KEY_REF=file:/run/secrets/artifactstore/s3-access-key
|
||||
export ARTIFACTSTORE_S3_SECRET_KEY_REF=file:/run/secrets/artifactstore/s3-secret-key
|
||||
```
|
||||
|
||||
5. Verify from artifact-store:
|
||||
|
||||
```bash
|
||||
artifactstore storage verify --backend s3
|
||||
```
|
||||
|
||||
STS credential vending remains linked to
|
||||
`ARTIFACT-STORE-WP-0007 - MinIO Compatibility, MaxIO Fork Assessment, And STS
|
||||
Credential Vending`. If that workstream chooses MinIO-compatible
|
||||
`AssumeRoleWithWebIdentity`, OpenBao should not become the identity provider by
|
||||
default. Use the NetKingdom OIDC issuer for workload/user identity, map object
|
||||
storage roles and policies there, and keep OpenBao responsible for bootstrap,
|
||||
break-glass, audit, and delivery of any controller configuration.
|
||||
|
||||
Current artifact-store configuration exposes access key and secret key refs,
|
||||
but no session-token ref. `ARTIFACT-STORE-WP-0007-T004` must either add
|
||||
temporary-session-token support to the S3 backend or choose a sidecar/secret
|
||||
controller pattern that keeps refreshed credentials available through the
|
||||
existing env/file reference contract.
|
||||
|
||||
## Upgrade And Rollback
|
||||
|
||||
1. Read the OpenBao chart release notes.
|
||||
2. Update `OPENBAO_CHART_VERSION` in `Makefile`.
|
||||
3. Run `make openbao-dry-run`.
|
||||
4. Confirm current backup and audit log posture.
|
||||
5. Run `make openbao-deploy`.
|
||||
6. Run `make openbao-status`.
|
||||
|
||||
For rollback, run `helm rollback openbao <REVISION> -n openbao` on Railiance01
|
||||
and re-check `bao status`.
|
||||
|
||||
## Scaling To Three Nodes
|
||||
|
||||
When Railiance02 and Railiance03 join:
|
||||
|
||||
1. Move storage from `local-path` to distributed storage.
|
||||
2. Set `server.affinity` back to anti-affinity.
|
||||
3. Set `server.ha.replicas: 3`.
|
||||
4. Re-enable a PodDisruptionBudget.
|
||||
5. Run an unseal, failover, backup, and restore drill before migrating secrets.
|
||||
Reference in New Issue
Block a user