Ravindra BagaleCourses & study guides मराठी Track your progress

Project: Multi-Tenant SaaS Keys and Isolation on DynamoDB

SaaS means many customers, one ops surface. Berlin PM Lena Vogt and Pune founder Vikram Patil ship TenantLite: TENANT# prefixes, IAM dynamodb:LeadingKeys, per-tenant email GSI, offboarding Query-delete. Reuse modeling; never trust client tenant id alone.

What you'll learn in this chapter

  • Prefix every key with TENANT#
  • Lock IAM with LeadingKeys
  • Per-tenant unique email GSI
  • Offboard a tenant safely
  • Lab + cleanup

1. Everyday example: co-working mail slots

Each company gets a labeled slot. Staff must not open another company slot. Label = TENANT# prefix. Staff badge rules = IAM LeadingKeys.

2. Vertical steps

Patterns -> TENANT# keys -> IAM -> GSI -> Offboard -> CleanupPatternsTENANT# keysIAMGSIOffboardCleanup
Cleanup

3. Why do we need this?

Why do we need this?

One leaked Query without a tenant prefix is a breach headline. MNCs ask how isolation is enforced in data and IAM, not only in UI.

4. What is it?

What is it?

TenantLite shared table: PK=TENANT#tid SK=USER#|ORDER#|SETTINGS; GSI1 PK=TENANT#tid SK=EMAIL#email. IAM condition dynamodb:LeadingKeys = TENANT#tid from the auth token.

5. How to do it (step by step)

How to do it (step by step)

  1. List patterns per tenant (users, orders, settings, email lookup).
  2. Draw two tenants acme + beta sample items.
  3. Create lab-ddo-saas; Put acme users; Put beta users.
  4. Attach IAM role with LeadingKeys TENANT#acme; prove beta denied.
  5. GSI1 email unique per tenant; offboarding BatchWrite delete.
  6. Delete lab table.

6. Key sketch

EntityPKSK
UserTENANT#acmeUSER#u1
SettingsTENANT#acmeSETTINGS
Email GSITENANT#acmeEMAIL#a@x.com

7. Commands with output and meaning

aws dynamodb create-table --table-name lab-ddo-saas \
  --attribute-definitions AttributeName=PK,AttributeType=S AttributeName=SK,AttributeType=S \
  --key-schema AttributeName=PK,KeyType=HASH AttributeName=SK,KeyType=RANGE \
  --billing-mode PAY_PER_REQUEST --region ap-south-1
aws dynamodb put-item --table-name lab-ddo-saas --item '{
 "PK":{"S":"TENANT#acme"},"SK":{"S":"USER#u1"},"email":{"S":"a@acme.test"}}'
aws dynamodb query --table-name lab-ddo-saas \
  --key-condition-expression "PK = :pk" \
  --expression-attribute-values '{":pk":{"S":"TENANT#acme"}}'
# IAM sketch (attach to tenant role):
# "Condition":{"ForAllValues:StringLike":{"dynamodb:LeadingKeys":["TENANT#acme"]}}
# Meaning: role can only touch keys beginning TENANT#acme.

App binds tid from JWT, not from request body alone. GSI PK also starts with TENANT#.

8. Industry stories

  • B2B CRM (Lena): workspace contacts.
  • EdTech (Sofia): school→class→student.
  • HealthTech (Meera): clinic-partitioned notes.
  • FinTech (Omar): merchant ledgers.
  • Logistics (Diego): shipper accounts.
  • Media (Priya): publisher catalogs.

9. Lab

How to do it (step by step)

  1. Create lab-ddo-saas; put acme+beta; Query each.
  2. Document LeadingKeys policy; simulate deny for cross-tenant.
  3. Script tenant delete by Query PK; delete table.

Cleanup (stop billing)

  1. Delete lab resources you created.
  2. Confirm with describe that names are gone.

10. Ops checklist before you ship

  1. Confirm TTL attribute name and units (epoch seconds).
  2. Decide soft-delete vs hard-delete vs archive-to-S3.
  3. Enable PITR on any table you cannot rebuild from source.
  4. Document RPO/RTO and who runs restore drills.
  5. If multi-region: pick write stickiness and conflict rules.
  6. If DAX: prove cache-miss path and warm-up plan.
  7. Tag Owner + Expiry on every lab resource.
  8. Budget alert in the account before load tests.

