Skip to main content

E. Access & Resource Governance

Wasteology now has a company-wide Azure governance standard (lat.md/cloud-governance.md) that defines the authoritative model for who can access what, how grants are made, and how changes are tracked. This section translates that standard into concrete day-one guidance for new developers and a clear decision framework for the product owner and COO — including the two-layer access model, role tiers, sanctioned tooling, when to engage ABS, and the ongoing review cadence.

The goal is a single reference every developer and future PO can consult when granting, requesting, or reviewing access — so that least-privilege defaults are established on day one and access does not accumulate silently over time.


1. The Two-Layer Access Model

Current state

Access to Wasteology resources is controlled at two independent layers. Historically these were managed ad hoc — some developers had broad portal access, and database role assignments were made directly in psql without a record. Both layers must be checked when auditing "who has access," because a principal can hold one without the other.

Treat the two layers as distinct and govern them with different tools:

LayerWhat it controlsGoverned byTooling
Control-plane (Azure RBAC)Who can view, manage, or modify Azure resources (subscriptions, resource groups, apps, key vaults)User Access Administrator or Owner role holdersops azure access [--sub] [--resource] [--principal]
Data-plane (database)Who can connect to a database and read/write rows or manage objectsDatabase role assignments (Postgres) or AAD admin grantsops db CLI or wdp-palantiri DB Access Manager (page 07)

How it works

Control-plane grants are inherited top-down: a role at subscription scope covers every resource group and resource beneath it. Narrower scope is always preferred — grant at the resource or resource-group level, not the subscription, unless the principal genuinely needs subscription-wide access.

Data-plane grants are independent of RBAC. For AAD-enabled Postgres servers (pg-wasteology, app-wasteology-prod, wg-pg-orbit-prod), a developer's Azure AD identity can be used as the login — but they still need a database role grant before they can read or write any rows. The two password-only servers (billing-modernization-dev/prd) are not governed by AAD at all and are managed via native Postgres credentials stored in Key Vault.

Why both matter: A developer with Owner on the Production subscription can still be locked out of prod database rows if they have no role grant in Postgres. Conversely, a database role grant does not give someone the ability to manage the Azure Container App that runs wdp-palantiri — that requires RBAC. Audits must check both.

PO decision point

The current model relies on kgray as the sole approver for both layers in most cases. As the team grows, decide whether TJ Lewis (tlewis) should be elevated to a co-approver on the DBACCESS_MUTATION_ALLOWLIST (currently Kent Gray,TJ Lewis in the deployed environment) — and whether a second UAA in the prefect-resources RG is warranted. The governance standard recommends monthly access reviews; the PO should confirm who runs this review during the transition.


2. Access Tiers

Current state

Three informal tiers exist in practice (read-only analyst, developer with write, platform admin) but they have not been formally defined or consistently applied. The ops db CLI introduced a four-tier model for Postgres in 2026-Q1; Azure RBAC assignments have been made on a per-case basis.

Define three access tiers that map to both layers. Assign every user to the narrowest tier that covers their role.

Tier Definitions

TierAzure RBAC roleDB role(s)Grants
ReadReader (specific RG or resource)wasteology_readonly + explicit grant-schema per schema neededSELECT on granted schemas; read the Azure resource in portal and ops azure
WriteContributor (scoped to specific RG)wasteology_readonly + grant-schema --access readwrite on specific schemasINSERT/UPDATE/DELETE on granted schemas; deploy container apps, push images, run pipelines within scope
AdminContributor (broader) + User Access Administrator (specific RGs only, via ABS/CGreco)wasteology_admin role membership + azure_pg_admin (where needed)ALL PRIVILEGES on all tables/sequences/schemas; can manage roles, extensions, all non-system DB objects; can assign Azure roles within their UAA scope

Who Approves What

Role requestedApproverMethod
Read — DB (dev)kgray or tlewisops db create-user or DB Access Manager page 07
Read — DB (prod)kgrayops db create-user --conn WASTE_PG
Read — Azure RBACABS / CGreco / ashullRequest via ABS (see Section 5); kgray can approve within Prod prefect-resources RG only
Write — DBkgrayops db grant-schema --access readwrite
Write — Azure RBAC (scoped RG)ABS / CGreco / ashullABS request; kgray can approve within Prod prefect-resources RG
Admin — DB (wasteology_admin)kgrayops db add-to-role --role wasteology_admin
Admin — DB (azure_pg_admin)kgrayops db add-to-role --role azure_pg_admin; treat as superuser-equivalent — grant deliberately
Admin — Azure RBAC (Owner / UAA)ABS / CGrecoABS request; never self-grant
New subscription / tenant-level roleABSABS request only

Postgres Role Reference

