Skip to content

fix: scope API secrets access to tenancy namespaces#618

Open
mgrzybek wants to merge 6 commits into
masterfrom
fix/h3-scope-secrets-rbac
Open

fix: scope API secrets access to tenancy namespaces#618
mgrzybek wants to merge 6 commits into
masterfrom
fix/h3-scope-secrets-rbac

Conversation

@mgrzybek

@mgrzybek mgrzybek commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Finding

API ClusterRole grants cluster-wide get/list/create/…/delete on secrets

Root cause

The ClusterRole bound to the API service account granted list, get, create, update, patch, and delete on secrets cluster-wide. Combined with create on namespaces, this gave the API pod an effective full-cluster secret exfiltration path (any secret in any namespace could be listed and read).

All secret operations in the Python code are scoped to per-tenancy namespaces (az-{tenancy}), so cluster-wide access was never necessary.

Changes

  • chart/templates/api/clusterrole.yaml: removed the secrets rule entirely; added get/create/patch on roles and rolebindings (needed for the bootstrap below)
  • chart/templates/api/deployment.yaml: always inject AZIMUTH_SA_NAME and AZIMUTH_SA_NAMESPACE via the Kubernetes downward API
  • api/azimuth/utils.py: ensure_namespace() now calls ensure_secrets_rbac(), which creates an azimuth-api-secrets Role and RoleBinding scoped to the tenancy namespace — granting the API SA the same verbs as before but only within that namespace

Limitation

Pre-existing tenancy namespaces will not have the Role/RoleBinding until the next create_cluster call triggers ensure_namespace. OIDC credential() calls on those namespaces will fail with 403 until then. This resolves on first user operation.

mgrzybek added 3 commits June 18, 2026 16:34
The API ClusterRole granted cluster-wide list/get/create/update/patch/delete
on secrets. Combined with create on namespaces, this was an effective
full-cluster secret exfiltration path.

Secrets are now governed by a namespaced Role + RoleBinding created per
tenancy namespace. When ensure_namespace() bootstraps a tenancy namespace it
also creates an "azimuth-api-secrets" Role and RoleBinding scoped to that
namespace. The API service account identity is supplied via the Kubernetes
downward API (AZIMUTH_SA_NAME / AZIMUTH_SA_NAMESPACE env vars added to the
Deployment). The ClusterRole no longer contains any secrets rule; instead it
gains get/create/patch on roles and rolebindings so the bootstrap can run.
@mgrzybek mgrzybek requested a review from a team as a code owner June 22, 2026 13:33
@mgrzybek mgrzybek changed the title fix: scope API secrets access to tenancy namespaces (H3) fix: scope API secrets access to tenancy namespaces Jun 22, 2026
mgrzybek added 3 commits June 22, 2026 16:04
Signed-off-by: Mathieu Grzybek <mathieu@stackhpc.com>
…ndling

The API SA could not create the per-namespace secrets Role because
Kubernetes escalation-prevention blocks granting permissions the SA
does not already hold. Missing `bind` caused the same rejection for
the RoleBinding.

Also convert unhandled RBAC ApiErrors in the CRD driver to typed
CommunicationError so views return JSON instead of a raw HTML 500,
and add explicit 403 messages in ensure_secrets_rbac pointing to the
missing ClusterRole verbs.

Signed-off-by: Mathieu Grzybek <mathieu@stackhpc.com>
Signed-off-by: Mathieu Grzybek <mathieu@stackhpc.com>
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