11. Copy-paste DynamoDB CLI starters (batch 2)

export AWS_DEFAULT_REGION=ap-south-1

# TTL status
aws dynamodb describe-time-to-live --table-name ShopApp

# PITR / continuous backups
aws dynamodb describe-continuous-backups --table-name ShopApp

# On-demand backup
aws dynamodb create-backup --table-name ShopApp --backup-name lab-shop-$(date +%Y%m%d)

# List backups
aws dynamodb list-backups --table-name ShopApp

# Global table description (v2)
aws dynamodb describe-table --table-name ShopApp --query 'Table.Replicas'

12. More industry stories

  • Retail (Aisha Khan, Dubai): TTL clears abandoned carts; soft-delete keeps 30-day undo.
  • Bank (Lucas Meyer, Berlin): PITR on ledger table; restore drill every quarter.
  • Travel (Omar Haddad, Amman): Global Tables for catalog reads; inventory writes sticky.
  • Gaming (Carlos Rivera, Mexico City): DAX for hot profile Gets; never cache money ledgers.
  • Social (Priya Nair, Kochi): adjacency edges for follows; sparse GSI for unread inbox.
  • IoT (Mei Lin, Shenzhen): device#day PK + TTL 14 days; rollups to S3.

13. Glossary (batch 2)

TermMeaning
TTLTime to Live — attribute with epoch seconds; DynamoDB deletes later
Soft deleteFlag deleted=true; item remains until TTL/archive
PITRPoint-in-time recovery — continuous backups window
Global TableMulti-region replicated DynamoDB table
LWWLast-writer-wins conflict resolution on replicas
DAXDynamoDB Accelerator — in-memory cache cluster
Adjacency listEdge items modeling relationships in one table
Fan-outWrite once; push copies to many feeds/inboxes

14. Practice: explain out loud

  1. 60s: TTL vs soft-delete vs S3 archive.
  2. 60s: PITR vs on-demand backup.
  3. 60s: when Global Tables help and hurt.
  4. 60s: DAX consistency trade-off.
  5. 60s: CartLite checkout keys in one breath.
  6. 60s: follow edge vs feed item.
  7. Record once; cut filler; record again.

15. Safe lab hygiene

  • Use ap-south-1 labs with a budget alert.
  • Prefix lab tables with lab- and your initials.
  • Delete replicas, DAX clusters, and backups you created for labs.
  • Never enable Global Tables on production without a write plan.
  • Tag every resource Owner + Expiry.
  • Export/import labs can create large S3 bills — delete prefixes.

17. Delete / archive decision pad

NeedPreferWhy
Undo 7-30 daysSoft-delete flagUser restore
Hard expiry, no readTTL attributeAuto delete later
Compliance keep coldExport/archive to S3Cheap long store
Mistake recoveryPITR / backupTable-level restore

18. Ten oral drill questions

  1. What units does DynamoDB TTL use?
  2. Does TTL delete instantly?
  3. PITR window typical length?
  4. Global Tables conflict default?
  5. When sticky writes matter?
  6. DAX vs API Gateway cache?
  7. Cart PK for a shopper?
  8. Order lines under which PK?
  9. Follow edge SK example?
  10. Unread inbox sparse GSI idea?

19. RPO / RTO mini workshop

  1. Write the worst data loss you can accept (RPO) in minutes.
  2. Write how long restore may take (RTO) before business pain.
  3. Map: on-demand backup vs PITR vs multi-region replica.
  4. Schedule a restore drill on a lab table this month.
  5. Name the person who runs the drill.

20. Cost watch list (batch 2)

  • PITR storage and on-demand backup storage.
  • Global Tables: replicated WCUs in every region.
  • DAX node hours even at idle.
  • Export to S3 + S3 storage + Athena later.
  • Streams + Lambda still bill during TTL deletes.

21. Project Definition of Done

  1. Access patterns written and peer-reviewed.
  2. Sample items drawn for happy path + one failure.
  3. Lab table created, exercised, deleted (or tagged Expiry).
  4. At least one conditional write or transaction exercised.
  5. Cleanup commands pasted in your notes.
  6. One interview answer recorded out loud.
  • TTL hygiene → Backup/PITR for “oops” recovery.
  • Global Tables → sticky writes from capacity/hot lessons.
  • DAX → only after Query shapes are correct.
  • P1 CartLite reuses modeling + transactions.
  • P2 Social reuses adjacency + Streams ideas.

