adnan koroth

System 05 — privileged access

JIT Access

Privileged-access management is one of the most expensive vendor categories in security, and most of the products are portals nobody opens. The actual requirement is small — a way to ask, a way to decide, a clock to revoke — and all of it can live where the team already is. JIT Access does that, in Slack, with no standing elevated permissions left behind.

Role design + build, end to end Runtime ECS + DynamoDB Surface Slack Socket Mode (no public endpoint) Boundary bounded session, auto-revoke

The problem

Vendor PAM (the well-known six-figure category) bundles a session vault, secret manager, an agent, a recording engine, and a portal — and charges for all of it whether you use the parts or not. Most teams need a much smaller thing: an engineer asks for elevated access, an owner approves it, and the access disappears on its own. Standing elevated permissions, even short-lived ones, are a category of liability that compliance frameworks (CIS, ISO 27001 A.9, OJK least-privilege) put pressure on directly, and the cheapest control is to never grant them in the first place.

What I built

A Slack-native just-in-time access portal that lives entirely inside the workspace. Identity stays in Okta and AWS IAM Identity Center; this system only mediates elevation.

  ┌────────────────┐     ┌─────────────────────────────────────────────┐
  │ engineer asks  │ ──▶ │ ECS service · DynamoDB state                │
  │ for elevation  │     │ write request → post Approve / Deny         │
  │ via /jit slash │     │ Block-Kit message in owner channel          │
  └────────────────┘     └─────────────────────────────────────────────┘

                    owner clicks ▼ in Slack
                    ┌────────────────────────────────────────────┐
                    │ grant elevated role (IAM Identity Center / │
                    │ STS AssumeRole) · write grant with TTL ·   │
                    │ notify requester                           │
                    └────────────────────────────────────────────┘

                    TTL expires → sweeper revokes
                    audit row persists for review

  Slack Socket Mode · no public endpoint · auto-expire
jit access — ask in Slack, approve in Slack, gone on a clock

Design decisions

Slack Socket Mode, not a public webhook

The integration is an outbound WebSocket from ECS to Slack. No public HTTP endpoint, no ingress to defend, no rotating webhook secret. The whole approve/deny surface lives inside the workspace's existing auth boundary.

Trade-off single Slack-workspace dependency. If Slack is down, new requests and approvals stall; existing grants continue to expire cleanly because the clock lives in Dynamo.

DynamoDB with TTL as the source of truth

The state model is small — request, grant, decision — and Dynamo's native TTL gives you "auto-revoke when the row dies" without an external cron. The table scales to zero between requests; the bill is effectively rounding error.

Trade-off Dynamo TTL is best-effort within minutes, not exact at the second. A sweeper enforces revocation at the IAM boundary so the revoke is always at least as tight as Dynamo's clock, never looser.

Approve in-channel, not in a portal

Decisions happen where the approver already lives. The request, the context, and the decision are one Slack thread, searchable forever, with the approver's identity already trusted by the Slack/Okta SSO chain. No second login, no portal anyone forgets to open.

Trade-off harder to enforce step-up MFA at the click than a dedicated portal would. Mitigated by short approval windows and a hardened Slack/Okta posture; for the very highest-blast-radius roles a WebAuthn challenge at approval time is the right next step (see below).

Bounded by design — no silent renewals

Sessions expire at the granted duration and require a fresh request to extend. Elevation does not slide forward by accident, and there is no "leave it open" mode.

Trade-off a small amount of friction for engineers who would rather keep a session warm. That friction is the feature: standing elevation is exactly what this system exists to remove.

Replaces vendor PAM, not vendor SSO

Identity remains in Okta and AWS IAM Identity Center. This system mediates elevation only, which keeps the scope and the attack surface small.

Trade-off not a full PAM — no secrets vault, no session recording, no agent. Chosen scope: the goal was the JIT lifecycle, not a Swiss-army-knife product.

Operating profile

Engineers request elevated access in Slack, account owners approve in Slack, and the access disappears on its own. The audit trail is the Slack thread plus the Dynamo grant record — no separate ticket queue, no portal anyone forgets to log into. Compliance auditors get a clean trail keyed to requester, approver, account, role, and duration, satisfying ISO 27001 A.9 / CIS / OJK least-privilege controls with a concrete, lived workflow.

What I would change

A WebAuthn step-up at the approval click for break-glass-tier roles — today the approver's Okta/Slack session is trusted, which is correct for most decisions but soft for the highest-blast-radius accounts. Pair that with a per-grant EventBridge scheduled revoke for those same tiers, so high-risk grants drop at the exact second rather than at Dynamo's best-effort. Both are fine to add incrementally; neither was needed to ship the system.