Postgres roleAccess levelWho gets it
wasteology_readonlySELECT on wasteology_ops schema onlyDefault for all read-tier users; other schemas require explicit grant-schema
wasteology_adminALL PRIVILEGES on all tables/sequences/schemasSenior devs with write access to shared schemas
azure_pg_adminPostgres superuser equivalent (manage roles, extensions, all objects)Platform admin only; grant deliberately
Schema ownerDROP rights via object ownership transferExplicitly scoped; only kgray/tlewis via DBACCESS_OWNER_ALLOWLIST
PO decision point

Decide whether new developers default to read-tier (SELECT only, schemas granted on request) or write-tier (DML on dev DB). The current recommendation is read-tier by default with a fast-path to write on dev — this limits blast radius during onboarding while keeping developers unblocked. Prod write access requires explicit approval in all cases.


3. New-Developer Onboarding Checklist

Current state

No formal onboarding checklist exists. Access has been granted reactively — developers request what they need, and grants accumulate. There is no standard day-one set of access nor a formal offboarding revoke process.

Apply the checklist below on every new-developer start. The platform owner (kgray) is the approver for all steps unless noted.

Day-One Access (all new developers)

  • ADO membership: Add to the wasteology ADO organization (project: Wasteology). Grants access to all ADO repos. Done in ADO Organization Settings → Users.
  • Repo access (ADO): Confirm the developer can clone and push to their assigned repos. Default: wg-orchestration, wdp-palantiri, and any project-specific repos. Branch policies are enforced at the PR level.
  • Dev DB — read grant: Run ops db create-user <email-prefix> --schema wasteology_ops --access read (targets WASTE_PG_DEV by default). This creates the user and adds them to wasteology_readonly. Grant additional schemas as needed with ops db grant-schema.
  • Dev DB — dev write (if applicable): Run ops db grant-schema <user> --schema <target_schema> --access readwrite for schemas the developer will actively write to in dev. Do not grant readwrite on prod schemas on day one.
  • Key Vault / secrets: Provide access to wg-orchestration-kv secrets via the .env file shared via Bitwarden (or the team vault, not email). The developer does not need Azure RBAC on the Key Vault itself unless they are running infra CI pipelines.
  • wdp-palantiri (dashboard): No RBAC required — the dashboard is open internally. If the developer needs to apply DB mutations via the UI, add their displayName to DBACCESS_MUTATION_ALLOWLIST in the container app environment.
  • Prefect Cloud: Invite to the Prefect Cloud workspace as Editor (for flow deployment) or Viewer (for monitoring only). Done in Prefect Cloud → Members.
  • dbt Cloud (if applicable): Invite via dbt Cloud → Account Settings → Users. Set their connection string parameter to options=-c wdp.mart_schema=dbt_{username} and add a row to lat.md/database-schemas.md#dbt_{username} — Personal Developer Schemas.
  • Least-privilege default: Do not grant wasteology_admin, azure_pg_admin, or any Azure RBAC Contributor/Owner on day one. Escalate only when a specific task requires it.

Standard Access NOT Granted on Day One

The following require explicit justification and approval:

  • Prod database write access (--conn WASTE_PG + --access readwrite)
  • wasteology_admin or azure_pg_admin role membership
  • Azure RBAC Contributor or higher on any resource group
  • Access to BINS password-only servers (billing-modernization-dev/prd) — credentials from Bitwarden "BINS Engagement" vault, by request
  • Orbit DB (wg-pg-orbit-prod) — AAD-only server, requires ABS for subscription-level RBAC

Offboarding (same day as departure)

  • Revoke DB roles: ops db remove-from-role <user> --role <role> for each role. Run ops db grants <user> first to enumerate all current grants.
  • Revoke DB schema grants: ops db grant-schema <user> --schema <s> --access none or equivalent revoke for each schema.
  • Remove from ADO: Remove from the wasteology ADO organization.
  • Remove from Prefect Cloud: Revoke workspace membership.
  • Remove from dbt Cloud: Revoke via dbt Cloud UI.
  • Rotate any shared credentials the user knew: If the developer had access to any service account passwords or Key Vault secrets that are not user-scoped (e.g., SLING_WASTE_PG_PASSWORD for a shared service account), rotate those secrets and update wg-orchestration-kv and ~/.sling/.env on all machines.
  • Audit RBAC: Run ops azure access --principal <upn> across all three subscriptions to confirm no residual RBAC assignments.
  • Record in audit log: The wg_digests.dbaccess_audit_log table captures all ops db mutations automatically. Manual RBAC revokes should be noted in the git history of lat.md/cloud-governance.md.
PO decision point

