fix: scope API secrets access to tenancy namespaces#618
Open
mgrzybek wants to merge 6 commits into
Open
Conversation
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.
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Finding
API ClusterRole grants cluster-wide
get/list/create/…/deleteonsecretsRoot cause
The ClusterRole bound to the API service account granted
list,get,create,update,patch, anddeleteon secrets cluster-wide. Combined withcreateonnamespaces, 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 thesecretsrule entirely; addedget/create/patchonrolesandrolebindings(needed for the bootstrap below)chart/templates/api/deployment.yaml: always injectAZIMUTH_SA_NAMEandAZIMUTH_SA_NAMESPACEvia the Kubernetes downward APIapi/azimuth/utils.py:ensure_namespace()now callsensure_secrets_rbac(), which creates anazimuth-api-secretsRole and RoleBinding scoped to the tenancy namespace — granting the API SA the same verbs as before but only within that namespaceLimitation
Pre-existing tenancy namespaces will not have the Role/RoleBinding until the next
create_clustercall triggersensure_namespace. OIDCcredential()calls on those namespaces will fail with 403 until then. This resolves on first user operation.