# shoc-assessment-dynamo-reader (TEMPORARY) — TORN DOWN **Status (2026-08-07):** Role deleted in seahaven-prod as part of PLAT-11 prep (`./teardown-assessment-reader.sh`). Do not recreate for the kebab rename. SHOC steady-state access remains `procurement-api` + webhook only. --- Original design (historical): Time-boxed cross-account read role in **seahaven-prod (011934824531)** that lets the Luby team assess the procurement-ingest DynamoDB tables directly from **seahaven-external-dev (396287094661)** during their initial assessment. **This is not the steady-state access path.** SHOC's durable integration is the `procurement-api` SigV4 read API plus the `workorder-shoc-emitter` webhook. This role exists only so the team can eyeball raw tables while scoping that integration, and it self-expires. | Item | Value | |---|---| | Role | `arn:aws:iam::011934824531:role/shoc-assessment-dynamo-reader` | | Trusts | `arn:aws:iam::396287094661:root` restricted by `ArnLike aws:PrincipalArn` to `role/aws-reserved/sso.amazonaws.com/*` — human Identity Center sessions in external-dev only (no EC2/service/created roles) | | Hard expiry | `2026-08-23T00:00:00Z` — `DateLessThan` on `aws:CurrentTime` in BOTH the trust policy (new AssumeRole calls fail) and every permissions statement (in-flight sessions lose all data access at the same instant) | | Actions | `dynamodb:GetItem`, `Query`, `Scan`, `DescribeTable` | | Tables | `purchase-orders`, `verified-sites`, `pending-site-review`, `WorkOrders`, `WorkOrderComments` (+ `index/*` on each) | | KMS | `kms:Decrypt` on `seahaven-dynamodb-cmk` (`be5fa4cb-c546-40fe-a13d-c7bec79f5d12`), `kms:ViaService`-pinned to DynamoDB (the three po-ingest tables are CMK-encrypted); create script validates the key ARN against SSM `/seahaven/dynamodb/cmk-arn` before applying | | Session | 1h (chained sessions from SSO cap at 1h regardless) | ## Deliberate design choices (re-review before changing) - **Root trust + `aws:PrincipalArn` condition, no ExternalId.** The assessors are humans on Identity Center sessions in external-dev; console Switch-Role cannot pass an ExternalId, and there is no service deputy in this path. The `ArnLike` condition on the SSO role path restricts to human sessions without pinning a specific role ARN in `Principal` (role principals resolve to unique IDs and silently break when Identity Center reprovisions the permission set — a string condition survives that). - **`DescribeTable` added** beyond the requested GetItem/Query/Scan: the DynamoDB console item explorer and SDK table bindings require it (metadata-only). - **Not in CDK, not a table resource policy.** Table resource policies would re-open the cross-account grant surface deliberately zeroed on 2026-07-23 and trip `tests/test_cross_account_principal_pin.py`. A standalone role keeps the grant in one deletable object; the pin test's scope (cdk/) is intact. - **Reads are not access-logged** (no CloudTrail data events on these tables) — accepted for a 30-day read-only window. ## Data handling (communicate to Luby with the grant) Table contents are Sea Haven confidential and the work-order comment bodies are free text that may contain personal data. View/query for the assessment only; no bulk export or copies outside the AWS session; delete any local extracts when the assessment ends. The governing vendor agreement applies. ## Emergency revocation Fastest kill: run `./teardown-assessment-reader.sh`. A successful `DeleteRole` immediately invalidates all outstanding session credentials — and the script strips every inline/attached policy first, so `DeleteRole` cannot fail on `DeleteConflict` (including the `AWSRevokeOlderSessions` inline policy the console's "Revoke active sessions" button attaches). ## Usage (Luby side) Console: Switch Role → account `011934824531`, role `shoc-assessment-dynamo-reader`. Direct table deep-links: `https://us-east-1.console.aws.amazon.com/dynamodbv2/home?region=us-east-1#item-explorer?table=` CLI: ```bash aws sts assume-role \ --role-arn arn:aws:iam::011934824531:role/shoc-assessment-dynamo-reader \ --role-session-name luby-assessment aws dynamodb scan --table-name WorkOrders --max-items 25 # with the returned creds ``` ## Lifecycle - Create/update: `./create-assessment-reader.sh` (gated on GPT-4.1 cross-family review + `/sh-security-review` of these exact files). - Remove: `./teardown-assessment-reader.sh` when the assessment is done; the trust expiry is the backstop, not the plan. - Extend: edit the `DateLessThan` timestamp in **both** `trust-policy.json` AND every statement of `permissions-policy.json` (the expiry is enforced in both layers — extending only the trust policy yields a role that assumes but cannot read), then re-run both review gates before `create-assessment-reader.sh`.