The offboarding rotation step for shared credentials is currently manual. If the team grows beyond 4–5 developers sharing a Postgres service-account password, consider switching all service accounts to AAD-only auth (managed identities or per-user AAD login) to eliminate the rotation burden on offboarding. wg-pg-orbit-prod already uses AAD-only; this would extend that pattern to pg-wasteology.


4. How to Grant Access (Sanctioned Tooling)

Current state

Grants have been made via psql directly, via the Azure portal, and via az CLI — with no consistent audit trail. The DB Access Manager (page 07) and ops db CLI were built to consolidate this.

Use only the sanctioned paths below. Portal-direct grants are not sanctioned because they bypass the audit trail.

Postgres — ops db CLI

# Create a new user and add to wasteology_readonly (read-tier onboarding)
ops db create-user <email-prefix> --schema wasteology_ops --access read

# Grant additional schema to an existing user
ops db grant-schema <user> --schema <schema> --access read|readwrite

# Add to a role (e.g., wasteology_admin or azure_pg_admin)
ops db add-to-role <user> --role wasteology_admin
ops db add-to-role <user> --role azure_pg_admin --conn WASTE_PG_DEV

# Remove from a role (offboarding / privilege reduction)
ops db remove-from-role <user> --role wasteology_admin

# Inspect current state
ops db grants <user> # all table-level privileges for a user
ops db roles # list roles and members
ops db audit-roles # find schemas missing baseline grants

Default target is WASTE_PG_DEV (dev). Always pass --conn WASTE_PG for production Postgres.

The DB Access Manager (wdp-palantiri page 07) provides the same operations with a visual access matrix, dry-run preview, typed confirmation, and automatic write to wg_digests.dbaccess_audit_log. Use the CLI for scripting and automation; use the page for interactive reviews and one-off changes.

Azure RBAC

Azure RBAC assignments must be made by a User Access Administrator or Owner. The people who currently hold those roles:

PersonRoleScope
ABS (external partner)User Access AdministratorAll three subscriptions
CGreco / CGreco-aUser Access AdministratorAll three subscriptions
ashullOwnerAll three subscriptions
kgrayUser Access AdministratorProd prefect-resources RG only

For any grant that kgray cannot make unilaterally (anything outside Prod prefect-resources RG), request from ABS or ashull using the template in Section 5.

Always specify the narrowest scope that works: resource > resource group > subscription. Avoid subscription-wide grants unless the developer genuinely needs access to all resources in that subscription.

Audit Trail

All DB grants and revokes via ops db or the DB Access Manager are recorded in wg_digests.dbaccess_audit_log (one row per SQL statement, with actor, operation, target user/schema/role, access level, DB env, SQL executed, success flag, and timestamp). Azure RBAC changes are recorded in Azure's native Activity Log, queryable via ops azure access. Provisioning decisions (new resources, RBAC grants) should also be recorded as git-reviewed edits to lat.md/cloud-governance.md.


5. The ABS Resource-Request Process

Current state

No formal template or escalation path exists for tenant-level or subscription-level requests. Requests have been made ad hoc via email or Teams message.

Maintain a clear boundary between what the team self-serves and what requires ABS engagement.

What the Team Can Self-Serve

ActionTooling
Postgres user creation and schema grants (dev + prod)ops db CLI
Postgres role membership changesops db CLI
Container App and supporting resource deployment into wdp-palantiri-rg (Prod sub)/infra Bicep (infra/) via ADO pipeline or az deployment group what-if/create
Azure RBAC within Prod prefect-resources RGkgray directly (UAA on that RG)
Image push to ACRs, Container App image updatesaz containerapp update or build scripts
Prefect Cloud workspace membershipPrefect Cloud UI (any Editor)

When to Request via ABS

Engage ABS for any of the following:

  • New Azure subscription — any new subscription under the Wasteology tenant
  • New resource group in Dev or Prod subscription — ABS or ashull must create it and assign initial RBAC
  • Subscription-wide RBAC grants — e.g., giving a developer Reader on the entire Prod subscription
  • Tenant-level role assignments — e.g., Global Admin, Directory Reader
  • App registration / service principal creation — the tenant has a directory restriction that blocks app registrations; all non-human identities must be managed identities (no SP registration). If an SP is unavoidable, ABS must request via the tenant admin.
  • Managed identity creation outside wdp-palantiri-rg — managed identities in other RGs or subscriptions require ABS for initial provisioning
  • Cleanup of stale SPs or expired credentials — ABS holds the permissions to hard-delete app registrations
  • Cost Management reader grants at subscription scope — needed to give the ADO CI identity (wg-azure-infra-identity) full snapshot capability; currently pending ABS grant

Information to Include in Every ABS Request