23. Quick self-check (yes/no)

  1. I can explain TTL delay vs instant DeleteItem.
  2. I know when soft-delete beats hard delete.
  3. I can start PITR and say what restore costs in time.
  4. I can name one reason NOT to use Global Tables.
  5. I know DAX does not fix a bad partition key.
  6. I can sketch CartLite USER# and ORD# keys.
  7. I can sketch a follow edge item.
  8. I delete lab replicas/DAX/backups the same day.

24. Common errors and fixes

Each row is a real mistake students and juniors hit. Read the fix before you panic.

Error / symptomFix
Client-supplied tenant id onlyBind from verified JWT.
IAM without LeadingKeysAdd dynamodb:LeadingKeys.
Email as global PKPer-tenant GSI SK=EMAIL#.
Scan for admin UITenant Query / export.
GSI without tenant prefixGSI PK=TENANT#…
Noisy neighbor ignoredIsolate whale tenant table.
Soft offboard onlyQuery-delete + verify GSI empty.
Leave lab tableDelete same day.
Rewrite modeling chapterLink modeling.

25. Troubleshooting checklist

  1. Cross-tenant Get returns data: missing LeadingKeys / app bug.
  2. AccessDenied after login: tid mismatch vs role.
  3. Unique email clash: include TENANT# in GSI PK.
  4. Throttle one tenant: reserved capacity or split table.
  5. Backup restore mix: restore aside; migrate slice.

26. FAQ

Q. Should I always use a single table?

Often yes for related access patterns; not a religion. Separate tables are fine for unrelated domains or different capacity/security needs.

Q. Do I still need RDS?

Yes for heavy joins, multi-row SQL reports, and strong relational constraints. See the intro DynamoDB vs RDS chapter.

Q. Is Scan evil?

Scan is a tool for rare admin jobs and small tables. Design so hot paths use Query/GetItem.

Q. Where are Put/Get command details?

In the CRUD survey, CLI and SDK chapters — this deep set links them instead of copying.

Q. Table per tenant?

Start shared; split noisy tenants later.

Q. CMK per tenant?

Optional; start with table CMK.

Q. GDPR delete proof?

Query delete + GSI empty + ticket.

Q. LeadingKeys syntax?

ForAllValues:StringLike dynamodb:LeadingKeys.

27. Interview Q&A

Q. (B) Isolation key?

PK begins TENANT#tid.

Q. (B) IAM control?

dynamodb:LeadingKeys.

Q. (M) Unique email?

GSI under same tenant PK.

Q. (M) Offboard?

Query PK + batch delete + verify.

Q. (S/MNC) Noisy neighbor?

Dedicated table / capacity.

Q. (MNC) Trust client tid?

Never — JWT/session only.

28. Tips in English, Marathi and Hindi

Ravindra Bagale's Tip (EN)

TENANT# in every key + LeadingKeys — UI filters are not security.

Ravindra Bagale's Tip (MR)

प्रत्येक key ला TENANT# आणि LeadingKeys.

Tip (HI)

हर कुंजी में TENANT# और LeadingKeys — UI सुरक्षा नहीं।

Try at home

  1. Draw acme vs beta items.
  2. Write LeadingKeys policy stub.
  3. Offboard checklist on paper.

In short

  1. TenantLite = TENANT# collections.
  2. IAM LeadingKeys enforce.
  3. Offboard = Query delete.
  4. Cleanup labs.

Revision, interview and comparison cards

Revise this lesson in a few minutes. Save the cards on your phone or download them as PNG files. The QR code on each card opens this lesson.

