# ============================================================================= # domain-manager-policy.yaml -- Keystone policy override (SCS Domain Manager) # Charmed OpenStack Caracal 2024.1 -- OLD-STYLE-DEFAULTS aligned # ============================================================================= # PROVENANCE (do not strip): # - Domain-manager BRANCHES: adapted from the canonical SCS reference # SovereignCloudStack/standards, scs-0302-w1-domain-manager-implementation-notes # (the 2024.1-and-below transitional policy implementation). # - FALLTHROUGH defaults: reproduced VERBATIM from THIS deployment's live policy # (`oslopolicy-policy-generator --namespace keystone` on keystone/leader, # captured 2026-06-24). The cloud runs OLD-STYLE policy (enforce_scope and # enforce_new_defaults are forced FALSE by the Canonical charm), so each # overridden rule reproduces the live OLD-STYLE default and PREPENDS the # manager branch. NO new-style (system_scope:all) rules are introduced. # # WHY NO base_* BLOCK (improvement over the SCS template): # This overlay does NOT redefine keystone's helper rules (cloud_admin, # admin_and_matching_*, owner, domain_admin_for_grants, admin_on_*_filter, ...). # Those remain keystone CODE DEFAULTS and are referenced by name. Each overridden # rule = (manager branch) OR (the live default string, verbatim). This is # behavior-preserving by construction for every non-manager actor, avoids copying # helper bodies (which would risk drift), and preserves cloud_admin's baked-in # admin domain/project IDs untouched. The `or rule:admin_required` tail from the # SCS NEW-STYLE template is deliberately OMITTED -- the live defaults gate on # cloud_admin (narrower than admin_required); appending admin_required would # WIDEN access beyond the current default. # # DELIVERY (use-policyd-override already true): # zip overrides.zip domain-manager-policy.yaml # juju attach-resource keystone policyd-override=overrides.zip # -> /etc/keystone/policy.d/domain-manager-policy.yaml ; keystone restarts. # juju status: "PO:" = applied; "PO (broken):" = YAML unparseable (atomic discard). # # *** HARD WARNINGS *** # 1. Validation is YAML-ONLY. A misspelled rule key PASSES and silently no-ops. # Acceptance MUST be BEHAVIORAL (see ACCEPTANCE). Same trap as D-046. # 2. 2024.1 ONLY. Native Domain Manager persona ships in 2024.2 (Dalmatian); on # any upgrade past 2024.1 this overlay MUST be removed/reconciled (it would # conflict with the native persona). [D-051] # 3. THREE rules are marked [PENDING-LIVE-READ]: identity:list_users, # identity:list_projects, identity:list_groups did NOT appear as explicit # lines in the live dump (they fall through to "default": "rule:admin_required"). # Their fallthrough below is the conservative "rule:admin_required" placeholder. # CONFIRM with the short read before shipping; replace if the live default differs. # # THIS-DEPLOY ADAPTATIONS vs verbatim SCS: # - is_domain_managed_role = member + load-balancer_member ONLY. admin NEVER in # the list (anti-escalation). load-balancer_member INCLUDED (Magnum apiserver LB). # reader/manager intentionally omitted (least privilege; tenants cannot propagate # domain-manager rights). # # ACCEPTANCE (behavioral -- gate G3; never trust "PO:" alone): # As a domain-scoped `manager` in domain D: # PASS user/project create within D; role add member|load-balancer_member within D; # user list / project list / group list within D; domain list; role list. # DENY role add admin (not a managed role); any create/list in a different domain. # As cloud admin: ALL prior admin operations still succeed (cloud_admin reproduced). # ============================================================================= # --- Domain Manager rules (NEW rules defined by this overlay) --- # A domain manager is a user holding the `manager` role (assigned in domain scope). "is_domain_manager": "role:manager" # Roles a domain manager may assign/revoke. *** admin MUST NOT appear here. *** # member + load-balancer_member (the latter for the Magnum apiserver load balancer). "is_domain_managed_role": "'member':%(target.role.name)s or 'load-balancer_member':%(target.role.name)s" # Grant-scoping helpers (NEW; self-contained token-domain checks, valid old-style). "is_domain_user_project_grant": "token.domain.id:%(target.user.domain_id)s and token.domain.id:%(target.project.domain_id)s" "is_domain_group_project_grant": "token.domain.id:%(target.group.domain_id)s and token.domain.id:%(target.project.domain_id)s" "is_domain_level_user_grant": "token.domain.id:%(target.user.domain_id)s and token.domain.id:%(target.domain.id)s" "is_domain_level_group_grant": "token.domain.id:%(target.group.domain_id)s and token.domain.id:%(target.domain.id)s" "domain_manager_grant": "rule:is_domain_manager and (rule:is_domain_user_project_grant or rule:is_domain_group_project_grant or rule:is_domain_level_user_grant or rule:is_domain_level_group_grant)" # --- Domain / role discovery (manager branch + verbatim live default) --- "identity:get_domain": "(rule:is_domain_manager and token.domain.id:%(target.domain.id)s) or rule:cloud_admin or rule:admin_and_matching_domain_id or token.project.domain.id:%(target.domain.id)s" "identity:list_domains": "rule:is_domain_manager or rule:cloud_admin" "identity:get_role": "(rule:is_domain_manager and rule:is_domain_managed_role) or rule:admin_required" "identity:list_roles": "rule:is_domain_manager or rule:admin_required" # --- Users (manager branch + verbatim live default) --- # [PENDING-LIVE-READ] list_users default not explicit in dump -> conservative admin_required "identity:list_users": "(rule:is_domain_manager and token.domain.id:%(target.domain_id)s) or rule:admin_required" "identity:get_user": "(rule:is_domain_manager and token.domain.id:%(target.user.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_user_domain_id or rule:owner" "identity:create_user": "(rule:is_domain_manager and token.domain.id:%(target.user.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_user_domain_id" "identity:update_user": "(rule:is_domain_manager and token.domain.id:%(target.user.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_user_domain_id" "identity:delete_user": "(rule:is_domain_manager and token.domain.id:%(target.user.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_user_domain_id" # --- Projects (manager branch + verbatim live default) --- # [PENDING-LIVE-READ] list_projects default not explicit in dump -> conservative admin_required "identity:list_projects": "(rule:is_domain_manager and token.domain.id:%(target.domain_id)s) or rule:admin_required" "identity:get_project": "(rule:is_domain_manager and token.domain.id:%(target.project.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_project_domain_id or project_id:%(target.project.id)s" "identity:create_project": "(rule:is_domain_manager and token.domain.id:%(target.project.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_project_domain_id" "identity:update_project": "(rule:is_domain_manager and token.domain.id:%(target.project.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_project_domain_id" "identity:delete_project": "(rule:is_domain_manager and token.domain.id:%(target.project.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_project_domain_id" "identity:list_user_projects": "(rule:is_domain_manager and token.domain.id:%(target.user.domain_id)s) or rule:owner or rule:admin_and_matching_domain_id" # --- Role assignments / grants (manager branch + managed-role gate + verbatim live default) --- "identity:check_grant": "rule:domain_manager_grant or rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants" "identity:list_grants": "(rule:is_domain_manager and token.domain.id:%(target.user.domain_id)s) or (rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s) or rule:cloud_admin or rule:domain_admin_for_list_grants or rule:project_admin_for_list_grants" "identity:create_grant": "(rule:domain_manager_grant and rule:is_domain_managed_role) or rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants" "identity:revoke_grant": "(rule:domain_manager_grant and rule:is_domain_managed_role) or rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants" "identity:list_role_assignments": "(rule:is_domain_manager and token.domain.id:%(target.domain_id)s) or rule:cloud_admin or rule:admin_on_domain_filter or rule:admin_on_project_filter" # --- Groups (manager branch + verbatim live default) --- # [PENDING-LIVE-READ] list_groups default not explicit in dump -> conservative admin_required "identity:list_groups": "(rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s) or rule:admin_required" "identity:get_group": "(rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_group_domain_id" "identity:create_group": "(rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_group_domain_id" "identity:update_group": "(rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_group_domain_id" "identity:delete_group": "(rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_group_domain_id" "identity:list_groups_for_user": "(rule:is_domain_manager and token.domain.id:%(target.user.domain_id)s) or rule:owner or rule:admin_and_matching_target_user_domain_id" "identity:list_users_in_group": "(rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_group_domain_id" "identity:remove_user_from_group": "(rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s and token.domain.id:%(target.user.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_group_domain_id" "identity:check_user_in_group": "(rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s and token.domain.id:%(target.user.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_target_group_domain_id" "identity:add_user_to_group": "(rule:is_domain_manager and token.domain.id:%(target.group.domain_id)s and token.domain.id:%(target.user.domain_id)s) or rule:cloud_admin or rule:admin_and_matching_group_domain_id"