Exercise 7.1 โ RBAC Model for Utility PII
Design and implement a 3-persona RBAC model on your trial account. Hands-on, end with a working grant tree you could walk an interviewer through.
The scenario
You're on a utility's data platform team. Three personas query the warehouse:
- Meter engineer: needs raw meter reads, asset IDs, consumption. Does not need customer names/addresses/billing.
- Customer analyst: needs billing addresses, customer names, consumption rolled up per account. Does not need SSN, DOB, credit-check data.
- Compliance officer: needs everything, for audit. Read-only. Never grants.
Step 1 โ Create sample tables
USE ROLE ACCOUNTADMIN;
USE WAREHOUSE LEARN_WH;
CREATE SCHEMA IF NOT EXISTS LEARN_DB.RBAC_DEMO;
USE SCHEMA LEARN_DB.RBAC_DEMO;
CREATE OR REPLACE TABLE meter_reads (
meter_id STRING, premise_zip STRING, read_ts TIMESTAMP_NTZ, consumption_kwh NUMBER(10,3)
);
CREATE OR REPLACE TABLE customers (
customer_id STRING, full_name STRING, billing_address STRING,
ssn STRING, dob DATE, credit_score NUMBER
);
CREATE OR REPLACE TABLE accounts (
account_id STRING, customer_id STRING, meter_id STRING, started_at DATE
);
INSERT INTO customers VALUES
('C1','Customer One','100 Main St','xxx-xx-1111','1982-01-01',780),
('C2','Customer Two','200 Oak Ave','xxx-xx-2222','1977-05-05',810);
INSERT INTO accounts VALUES ('A1','C1','MTR-00001','2020-01-01'),('A2','C2','MTR-00002','2020-01-01');
INSERT INTO meter_reads VALUES
('MTR-00001','97124','2026-04-20 10:00:00',3.2),
('MTR-00002','97201','2026-04-20 10:00:00',4.1);
Step 2 โ Create access roles
USE ROLE SECURITYADMIN;
CREATE ROLE IF NOT EXISTS AR_METERS_READ;
CREATE ROLE IF NOT EXISTS AR_CUSTOMERS_NOPII_READ; -- customers w/o ssn/dob/credit
CREATE ROLE IF NOT EXISTS AR_CUSTOMERS_FULL_READ; -- full customer record
CREATE ROLE IF NOT EXISTS AR_ACCOUNTS_READ;
-- Grant DB/schema USAGE first (easy to forget!)
GRANT USAGE ON DATABASE LEARN_DB TO ROLE AR_METERS_READ;
GRANT USAGE ON SCHEMA LEARN_DB.RBAC_DEMO TO ROLE AR_METERS_READ;
GRANT SELECT ON TABLE LEARN_DB.RBAC_DEMO.meter_reads TO ROLE AR_METERS_READ;
GRANT USAGE ON DATABASE LEARN_DB TO ROLE AR_ACCOUNTS_READ;
GRANT USAGE ON SCHEMA LEARN_DB.RBAC_DEMO TO ROLE AR_ACCOUNTS_READ;
GRANT SELECT ON TABLE LEARN_DB.RBAC_DEMO.accounts TO ROLE AR_ACCOUNTS_READ;
-- NO-PII access: grant on a *view* that strips sensitive cols
USE ROLE SYSADMIN;
CREATE OR REPLACE VIEW LEARN_DB.RBAC_DEMO.customers_nopii AS
SELECT customer_id, full_name, billing_address FROM LEARN_DB.RBAC_DEMO.customers;
USE ROLE SECURITYADMIN;
GRANT USAGE ON DATABASE LEARN_DB TO ROLE AR_CUSTOMERS_NOPII_READ;
GRANT USAGE ON SCHEMA LEARN_DB.RBAC_DEMO TO ROLE AR_CUSTOMERS_NOPII_READ;
GRANT SELECT ON VIEW LEARN_DB.RBAC_DEMO.customers_nopii TO ROLE AR_CUSTOMERS_NOPII_READ;
-- Full customer read (compliance)
GRANT USAGE ON DATABASE LEARN_DB TO ROLE AR_CUSTOMERS_FULL_READ;
GRANT USAGE ON SCHEMA LEARN_DB.RBAC_DEMO TO ROLE AR_CUSTOMERS_FULL_READ;
GRANT SELECT ON TABLE LEARN_DB.RBAC_DEMO.customers TO ROLE AR_CUSTOMERS_FULL_READ;
Step 3 โ Functional roles
CREATE ROLE IF NOT EXISTS FR_METER_ENGINEER;
CREATE ROLE IF NOT EXISTS FR_CUSTOMER_ANALYST;
CREATE ROLE IF NOT EXISTS FR_COMPLIANCE;
GRANT ROLE AR_METERS_READ TO ROLE FR_METER_ENGINEER;
GRANT ROLE AR_ACCOUNTS_READ TO ROLE FR_METER_ENGINEER;
GRANT ROLE AR_CUSTOMERS_NOPII_READ TO ROLE FR_CUSTOMER_ANALYST;
GRANT ROLE AR_ACCOUNTS_READ TO ROLE FR_CUSTOMER_ANALYST;
GRANT ROLE AR_METERS_READ TO ROLE FR_CUSTOMER_ANALYST;
GRANT ROLE AR_METERS_READ TO ROLE FR_COMPLIANCE;
GRANT ROLE AR_ACCOUNTS_READ TO ROLE FR_COMPLIANCE;
GRANT ROLE AR_CUSTOMERS_FULL_READ TO ROLE FR_COMPLIANCE;
-- Roll up to SYSADMIN for visibility
GRANT ROLE FR_METER_ENGINEER TO ROLE SYSADMIN;
GRANT ROLE FR_CUSTOMER_ANALYST TO ROLE SYSADMIN;
GRANT ROLE FR_COMPLIANCE TO ROLE SYSADMIN;
-- Grant yourself (the ACCOUNTADMIN user) all three to test
GRANT ROLE FR_METER_ENGINEER TO USER CURRENT_USER();
GRANT ROLE FR_CUSTOMER_ANALYST TO USER CURRENT_USER();
GRANT ROLE FR_COMPLIANCE TO USER CURRENT_USER();
Step 4 โ Test as each persona
-- As meter engineer
USE ROLE FR_METER_ENGINEER;
USE WAREHOUSE LEARN_WH;
SELECT * FROM LEARN_DB.RBAC_DEMO.meter_reads; -- โ works
SELECT * FROM LEARN_DB.RBAC_DEMO.customers; -- โ should fail (no privilege)
-- As customer analyst
USE ROLE FR_CUSTOMER_ANALYST;
SELECT * FROM LEARN_DB.RBAC_DEMO.customers_nopii; -- โ works (no PII)
SELECT * FROM LEARN_DB.RBAC_DEMO.customers; -- โ should fail
-- As compliance
USE ROLE FR_COMPLIANCE;
SELECT ssn, credit_score FROM LEARN_DB.RBAC_DEMO.customers; -- โ works
Step 5 โ Audit your work
USE ROLE SECURITYADMIN;
SHOW GRANTS TO ROLE FR_CUSTOMER_ANALYST;
SHOW GRANTS OF ROLE AR_CUSTOMERS_NOPII_READ;
The first tells you "what can Alice (as an analyst) do?" The second tells you "who all has access to this?"
Step 6 โ Cleanup
USE ROLE ACCOUNTADMIN;
DROP SCHEMA IF EXISTS LEARN_DB.RBAC_DEMO CASCADE;
DROP ROLE IF EXISTS FR_METER_ENGINEER;
DROP ROLE IF EXISTS FR_CUSTOMER_ANALYST;
DROP ROLE IF EXISTS FR_COMPLIANCE;
DROP ROLE IF EXISTS AR_METERS_READ;
DROP ROLE IF EXISTS AR_CUSTOMERS_NOPII_READ;
DROP ROLE IF EXISTS AR_CUSTOMERS_FULL_READ;
DROP ROLE IF EXISTS AR_ACCOUNTS_READ;
Reflection โ save to notepad
- When would you use a VIEW to strip columns vs a MASKING POLICY? (Lesson 7.2 covers this โ write your hypothesis now.)
- How would you express this RBAC tree in Terraform?
- What breaks if you skip
GRANT USAGE ON DATABASEto an access role?