Revision card: TENANT# prefix. Keys without tenant prefix leak across customers. Every PK/GSI starts TENANT#tid; bind tid from JWT. Draw two tenants → Put → Query only own PK → never trust body tid. Lena Vogt rejects client-supplied tenant ids.
Revision card: TENANT# prefix · Download PNG · Open card page
Revision card: LeadingKeys IAM. App filters alone are not isolation. IAM dynamodb:LeadingKeys = TENANT#tid on the role. Attach condition → attempt cross-tenant Get → must Deny → CloudTrail. Vikram Patil demos Deny before production cutover.
Revision card: LeadingKeys IAM · Download PNG · Open card page
Comparison: UI filter only vs LeadingKeys IAM. UI filter only: Hide other tenants only in the UI. LeadingKeys IAM: IAM dynamodb:LeadingKeys Deny.
Comparison: UI filter only vs LeadingKeys IAM · Download PNG · Open card page
Comparison: Global email PK vs Tenant email GSI. Global email PK: Email as table PK collides across tenants. Tenant email GSI: GSI PK=TENANT# SK=EMAIL#.
Comparison: Global email PK vs Tenant email GSI · Download PNG · Open card page
Interview card: LeadingKeys demo. Policy without condition still reads other tenants. ForAllValues:StringLike dynamodb:LeadingKeys TENANT#acme. Role acme → Get beta → AccessDenied → CloudTrail proof.
Interview card: LeadingKeys demo · Download PNG · Open card page
Interview card: Per-tenant email. Global email PK collides across tenants. GSI PK=TENANT#tid SK=EMAIL#addr for uniqueness. Put two tenants same email → both OK → Query each.
Interview card: Per-tenant email · Download PNG · Open card page
Interview card: Offboard delete. UI hide is not GDPR delete. Query PK=TENANT#tid → BatchWrite delete → verify GSI empty. Ticket → script → verify → retain audit log.
Interview card: Offboard delete · Download PNG · Open card page
Interview card: Noisy neighbor. One whale throttles the shared table. Move noisy tenant to dedicated table; same code via config. Contributor Insights → threshold → split table → retest.
Interview card: Noisy neighbor · Download PNG · Open card page

More cards: Ravi Sir's Cards.

Practice Tasks

About this scenario

London Legal LLP is a law business in London. Oliver Hughes looks after its IT and cloud work. They count money in GBP and run their AWS resources in the eu-west-2 Region. In the tasks below you do real jobs for them using what this lesson teaches. All names, account IDs, IP addresses and numbers are made up for practice.

0 / 16

Easy TENANT# prefix — 1

Why: Isolation.

What to do: Enter 1 if every app key starts with TENANT#tid.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Easy LeadingKeys IAM — 1

Why: Enforce.

What to do: Enter 1 if IAM uses dynamodb:LeadingKeys.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Easy Bind tid from JWT — 1

Why: Trust.

What to do: Enter 1 if tenant id comes from verified JWT not body alone.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Easy Email GSI under tenant — 1

Why: Unique.

What to do: Enter 1 if unique email GSI stays under TENANT# PK.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Easy Describe saas table

Why: CLI.

What to do: Describe table ShopApp

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Easy Tenant key YAML

Why: Sketch.

What to do: YAML: pk: TENANT#acme, sk: USER#u1.

How:
  1. Start from the top-level keys the task names.
  2. Indent child keys with 2 spaces (no tabs).
  3. Fill in each property with the value from the task.
  4. Click Check answer. Key order does not matter.

Easy Verify GSI empty after delete — 1

Why: Proof.

What to do: Enter 1 if offboard verifies GSI empty.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Medium Offboard Query delete — 1

Why: GDPR.

What to do: Enter 1 if offboarding Queries PK and batch deletes.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Medium Avoid admin Scan — 1

Why: Anti.

What to do: Enter 1 if admin should avoid full-table Scan.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Medium GSI also tenant-prefixed — 1

Why: Leak.

What to do: Enter 1 if GSI PK must include TENANT#.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Medium Isolate noisy tenant — 1

Why: Ops.

What to do: Enter 1 if noisy neighbors may get a dedicated table.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Medium IAM key YAML

Why: Name.

What to do: YAML: condition_key: dynamodb:LeadingKeys.

How:
  1. Start from the top-level keys the task names.
  2. Indent child keys with 2 spaces (no tabs).
  3. Fill in each property with the value from the task.
  4. Click Check answer. Key order does not matter.

Hard Start shared table — 1

Why: Start.

What to do: Enter 1 if SaaS often starts on one shared table.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Hard UI filter is not security — 1

Why: Truth.

What to do: Enter 1 if UI filters alone are not tenant security.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Hard Delete lab same day — 1

Why: Hygiene.

What to do: Enter 1 if lab-ddo-saas should be deleted same day.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Hard Link modeling chapter — 1

Why: Reuse.

What to do: Enter 1 if this project links the modeling chapter.

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.