Skip to content

eSHARS Database Access Strategy

Overview

eSHARS developer access to the Azure SQL databases (data, log, audit) is managed via seven Entra ID security groups in the HISD tenant. Each group maps to a specific (environment tier, access profile) — the SQL-side role grants encode the per-database permissions. A developer’s effective access is the union of all groups they belong to.

This doc is for engineers granting or revoking database access, and for onboarding new developers. See INFRA-0006 for the rationale behind this model.


Access Model

Environments and databases

TierEnvironmentsDatabases
nonprodqa, uat, training, regressiondata, log, audit
prodproddata, log, audit

Groups

GroupdatalogauditTypical user
sg-eshars-db-nonprod-readerReadReadReadQA engineer, analyst, junior dev
sg-eshars-db-nonprod-writerRead-WriteReadReadDeveloper (baseline)
sg-eshars-db-nonprod-dbaDBADBADBALead developer, DBA
sg-eshars-db-prod-readerReadTroubleshooting prod data
sg-eshars-db-prod-writerRead-WriteReadReadAuthorized hotfix / data-fix
sg-eshars-db-prod-auditorReadCompliance reviewer, auditor
sg-eshars-db-prod-dbaDBADBADBAFormal DBA only

Mix-and-match rule

A developer gets 1–2 groups covering their access needs. The effective permission on any database is the union of all granted group permissions.

Example — standard developer (Markel Fennell):

  • sg-eshars-db-nonprod-writer → RW on data, R on log/audit across qa/uat/training/regression
  • sg-eshars-db-prod-reader → R on prod data only

Assignment Flow

Standard request (new dev / permission change)

  1. Developer fills in the eSHARS Database Permissions SharePoint list.

  2. Leon maps the response to group(s) using the Decision Table below.

  3. Add the developer to the group(s):

    Terminal window
    az login --tenant b07ee812-5705-40b5-b227-3df824080db8
    az ad group member add \
    --group sg-eshars-db-nonprod-writer \
    --member-id <user-object-id>
  4. Access is live within ~15 minutes (Entra token refresh).

  5. If the response doesn’t fit any standard pattern, add a direct SQL user and register it in the Exceptions Registry.

Decision Table

Access pattern requestedGroups to assign
Standard developernonprod-writer + prod-reader
QA / analyst / read-only nonprodnonprod-reader
Lead dev / needs all nonprodnonprod-dba + prod-reader
Formal DBAnonprod-dba + prod-dba
Compliance / audit trail reviewerprod-auditor
Authorized hotfix (time-boxed)prod-writerremove after incident closes
No prod accessnonprod group only, no prod group

Granting Permissions in SQL

These grants are one-time per group per database server. Run inside the target database (not master). They are idempotent — safe to re-run.

nonprod-reader (run in each nonprod data, log, and audit DB)

CREATE USER [sg-eshars-db-nonprod-reader] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [sg-eshars-db-nonprod-reader];

nonprod-writer

-- Run in each nonprod DATA DB (qa, uat, training, regression)
CREATE USER [sg-eshars-db-nonprod-writer] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [sg-eshars-db-nonprod-writer];
ALTER ROLE db_datawriter ADD MEMBER [sg-eshars-db-nonprod-writer];
GRANT EXECUTE ON SCHEMA::dbo TO [sg-eshars-db-nonprod-writer];
-- Run in each nonprod LOG and AUDIT DB (read-only + execute)
CREATE USER [sg-eshars-db-nonprod-writer] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [sg-eshars-db-nonprod-writer];
GRANT EXECUTE ON SCHEMA::dbo TO [sg-eshars-db-nonprod-writer];

nonprod-dba

-- Run in all nonprod DBs (data, log, audit × qa/uat/training/regression)
CREATE USER [sg-eshars-db-nonprod-dba] FROM EXTERNAL PROVIDER;
ALTER ROLE db_owner ADD MEMBER [sg-eshars-db-nonprod-dba];

prod-reader

-- Run in prod DATA DB only
CREATE USER [sg-eshars-db-prod-reader] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [sg-eshars-db-prod-reader];

prod-writer

-- Run in prod DATA DB
CREATE USER [sg-eshars-db-prod-writer] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [sg-eshars-db-prod-writer];
ALTER ROLE db_datawriter ADD MEMBER [sg-eshars-db-prod-writer];
GRANT EXECUTE ON SCHEMA::dbo TO [sg-eshars-db-prod-writer];
-- Run in prod LOG and AUDIT DB (read-only + execute)
CREATE USER [sg-eshars-db-prod-writer] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [sg-eshars-db-prod-writer];
GRANT EXECUTE ON SCHEMA::dbo TO [sg-eshars-db-prod-writer];

prod-auditor

-- Run in prod AUDIT DB only
CREATE USER [sg-eshars-db-prod-auditor] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [sg-eshars-db-prod-auditor];

prod-dba

-- Run in all prod DBs (data, log, audit)
CREATE USER [sg-eshars-db-prod-dba] FROM EXTERNAL PROVIDER;
ALTER ROLE db_owner ADD MEMBER [sg-eshars-db-prod-dba];

Exceptions Registry

Individual SQL users for access patterns that don’t fit any standard group. Review quarterly — remove stale entries.

UserDatabaseGrantReasonAddedReview
(none yet)

Revocation

Group removal — remove from the Entra group; access revokes within ~15 minutes:

Terminal window
az ad group member remove \
--group sg-eshars-db-nonprod-writer \
--member-id <user-object-id>

Offboarding checklist:

  • Remove from all sg-eshars-db-* groups the user belongs to
  • Check the Exceptions Registry above — drop any direct SQL users for this person
  • Verify with entra-access-audit.sql that no residual access remains

Verification

Entra side — list members of a group:

Terminal window
az ad group member list --group sg-eshars-db-nonprod-writer --output table

SQL side — run entra-access-audit.sql (see Database scripts) against each database. It lists all Entra users/groups and their assigned roles. After the initial setup you should see exactly the groups relevant to that DB tier and no legacy individual user entries.

Smoke test after adding a user:

  1. Add user to sg-eshars-db-nonprod-writer.
  2. Wait 15 minutes.
  3. Connect to a nonprod data DB as the user — SELECT TOP 1 * FROM <any table> and INSERT/UPDATE should both succeed.
  4. Connect to a nonprod log or audit DB — SELECT should succeed, INSERT should fail with permission denied.