Submit requests to ABS (and CC ashull) with the following fields filled in. Incomplete requests will be returned.


ABS Access / Resource Request Template

Subject: Wasteology Azure Request — [brief description]

Requestor: [name + email]
Date needed by: [YYYY-MM-DD]
Urgency: [routine | blocking a deploy | security remediation]

--- REQUEST TYPE (check one) ---
[ ] New subscription
[ ] New resource group
[ ] RBAC role assignment
[ ] Managed identity creation
[ ] SP registration (explain why managed identity is insufficient)
[ ] Credential rotation / cleanup
[ ] Tenant-level role assignment
[ ] Other: ___

--- DETAILS ---
Principal (who needs access):
Name/UPN or managed identity name: ___
Object ID (if known): ___

Resource (what they need access to):
Subscription(s): [ ] dev (669a4356) [ ] prod (a5a6818e) [ ] orbit (60e2b27e)
Resource group (if scoped): ___
Specific resource name/ID (if scoped further): ___

Role requested: ___
(Reader / Contributor / Owner / User Access Administrator / Key Vault Secrets User / other)

Justification (one sentence — what breaks without this):
___

Least-privilege check:
Can a narrower scope work? (e.g., RG instead of sub) ___
Is a time-bound grant sufficient? ___
Is a managed identity preferred over a user grant? ___

Related ticket / ADO work item (if any): ___
Approved by (platform owner): kgray@wasteologygroup.com

Submit via Teams to ABS with ashull CC'd. Expected turnaround: 1–2 business days for routine requests, same day for security remediations.

PO decision point

The current ABS engagement is informal. As team size grows, consider formalizing requests through a shared ADO queue so all pending and completed access changes are visible to the PO. A lightweight ADO Task in the Wasteology project with the access-request tag would suffice to start — this also gives the monthly access review a single place to look.


6. RACI for Access Approval and Review Cadence

Current state

Access approval is informal and concentrated in kgray. No regular review cadence is documented, and there is no explicit RACI. Service principal and credential expiry tracking is manual.

RACI

ActivityResponsibleAccountableConsultedInformed
DB read-tier grant (dev)kgray / tlewiskgrayNew developer
DB write/admin grantkgraykgrayashull (for prod)New developer
Azure RBAC grant (within kgray's UAA scope)kgraykgrayDeveloper, ABS
Azure RBAC grant (outside kgray's scope)ABS / ashullashullkgrayDeveloper
New subscription / resource groupABSashullkgrayPlatform owner
Managed identity creationABSashullkgrayDeveloper
SP registration (requires ABS)ABSashullkgrayPlatform owner
Monthly access reviewkgrayPlatform owner (PO designates)ashullCOO
Quarterly SP / credential cleanupkgrayPlatform ownerABSCOO
Cost review (weekly via digest)kgrayPlatform ownerCOO

Review Cadence

ReviewCadenceOwnerTooling
Cost reviewWeekly (surfaced in morning standup digest automatically)kgrayops digest standup → AZURE GOVERNANCE block; ops azure costs
Access review (RBAC + DB roles)Monthlykgray`ops azure access --sub dev
Service-principal & credential cleanupQuarterlykgrayops azure identities; check expiry flags from ops azure drift
Drift alert reviewDaily (automatic via digest pipeline)kgray (acts on findings)ops azure drift — flags new SPs, new Owner/UAA grants, expiring credentials, cost spikes >20%

How Drift Detection Works

The ops azure snapshot command (run daily in the ADO digest pipeline) captures subscription state to wg_digests.azure_governance_snapshots. ops azure drift diffs the two most recent snapshots and emits findings:

  • Absolute (no prior snapshot needed): credentials expiring within 30 days, already-expired credentials
  • Relative (needs prior snapshot): new service principals, new Owner or User Access Administrator grants, month-to-date cost spikes over 20%

These findings appear in the AZURE GOVERNANCE block of the daily morning brief. Any finding other than a known/expected change requires same-day investigation.

Note: Full daily drift capture is currently gated on granting wg-azure-infra-identity (the ADO CI managed identity) Reader + Cost Management Reader on all three subscriptions and Application.Read.All on Microsoft Graph. Until ABS completes this grant, daily captures are partial and the dashboard relies on manually authenticated snapshots. This ABS request should be prioritized as part of new-developer onboarding infrastructure.

PO decision point

Decide who owns the monthly access review after kgray. The platform owner role is the natural candidate, but this person needs either UAA in prefect-resources RG or a standing relationship with ABS/ashull to act on findings. If the incoming PO does not have Azure access, the review becomes advisory only — which defeats the purpose. Recommend granting the PO read-only access (Reader on all three subscriptions) as a first step so they can independently verify the access matrix without needing to request data from kgray.