-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path317-okta.mdc
More file actions
497 lines (350 loc) · 20.9 KB
/
Copy path317-okta.mdc
File metadata and controls
497 lines (350 loc) · 20.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
---
title: Okta Workforce Identity
description: Production patterns for Okta Workforce Identity - orgs, apps, users/groups, policies, lifecycle (SCIM), Workflows, Advanced Server Access, Admin API, and terraform-provider-okta.
priority: 317
alwaysApply: false
files:
include:
- "**/*okta*.*"
- "**/terraform-provider-okta/**"
- "**/*.tf"
- "**/*.tfvars"
- "**/.github/workflows/*.yaml"
- "**/.github/workflows/*.yml"
- "**/*sso*.*"
- "**/*saml*.*"
- "**/*scim*.*"
---
# Okta Workforce Identity
**Audience:** engineers designing, operating, or auditing Okta Workforce Identity (SSO, MFA, lifecycle, Workflows, Advanced Server Access).
**Scope:** Okta Workforce Identity Cloud (WIC). For Customer Identity Cloud (formerly Auth0), see Auth0 documentation - patterns overlap but are not identical.
> [!IMPORTANT]
> This rule complements:
>
> - `315-iam.mdc` - protocol reference (OIDC/SAML/PKCE/PKI)
> - `316-zero-trust.mdc` - Zero Trust principles (always-on)
> - `180-terraform.mdc` - Terraform patterns (for `terraform-provider-okta`)
>
> Use this rule for Okta-specific decisions: app config, policies, SCIM, Workflows, API usage, and Terraform modelling.
---
## Non-negotiables
- **MFA required for all users** (WebAuthn / FIDO2 preferred; TOTP acceptable; SMS is legacy)
- **Phishing-resistant MFA for privileged roles** (Super Admin, Org Admin, App Admin on sensitive apps)
- **No long-lived API tokens in code or config** - use OAuth 2.0 for Okta or scoped, rotated SSWS tokens in a vault
- **All apps use OIDC or SAML with signed responses**, audience and issuer validation, and short assertion lifetimes
- **Source of truth for identities is the HRIS** (Workday, BambooHR, etc.) or IdP-to-IdP federation, not manual Okta user creation
- **Audit log exported to SIEM** (System Log API or Event Hooks), retention aligned with policy
- **Terraform-managed org** (`terraform-provider-okta`) for any non-trivial config; no click-ops drift
---
## Org and Environment Model
### Orgs (tenants)
- **Production org** - real users, real apps
- **Preview/sandbox org** - test config changes, Workflows, API automations
- **Optional per-env orgs** for isolation of dev/stage/prod app configurations
### Realms (if using Identity Engine Realms)
- Use realms to segment user populations (employees, contractors, partners) with distinct policies
- Do not use realms as a substitute for separate orgs when compliance requires full isolation
### Admin access
- **No standing Super Admin** access for humans - use just-in-time elevation with approval
- **Scoped admin roles** (Group Admin, App Admin for specific apps) preferred over broad roles
- **Service principals for automation** use scoped admin roles, not Super Admin
---
## Apps
### OIDC vs SAML
- **Prefer OIDC** for modern web apps, SPAs, mobile, and API-consumers. Simpler, JSON-based, modern crypto.
- **SAML** only when the app requires it. Still common for legacy enterprise apps.
- **Neither** when the app supports SCIM + JWT / client-credentials directly from your own IdP.
### OIDC specifics
- **PKCE required** for public clients (SPA, mobile). See `315-iam.mdc` for the protocol detail.
- **No implicit flow** - deprecated. Use authorization code + PKCE.
- **Short-lived access tokens** (15-60 min); refresh tokens rotated on use.
- **Proper `aud`, `iss`, `sub`, `exp` validation** at every resource server.
- **JWKS-based signature validation** with rotation support.
- **Trusted origins** configured per app - only the origins that should redirect back.
### SAML specifics
- **SHA-256 signatures** (not SHA-1).
- **Signed and encrypted assertions** for sensitive apps.
- **Audience restriction** set to the exact SP.
- **NotBefore / NotOnOrAfter** tight (a few minutes).
- **NameID format** explicit (`emailAddress` or `persistent`, not `unspecified`).
- **Attribute statements** mapped from IdP profile, not Okta profile when IdP is source of truth.
### Per-app sign-on policies
Every app has its own Sign-On Policy. Not "default for all apps".
- **Default deny** - explicit allow rules per app
- **Context-aware rules** (network zone, device state, user risk)
- **Step-up auth** for high-risk apps
- **Session lifetime** appropriate for the app (shorter for admin consoles, longer for productivity apps)
---
## Users and Groups
### Source of truth
- **HRIS -> Okta** via SCIM or a connector (Workday, Workday Adaptive, BambooHR, UKG, etc.). HRIS creates/updates/deactivates.
- **Okta -> downstream apps** via SCIM (when the app supports it) or per-app provisioning connectors.
- **Never** manually create users in Okta for employees.
- **Contractors / partners** go through the same HRIS when possible; otherwise a documented exception with lifecycle automation.
### Group strategy
- **Group rules** (dynamic groups) driven by profile attributes - `department`, `cost_center`, `title`, `employee_type`.
- **Static groups** only for exceptions and admin-managed access bundles.
- **No "all users" as an access grant** for anything sensitive. Always narrow by group.
- **Naming convention**: `app-<app>-<role>` (e.g., `app-snowflake-analyst`, `app-aws-admin-prod`).
### Profile mapping
- **IdP profile is the master** for fields sourced from HRIS
- **Okta profile** adds Okta-specific fields (never override HRIS fields)
- **App profile** mapped from Okta profile with explicit transforms (not "pass-through everything")
---
## Authenticator and MFA Policies
### Authenticator policy
- **FIDO2 / WebAuthn** for all privileged users (Admins, sensitive app users)
- **Okta Verify** (push or OTP) as baseline
- **TOTP** acceptable as backup
- **SMS** deprecated - allow only as last-resort recovery, not primary factor
- **Email** not used as a factor (recovery only)
### Enrollment policy
- **Mandatory enrollment** at first sign-in
- **Multi-factor enrollment** required (at least two factors registered)
- **Self-service factor reset** only via phishing-resistant channels; otherwise helpdesk with identity-verification process
### Sign-on policy
- **MFA every sign-on** for sensitive apps
- **Device assurance** (managed device, biometric, screen lock) for high-sensitivity access
- **Risk-based prompting** using Okta ThreatInsight / Risk Scoring
---
## Lifecycle (JML)
### Joiner
- HRIS creates user with start date; SCIM pushes to Okta on or before start date
- Okta auto-assigns apps via group rules based on department/role/location
- First sign-in triggers MFA enrollment and password set
### Mover
- HRIS attribute change (department, manager, title) propagates via SCIM
- Group rules recompute; app access changes automatically
- Manual app assignments are audited and time-boxed
### Leaver
- HRIS termination triggers SCIM "delete" or "deactivate" to Okta
- Okta deactivation revokes all app access, terminates sessions, invalidates refresh tokens
- **Emergency off-boarding**: admin can deactivate immediately via Admin API or UI; still logged
- No user lingers in "suspended" state without a documented reason
---
## Okta Workflows vs Custom Code
### Use Workflows for
- Cross-app orchestration (e.g., "when a user joins group X, create mailbox in Y, ticket in Z")
- Notifications and approvals (Slack, email, ServiceNow)
- Light data transformations and attribute enrichment
- Scheduled jobs (nightly hygiene, stale account reports)
### Use custom code (your own services calling Okta API) for
- High-throughput automation (SCIM endpoint implementations, bulk provisioning)
- Integrations with systems Workflows doesn't support natively
- Anything that needs complex state, retry, or transactional semantics
- Anything that needs to live in your existing CI/CD and audit chain
### Either way
- Workflows and custom code both count as production - version-controlled exports, change review, environment separation (sandbox first).
---
## Admin API
### Auth
- **OAuth 2.0 for Okta** (client-credentials with scoped access) is preferred over SSWS tokens
- **SSWS tokens**, if used, are service-principal-owned, stored in a vault, rotated quarterly (or shorter), and scoped to minimum admin role
- **Never** commit SSWS tokens to source; never put them in env vars without vault brokering
### Rate limits
- **Honor `X-Rate-Limit-*` headers** on every response
- **Exponential backoff with jitter** on 429
- **Per-minute and per-org limits** - design for them (batch, pagination, parallelism caps)
- **Separate token per integration** so one misbehaving integration doesn't starve others
### Pagination
- **Always paginate** (`?limit=200` and follow `Link: <...>; rel="next"`)
- Do not assume a single page contains all results
### Idempotency
- Most Okta write operations are not idempotent. Build your own idempotency layer (e.g., check-then-act with `If-Match`, or a client-side ledger keyed by a stable external ID).
---
## Advanced Server Access (ASA)
For SSH / RDP access instead of static keys and shared accounts.
- **Per-user ephemeral certificates** minted on access (minutes, not months)
- **Group-based project access** mapped to Okta groups; aligned with least privilege
- **Session recording** on sensitive tiers
- **MFA on elevation** (sudo / admin commands)
- **No shared bastion credentials**; no `~/.ssh/authorized_keys` drift
---
## Terraform (`terraform-provider-okta`)
### Structure
- One module per concern (orgs, apps, groups, policies, authenticators)
- Environment workspaces (prod / preview) per org
- Sensitive values (SCIM secrets, SAML signing certs) from vault, not in state files
### State
- Remote state with encryption and access control (same as other infra)
- **Drift detection** scheduled: `terraform plan` nightly in CI, alert on drift
- Imports for pre-existing objects; do not clone-and-diverge
### Common resources
- `okta_app_oauth` / `okta_app_saml` - application definitions
- `okta_group` / `okta_group_rule` - groups and dynamic group rules
- `okta_policy_*` - authenticator, sign-on, password, MFA enrollment policies
- `okta_authenticator` - configure authenticators
- `okta_user_schema_property` - profile attributes
### Drift causes (plan for these)
- Click-ops in the UI (disable or limit admin UI where possible)
- Group rule evaluation (some state rebuilt server-side)
- App config changed by support / vendor sync
---
## Audit and System Log
- **Stream System Log to SIEM** via:
- Polling with pagination (simple but slow)
- Event Hooks (push-based; requires an HTTPS endpoint)
- Log Streaming (native to AWS EventBridge, Splunk, etc.)
- **Retention** per legal/regulatory requirements (typically 1-7 years for identity events)
- **Alerts** on:
- Admin role grants
- MFA factor removal / replacement
- Policy changes (especially authenticator and sign-on policies)
- User factor resets via support channel
- API token creation / rotation
- Anomalous sign-in patterns (ThreatInsight integration)
- Failed-then-succeeded auth bursts
- Off-network admin activity
---
## Do / Don't
| Area | Do | Don't |
|---|---|---|
| Admin | Just-in-time Super Admin; scoped roles default | Standing Super Admin for humans |
| API | OAuth 2.0 for Okta; scoped SSWS rotated | Long-lived SSWS in config; Super-Admin-scoped tokens |
| Apps | OIDC + PKCE; signed SAML | Implicit flow; SHA-1 SAML |
| MFA | WebAuthn for privileged; Okta Verify baseline | SMS as primary factor |
| Groups | Rule-driven from HRIS attrs | "All users" grants; manual membership sprawl |
| Lifecycle | HRIS as source; SCIM both directions | Manual Okta user creation for employees |
| Policy | Per-app sign-on policy, default deny | One "default" policy for everything |
| Terraform | Modularized, drift-detected | Mixed UI + Terraform edits |
| Audit | System Log to SIEM, alerting | System Log only in Okta UI |
| Automation | Workflows for orchestration; code for throughput | Workflows for critical-path bulk ops |
---
## Reviewer Checklist
Apps:
- [ ] OIDC uses authorization code + PKCE; no implicit
- [ ] SAML uses SHA-256; assertions signed; audience restriction set
- [ ] Per-app sign-on policy configured with default deny
- [ ] Trusted origins limited to known hosts
Users and groups:
- [ ] HRIS (or federated IdP) is source of truth
- [ ] SCIM configured inbound from HRIS and outbound to downstream apps that support it
- [ ] Group rules drive access; no "all users" grants
- [ ] Profile attribute mappings explicit, not pass-through
Policies:
- [ ] MFA required for all users
- [ ] Phishing-resistant MFA required for admins and sensitive apps
- [ ] Session lifetimes tuned per app sensitivity
- [ ] Device assurance enforced where warranted
Admin and API:
- [ ] No standing Super Admin on humans
- [ ] Scoped admin roles for service principals
- [ ] OAuth 2.0 for Okta used where supported; SSWS tokens scoped and in vault
- [ ] Rate-limit handling implemented (backoff, per-integration tokens)
Lifecycle:
- [ ] JML events flow HRIS -> Okta -> apps automatically
- [ ] Off-boarding revokes sessions and refresh tokens immediately
- [ ] No lingering suspended accounts without documented reason
Terraform:
- [ ] Non-trivial config managed by `terraform-provider-okta`
- [ ] State in remote backend, encrypted, access-controlled
- [ ] Drift detection scheduled
Audit:
- [ ] System Log streamed to SIEM
- [ ] Alerts on sensitive actions configured
- [ ] Retention meets legal requirements
---
## Cross App Access (XAA / ID-JAG)
**Cross App Access (XAA)** is Okta's branded implementation of the IETF OAuth **Identity Assertion JWT Authorization Grant (ID-JAG)** standard. ID-JAG is the spec; XAA is Okta's product. Both terms are essentially interchangeable. It extends OAuth 2.0 Token Exchange (RFC 8693) to solve app-to-app and **agent-to-app** access with the IdP as the broker.
Announced June 23, 2025; rolling into the Okta Platform through 2025-2026. Auth0 is adding ID-JAG support for ISVs. Initial ecosystem includes AWS, Box, Glean, Salesforce, Automation Anywhere, Boomi, Google Cloud, Grammarly, Miro, Writer.
### The problem XAA solves
Two existing patterns for app-to-app access, both broken at scale:
1. **API keys / shared secrets.** Each app stores credentials for each other app it needs to call. Sprawl, no rotation, no centralized revocation, no user context.
2. **User-granted OAuth.** Every user clicks consent for every app-to-app connection. Doesn't scale to agents (no UI) or enterprises (bypasses IT governance).
XAA makes the **IdP the broker** - admins configure which apps can talk to which other apps; the IdP issues short-lived tokens carrying user identity *and* requesting-app/agent identity.
### Three roles
- **Requesting App** - the agent or app that needs to call another app's API.
- **Resource App** - the app whose API is being called.
- **Identity Provider (IdP)** - Okta (or any ID-JAG-compliant IdP) brokers the trust.
### Protocol flow (simplified)
```
1. User logs in to Requesting App via Okta (OIDC). Requesting App
has an ID token + session.
2. Requesting App needs Resource App's API. It sends an Identity
Assertion request to Okta:
"I am Requesting App. User X is active. I want to call
Resource App with scope Y."
3. Okta evaluates XAA policy:
- Is Requesting App allowed to talk to Resource App?
- Is the user authorized?
- Which scopes are permitted?
4. Okta issues an ID-JAG (signed JWT) asserting:
- sub = user
- act = Requesting App (actor chain)
- aud = Resource App
- scopes
- short TTL (typically 5 minutes)
5. Requesting App posts the ID-JAG to Resource App's token
endpoint (RFC 8693 token exchange).
6. Resource App validates: signature against Okta JWKS, aud is
itself, trust relationship configured, user has corresponding
account.
7. Resource App issues its own access token, scoped appropriately.
8. Requesting App calls Resource App API with that access token.
Action logged with BOTH user identity AND Requesting App as
actor.
```
### Why this is significant
| Property | OAuth (user-granted) | Shared API keys | **XAA / ID-JAG** |
|---|---|---|---|
| Centralized access control | No | No | **Yes (IdP)** |
| Works for autonomous agents | No (consent UI) | Yes (but unsafe) | **Yes** |
| Short-lived credentials | Depends | Usually no | **Yes by design** |
| User identity preserved in call | Yes | No | **Yes** |
| Agent/app identity preserved | Weak | No | **Yes (first-class)** |
| Audit trail of both user + agent | No | No | **Yes** |
| Admin-revocable in one place | Per-app | No | **Yes** |
| Policy on cross-app connections | No | No | **Yes** |
### What XAA does NOT solve (be honest)
- **Cross-organizational trust.** XAA addresses the *single trust domain* case. Cross-org agent-to-app is still an open industry problem. The OAuth Identity Chaining draft is the spec to watch.
- **Revocation propagation.** Revoking at the IdP doesn't instantly invalidate Resource-App-issued tokens. They live until their TTL. Short TTLs are the mitigation; CAEP (Continuous Access Evaluation Profile) is the long-term answer.
- **Agent supply chain.** XAA tells the Resource App *which* Requesting App is calling, not whether its code was compromised. Pair with sigstore / SLSA / in-toto attestation.
- **Model-level data governance.** XAA governs *API access*. It does not prevent a misaligned agent from misusing data it legitimately fetched. That's an AI governance / DLP problem.
### When to use XAA
**Use XAA when:**
- The organization is already on Okta
- There are agentic apps (internal or SaaS) that need to call other SaaS apps
- The relevant SaaS vendors are in the XAA ecosystem (Salesforce, Box, Glean, AWS, etc.)
- Centralized policy + audit for app-to-app + agent-to-app is required
**Don't rely solely on XAA when:**
- Cross-organizational agent access is required (not yet solved)
- Integrations are custom internal services (use SPIFFE + mTLS via `318-workload-identity.mdc` - XAA is for the app layer, SPIFFE is for the infrastructure layer)
- Sub-second revocation propagation is required (XAA is TTL-based)
### XAA vs MCP vs A2A
- **MCP (Model Context Protocol, Anthropic)** defines *how* an agent talks to tools (the wire protocol for tool invocations).
- **A2A (Agent2Agent, Google)** defines how agents talk to each other.
- **XAA / ID-JAG** defines *how access is authorized* regardless of MCP, A2A, or direct API.
These are complementary. MCP is the agent's tool interface, A2A is agent-to-agent orchestration, XAA enforces "which user, via which agent, can reach which app" underneath all of it.
### Implementation notes
- **Requesting App** typically uses the Auth0 SDK (Node, Python, Go) for token exchange. Build it from scratch only if no SDK exists.
- **Resource App** must publish a token endpoint that accepts ID-JAG via RFC 8693 grant type `urn:ietf:params:oauth:grant-type:token-exchange`.
- **Admin setup in Okta**: Requesting App and Resource App both pre-registered; trust relationship and scope mapping configured by IT, not the user.
- **Conditional Access** policies still apply (device posture, network zone, MFA freshness).
### Hands-on
Okta runs a free no-signup playground at **`xaa.dev`** that walks the protocol in each role (Requesting App, Resource App, IdP) and includes an MCP server acting as a Resource App so the agent path is visible end-to-end. Worth 30 minutes before architectural decisions.
### Auth0 add-ons
- **Auth0 Token Vault** - cryptographically verified user-entity tokens and cross-domain access translation.
- **Auth0 FGA** - ReBAC engine (Zanzibar-inspired) for fine-grained agent permissions.
- **Auth0 for AI Agents** - SDKs specifically for adding identity-first security to AI apps.
---
## Common Anti-patterns
1. **Super Admin as "service account".** Use scoped roles; OAuth 2.0 for Okta.
2. **One Sign-On Policy for all apps.** Different apps have different risk profiles. Per-app.
3. **Manual user creation.** HRIS is source. Manual creation breaks lifecycle.
4. **SMS as primary MFA.** Phishing-resistant for admins; Okta Verify / WebAuthn baseline for the rest.
5. **Group Rules disabled for "performance".** If the rule is too expensive, the attributes or the rule is wrong. Fix the rule.
6. **SCIM disabled because "it's complex".** SCIM is the cheapest part of lifecycle. Enable it.
7. **`*.tf` files for everything in one module.** Modularize by concern; separate state files.
8. **Workflows running critical-path bulk operations.** Use code with proper observability and retry.
9. **System Log visited only by humans.** Stream to SIEM and alert; don't expect anyone to read it.
10. **"We'll tighten policies later."** "Later" never comes. Tighten at the start; loosen with an exception process.
---
## See also
- `315-iam.mdc` - IAM/OIDC/SAML/PKCE protocol reference
- `316-zero-trust.mdc` - Zero Trust principles and AI-agent Zero Trust
- `318-workload-identity.mdc` - infrastructure-layer identity (SPIFFE/SPIRE/cloud IAM); pairs with XAA at the app layer
- `412-aws-iam.mdc` - AWS IAM (for AWS-Okta SSO integration)
- `180-terraform.mdc` - Terraform patterns
- `330-observability.mdc` - SIEM integration and audit logging
- `310-security.mdc` - OWASP web + NHI Top 10 (for app-side auth bugs)
- `510-mcp-servers.mdc` - MCP servers as Resource Apps for XAA