Skip to content

feat(oabctl): wire k8s secret refs into K8sDriver (slice 3d) - #100

Merged
brettchien merged 1 commit into
mainfrom
feat/k8s-driver-slice3d-secrets
Aug 23, 2026
Merged

feat(oabctl): wire k8s secret refs into K8sDriver (slice 3d)#100
brettchien merged 1 commit into
mainfrom
feat/k8s-driver-slice3d-secrets

Conversation

@brettchien

Copy link
Copy Markdown
Contributor

Summary

Sub-slice 3d of #97 (K8s driver — ADR #63 slice 3): k8s secret refs, wired into K8sDriver.

  • secrets::parse_k8s_secret_uri("k8s-secret://<secret-name>#<key>") — pure parsing, no API call (unlike aws-sm://, which resolves a logical secret-id to an ARN via DescribeSecret; a k8s Secret is referenced by name+key directly, kubelet resolves it at pod-start).
  • K8sDriver::build_deployment now emits env[].valueFrom.secretKeyRef for each spec.secrets entry, instead of the placeholder bail from feat(oabctl): K8sDriver skeleton — apply/scale/delete against a Deployment (slice 3b) #99.
  • Any value using a different scheme (an ECS aws-sm:// ref or raw ARN — e.g. copy-pasted from an ECS manifest) fails loudly at apply time with a clear message, rather than being silently ignored or mis-deployed.
  • The k8s Secret object itself must already exist in the target namespace — creating it is explicitly out of scope here, same non-creating shape aws-sm:// already has for ECS (it references a secret Secrets Manager already holds, never creates one). Who/what creates the Secret is create.rs-wizard-adjacent territory, tracked separately (already flagged as open in K8s driver (ADR #63 slice 3) — sub-slice tracking #97's 3a notes).

reject_unsupported() now only guards spec.bundleFrom (3c, still open) — secrets are no longer on that list.

Stacking note

Branched from #99 (3b). Diff will narrow once #98#99→this land in order.

Testing

cargo test -p oabctl (98/98, 6 new) + cargo clippy -p oabctl --all-targets -- -D warnings — clean, CARGO_PROFILE_DEV_DEBUG=0 as usual on this box.

Ref #97.

spec.secrets values for a k8s-runtime manifest must now be
k8s-secret://<secret-name>#<key> — parsed in secrets.rs (pure, no API call:
unlike aws-sm://, a k8s Secret is referenced by name+key directly, kubelet
resolves it at pod-start time) and wired into build_deployment as
env[].valueFrom.secretKeyRef. Any other scheme (an ECS aws-sm:// ref or raw
ARN left over from copy-pasting an ECS manifest) fails loudly at apply time
instead of silently mis-deploying — same "declare the contract, fail closed
on mismatch" shape the rest of this driver already uses.

The Secret object itself must already exist in the target namespace —
creating it is a separate concern, deliberately out of scope here (mirrors
aws-sm://, which likewise only *references* a secret Secrets Manager already
holds, never creates one).

reject_unsupported() now only guards spec.bundleFrom (3c, still open) —
secrets are no longer in that list.

6 new tests (2 in secrets.rs for the parser, 4 in k8s_driver.rs), 98/98
total green, clippy -D warnings clean.

Ref: studio#97 (K8s driver — ADR #63 slice 3, sub-slice tracking)
@brettchien
brettchien force-pushed the feat/k8s-driver-slice3d-secrets branch from e8b3ad5 to 6b1cde7 Compare August 23, 2026 17:11
@brettchien
brettchien merged commit d56e818 into main Aug 23, 2026
2 checks passed
brettchien added a commit that referenced this pull request Aug 23, 2026
…s.toml (slice 3f)

K8sFleetBinding/K8sFleetBindings, the k8s counterpart to the existing AWS
FleetBinding/FleetBindings: a fleet's context+namespace instead of
cluster+profile, resolve_binding_driver -> oabctl::K8sDriver instead of
resolve_binding_config -> aws_config::SdkConfig.

Deliberately a **separate file** (fleets-k8s.toml, $OAB_K8S_FLEETS_CONFIG),
not a second [k8s_fleet.*] table in the existing fleets.toml. Reason:
save_bindings_text/save_k8s_bindings_text are both whole-file verbatim
writes (the console's TOML editor round-trips exact text, comments and all).
Two tables sharing one file means saving either one from the UI would
silently clobber the other's edits on the next write -- concretely, editing
a k8s fleet in the console could wipe Brett's actual prod fleets.toml
([fleet.orca]/[fleet.mira], the ECS bindings that already gate real AWS
credential selection -- see the fleets-toml-binding incident history).
Separate files make that class of bug structurally impossible rather than
relying on a careful merge in the write path.

read_bindings_text/write_bindings_atomic are reused as-is for the k8s file
(they're already path+text generic, no AWS types) -- only the TOML-shaped
type being parsed differs.

Scope: backend config-schema + load/save only. The console UI panel that
actually lets an operator pick AWS-vs-k8s and edit fleets-k8s.toml is
frontend work, not attempted here.

Stacked on #100 (3d) -- resolve_binding_driver needs oabctl::K8sDriver,
which only exists on the unmerged 3a/3b branch chain.

8 new tests (23/23 total in studio-cp), clippy introduces no new warnings
(2 pre-existing ones elsewhere in studio-cp/studio-compose, untouched).

Ref: studio#97 (K8s driver — ADR #63 slice 3, sub-slice tracking)
brettchien added a commit that referenced this pull request Aug 23, 2026
…s.toml (slice 3f) (#102)

K8sFleetBinding/K8sFleetBindings, the k8s counterpart to the existing AWS
FleetBinding/FleetBindings: a fleet's context+namespace instead of
cluster+profile, resolve_binding_driver -> oabctl::K8sDriver instead of
resolve_binding_config -> aws_config::SdkConfig.

Deliberately a **separate file** (fleets-k8s.toml, $OAB_K8S_FLEETS_CONFIG),
not a second [k8s_fleet.*] table in the existing fleets.toml. Reason:
save_bindings_text/save_k8s_bindings_text are both whole-file verbatim
writes (the console's TOML editor round-trips exact text, comments and all).
Two tables sharing one file means saving either one from the UI would
silently clobber the other's edits on the next write -- concretely, editing
a k8s fleet in the console could wipe Brett's actual prod fleets.toml
([fleet.orca]/[fleet.mira], the ECS bindings that already gate real AWS
credential selection -- see the fleets-toml-binding incident history).
Separate files make that class of bug structurally impossible rather than
relying on a careful merge in the write path.

read_bindings_text/write_bindings_atomic are reused as-is for the k8s file
(they're already path+text generic, no AWS types) -- only the TOML-shaped
type being parsed differs.

Scope: backend config-schema + load/save only. The console UI panel that
actually lets an operator pick AWS-vs-k8s and edit fleets-k8s.toml is
frontend work, not attempted here.

Stacked on #100 (3d) -- resolve_binding_driver needs oabctl::K8sDriver,
which only exists on the unmerged 3a/3b branch chain.

8 new tests (23/23 total in studio-cp), clippy introduces no new warnings
(2 pre-existing ones elsewhere in studio-cp/studio-compose, untouched).

Ref: studio#97 (K8s driver — ADR #63 slice 3, sub-slice tracking)
brettchien added a commit that referenced this pull request Aug 23, 2026
…r kubeconfig contexts (slice 3e)

observe_k8s_identity(context) is the k8s counterpart to the existing AWS
observe_identity(aws_config) — same RuntimeContext struct, per ADR-19's
AWS-driver/k8s-driver field mapping table:

  principal  <- SelfSubjectReview username (authentication.k8s.io/v1,
                stable since k8s 1.28 — the literal API `kubectl auth
                whoami` calls; a live server round-trip, not a value read
                out of the kubeconfig file, matching how observe_identity
                uses a live STS GetCallerIdentity rather than trusting the
                configured profile)
  principal_kind <- "service-account" / "user" / "unknown", mirrors
                     principal_kind's role/user/unknown split
  scope      <- "{cluster}/{namespace}" from the kubeconfig context entry
  location   <- left empty: k8s has no first-class region/zone concept
                the way AWS does, so there's nothing honest to fill in
                (same "empty if unset" contract location already has)
  source     <- "kubeconfig context: <name>"
  caller_id  <- SelfSubjectReview's UserInfo.uid

context = None uses the kubeconfig's current-context, mirroring
K8sDriver::from_context's "ambient default, explicit override" shape.

Adds kube 0.99 + k8s-openapi 0.24 to studio-cp (same versions oabctl
already pulls in slice 3b). 1 new test (k8s_principal_kind), 18/18 total
green in studio-cp. clippy clean for this code specifically — studio-cp/
studio-compose already carry a few pre-existing warnings elsewhere in the
crate, untouched by this change, not part of CI's gate for these crates.

Not stacked on #98/#99/#100 — this only touches studio-cp, independent of
oabctl's driver work, so it branches from main directly.

Ref: studio#97 (K8s driver — ADR #63 slice 3, sub-slice tracking)
brettchien added a commit that referenced this pull request Aug 23, 2026
…r kubeconfig contexts (slice 3e) (#101)

observe_k8s_identity(context) is the k8s counterpart to the existing AWS
observe_identity(aws_config) — same RuntimeContext struct, per ADR-19's
AWS-driver/k8s-driver field mapping table:

  principal  <- SelfSubjectReview username (authentication.k8s.io/v1,
                stable since k8s 1.28 — the literal API `kubectl auth
                whoami` calls; a live server round-trip, not a value read
                out of the kubeconfig file, matching how observe_identity
                uses a live STS GetCallerIdentity rather than trusting the
                configured profile)
  principal_kind <- "service-account" / "user" / "unknown", mirrors
                     principal_kind's role/user/unknown split
  scope      <- "{cluster}/{namespace}" from the kubeconfig context entry
  location   <- left empty: k8s has no first-class region/zone concept
                the way AWS does, so there's nothing honest to fill in
                (same "empty if unset" contract location already has)
  source     <- "kubeconfig context: <name>"
  caller_id  <- SelfSubjectReview's UserInfo.uid

context = None uses the kubeconfig's current-context, mirroring
K8sDriver::from_context's "ambient default, explicit override" shape.

Adds kube 0.99 + k8s-openapi 0.24 to studio-cp (same versions oabctl
already pulls in slice 3b). 1 new test (k8s_principal_kind), 18/18 total
green in studio-cp. clippy clean for this code specifically — studio-cp/
studio-compose already carry a few pre-existing warnings elsewhere in the
crate, untouched by this change, not part of CI's gate for these crates.

Not stacked on #98/#99/#100 — this only touches studio-cp, independent of
oabctl's driver work, so it branches from main directly.

Ref: studio#97 (K8s driver — ADR #63 slice 3, sub-slice tracking)
@brettchien
brettchien deleted the feat/k8s-driver-slice3d-secrets branch August 23, 2026 17:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant