One table, two analysts, two different answers, with PII hidden by policy instead of by copying data.
The problem
Data teams want access to everything. Security teams want sensitive columns locked down. The usual compromise is to copy “safe” subsets into separate buckets, which multiplies storage, drift and risk. Lake Formation lets you keep one copy and enforce who sees which rows and columns at query time.
What you’ll build
- A KMS-encrypted, versioned, access-logged S3 data lake with sample customer data
- Lake Formation as the only authority (legacy IAMAllowedPrincipals defaults turned off)
- A Glue Data Catalog table registered from a Lake Formation-managed location
- Two personas:
analystfull(everything) andanalystrestricted(onlysegment='retail'rows, neverssn/email) via a data cells filter - An Athena engine v3 workgroup with KMS-encrypted results, plus optional Macie PII discovery
Architecture
S3 (KMS, versioned, access-logged) โโถ Lake Formation (registered location, LF-only permissions)
โโ Glue Data Catalog: secure_lake.customers
โโ grant: AnalystFull โ SELECT table
โโ data-cells filter retail_no_pii โ AnalystRestricted
Athena workgroup (KMS-encrypted results, engine v3) ยท Macie PII discovery (optional)
AWS services used
How it works
- StoreData lands once in S3, encrypted with a customer-managed key.
- GovernLake Formation owns the location and grants table or filter permissions to roles.
- FilterA data cells filter combines a row expression with excluded columns.
- QueryAthena asks Lake Formation for scoped credentials, so each persona sees only what policy allows.
Key design decisions
- No data copies: security is enforced at read time.
- Turning off the default IAMAllowedPrincipals grants is the step most tutorials skip, and it is the one that makes Lake Formation actually enforce.
- Macie provides evidence that the columns you protect are the ones that contain PII.
Deploy it
npm install
npx cdk deploy -c adminArn=arn:aws:iam::123456789012:role/YourAdminRole
# add -c enableMacie=true if Macie is not yet enabled in this account/region
Full prerequisites, parameters and clean-up steps are in the project README on the code page.
See it work
Run SELECT * FROM secure_lake.customers as each role. The full analyst sees 10 rows and 7 columns. The restricted analyst sees 5 retail rows, and the ssn and email columns don’t exist for them.
Skills this demonstrates
Get the code
Every file needed to build this project, written as a deployable AWS CDK app and validated with the CloudFormation schema.
Leave a Reply