From e861f63513859d5240773ce72e162b303fa7b9e4 Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 14 Oct 2026 00:44:33 +0200 Subject: [PATCH] security: reserve platform IAM groups in service group operations Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a1346b-72a4-7d40-b8bd-8b8ca346cfa2 --- identity-provisioner/provisioner.py | 7 ++--- .../tests/test_platform_group_boundary.py | 27 +++++++++++++++++++ ...-bootstrap-secret-free-recovery-handoff.md | 13 +++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 identity-provisioner/tests/test_platform_group_boundary.py diff --git a/identity-provisioner/provisioner.py b/identity-provisioner/provisioner.py index 1ae6d54..d97b409 100644 --- a/identity-provisioner/provisioner.py +++ b/identity-provisioner/provisioner.py @@ -425,7 +425,7 @@ def _discard(exc: BaseException) -> None: SERVICE_GROUP = re.compile(r"[a-z][a-z0-9-]{1,62}") -RESERVED_GROUP_PREFIXES = ("tenant", "netkingdom-", "lldap_") +RESERVED_GROUP_PREFIXES = ("tenant", "netkingdom-", "net-kingdom-", "lldap_") DIRECTORY_USERNAME = re.compile(r"[a-z][a-z0-9._-]{0,31}") @@ -433,8 +433,9 @@ def _service_group_request(payload: dict[str, Any]) -> tuple[list[str], dict[str """Validate a service-access group request before anything is changed. Service-access groups gate sign-in to an internal service (SecurityCaseType - oidc-browser-relying-party). Tenant, platform-suspension and LLDAP admin - groups are reserved and can never be touched through this path. + oidc-browser-relying-party). Tenant, platform identity/administration, + platform-suspension and LLDAP admin groups are reserved and can never be + touched through this path. """ _required(payload, "groups", "idempotency_key", "correlation_id") groups = payload["groups"] diff --git a/identity-provisioner/tests/test_platform_group_boundary.py b/identity-provisioner/tests/test_platform_group_boundary.py new file mode 100644 index 0000000..65dbf9c --- /dev/null +++ b/identity-provisioner/tests/test_platform_group_boundary.py @@ -0,0 +1,27 @@ +"""Service group operations must never reach platform IAM groups.""" +from unittest.mock import Mock + +import pytest + +from provisioner import LLDAPProvisioner, dispatch + + +@pytest.mark.parametrize("path", ["/v1/groups/ensure", "/v1/groups/revoke"]) +@pytest.mark.parametrize("group", [ + "net-kingdom-admins", "net-kingdom-users", "net-kingdom-future-role", +]) +def test_platform_groups_refused_before_directory_login(path, group): + provider = LLDAPProvisioner( + base_url="https://directory.invalid", admin_password="synthetic-fixture", + ) + provider._login = Mock(side_effect=AssertionError("must not contact directory")) + payload = { + "groups": ["activity-core-operators", group], + "members": {group: ["agent-codex"]}, + "idempotency_key": "platform-boundary-test", + "correlation_id": "source-test", + "delete_if_empty": True, + } + with pytest.raises(ValueError, match="reserved"): + dispatch(provider, path, payload) + provider._login.assert_not_called() diff --git a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md index 8dc8e52..61713a5 100644 --- a/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md +++ b/workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md @@ -317,6 +317,19 @@ verification repair (only stale lifecycle guidance changed in two of them). Incident cutover helpers, the full caller/root-output inventory and T03 remain open. T02 stays progress; no workplan closure is claimed. +2026-10-14 group-provider boundary follow-up: source review before reusing +service-group APIs reproduced acceptance of `net-kingdom-admins` and +`net-kingdom-users`. The reserved prefix covered `netkingdom-` (suspension) but +omitted the actual hyphenated platform namespace. Both ensure and revoke now +reject `net-kingdom-` before directory login, including mixed service/platform +requests and delete-if-empty. Six new regressions fail on prior source; provider +suite and source hash evidence: Custodian +`docs/evidence/2026-10-14-netkingdom-security/platform-group-boundary.json`. +This is a provider source repair, not deployed enforcement or evidence of past +exploitation. The existing service-group behavior and tenant lifecycle remain +covered by their tests. Deploy/admit this source through the existing owner path +before treating the live boundary as fixed; native enforcement remains in T03. + ## Verify owner-approved recovery and current native callers ```task