# HealthBridge AWS Identity Center Migration & Permissions Guide ## Executive Summary This guide outlines the migration from Okta IAM SAML Federation to AWS Identity Center while maintaining the multiple-tile Okta interface required by security. It includes comprehensive permission set definitions for all teams (Developers, DevOps, Data, Security, QA, Connect) with automated Slack-based access management. ## Current State vs Future State ```mermaid graph TB subgraph "Current State: IAM SAML Federation" CO[Okta Login] --> CT[Multiple Account Tiles] CT --> CIAM[Shared IAM Roles:<br/>ManagementAccount-DevOps-Role<br/>ManagementAccount-Admins-Role<br/>etc.] CIAM --> CC[AWS Console] CIAM --> CPROB[PROBLEMS:<br/>- Dom adds S3 permission,<br/>Tim & Josh get it too<br/>- Manual IAM updates<br/>- No temp access<br/>- Poor audit trail] style CPROB fill:#ffebee,stroke:#c62828,color:#000 end subgraph "Future State: Identity Center with Deep Links" FO[Okta Login] --> FT[Multiple Account Tiles<br/>Same UX] FT --> FIC[Identity Center<br/>Deep Links] FIC --> FPS[Individual Permission Sets:<br/>Dom: DevOps-PowerUser + S3-Admin<br/>Tim: DevOps-PowerUser + EC2-Admin<br/>Josh: DevOps-PowerUser + RDS-Admin] FPS --> FC[AWS Console] FPS --> FBEN[BENEFITS:<br/>- Individual permissions<br/>- Slack automation<br/>- Temp elevated access<br/>- Full audit trail] style FBEN fill:#c8e6c9,stroke:#2e7d32,color:#000 end style CT fill:#fff9c4,stroke:#f9a825,color:#000 style FT fill:#e3f2fd,stroke:#1565c0,color:#000 ``` ## Permission Philosophy ### Account Classification ```mermaid graph TD subgraph "High Security Accounts" PROD[Production<br/>065532173824<br/>Restricted Access] MIRROR[Production-Mirror<br/>068217805200<br/>Restricted Access] end subgraph "Standard Security Accounts" DEV[Development<br/>658413592781<br/>Permissive Access] STAGING[Staging<br/>844077369820<br/>Permissive Access] TEST[Test<br/>035966626420<br/>Permissive Access] end subgraph "Administrative Account" MGMT[Management<br/>087797848983<br/>Organization Control] end style PROD fill:#ffcdd2,stroke:#c62828,color:#000 style MIRROR fill:#ffcdd2,stroke:#c62828,color:#000 style DEV fill:#c8e6c9,stroke:#2e7d32,color:#000 style STAGING fill:#fff9c4,stroke:#f9a825,color:#000 style TEST fill:#e1f5fe,stroke:#01579b,color:#000 style MGMT fill:#f3e5f5,stroke:#6a1b9a,color:#000 ``` ### Core Principle - **Production/Mirror**: Read-only by default, no database access for developers, time-limited elevated access - **Dev/Staging/Test**: Power-user access with guardrails, self-service deployments ## Permission Sets by Team ### Developer Permission Sets | Permission Set | Production/Mirror | Dev/Staging/Test | Duration | Approval | |---------------|------------------|------------------|----------|----------| | **Developer-Prod-ReadOnly** | ✅ View Beanstalk, logs, S3 | - | 12 hours | Auto | | **Developer-Prod-Deploy** | 🕐 Deploy code only | - | 2 hours | Manager | | **Developer-Prod-SSH** | 🕐 Session Manager only, recorded | - | 1 hour | Manager | | **Developer-NonProd-Standard** | - | ✅ Full Beanstalk, limited RDS | 12 hours | Auto | | **Developer-NonProd-Admin** | - | 🕐 Full control | 4 hours | Manager | | **Developer-NonProd-SSH** | - | ✅ Full SSH access | 12 hours | Auto | **Key Protections**: - NO database access in production/mirror accounts - SSH in production is Session Manager only with full recording - All production SSH sessions logged to S3 for audit ### DevOps Permission Sets | Permission Set | Scope | Duration | Approval | |---------------|-------|----------|----------| | **DevOps-PowerUser** | Everything except IAM/Org/Billing | 8 hours | Auto | | **DevOps-Infrastructure** | + VPC, Direct Connect, Transit Gateway | 4 hours | Manager | | **DevOps-Security** | + WAF, Security Groups, Shield | 4 hours | Manager | | **DevOps-BreakGlass** | AdministratorAccess | 30 min | 2-person | ### Data Team Permission Sets | Permission Set | Production/Mirror | Dev/Staging/Test | Duration | Approval | |---------------|------------------|------------------|----------|----------| | **DataScientist-Prod** | 👁️ SageMaker endpoints, S3 read | - | 8 hours | Auto | | **DataScientist-NonProd** | - | ✅ Full SageMaker, training | 12 hours | Auto | | **DataEngineer-Prod** | 👁️ Kinesis/Glue read-only | - | 4 hours | Manager | | **DataEngineer-NonProd** | - | ✅ Full pipeline control | 12 hours | Auto | | **DataAnalyst-Prod** | 👁️ Query-only access | - | 12 hours | Auto | ### Security Team Permission Sets | Permission Set | Scope | Duration | Approval | |---------------|-------|----------|----------| | **Security-Auditor** | Read everything, all accounts | 12 hours | Auto | | **Security-Incident** | Isolate resources, block IPs | 4 hours | Security Lead | | **Security-Admin** | Manage GuardDuty, Security Hub | 8 hours | Manager | ### QA Team Permission Sets | Permission Set | Scope | Duration | Approval | |---------------|-------|----------|----------| | **QA-Tester** | Read/test in Test/Staging | 8 hours | Auto | | **QA-Engineer** | Deploy test environments | 4 hours | Manager | ### Connect Team Permission Sets | Permission Set | Production/Mirror | Dev/Staging/Test | Duration | Approval | |---------------|------------------|------------------|----------|----------| | **Connect-Developer-Prod** | 👁️ View flows, metrics | - | 8 hours | Auto | | **Connect-Developer-NonProd** | - | ✅ Full development | 12 hours | Auto | | **Connect-Admin-Prod** | 🕐 Emergency fixes only | - | 2 hours | Manager | | **Connect-Admin-NonProd** | - | ✅ Full admin | 8 hours | Manager | ## Okta Tile Configuration with Deep Links ### Actual Tiles Based on Permission Sets ```mermaid graph LR subgraph "Okta Dashboard Tiles" subgraph "Production Access" T1[🔴 Prod - DevOps Power<br/>DevOps Team] T2[🟡 Prod - Developer Read<br/>All Developers] T3[🟡 Prod - Data Query<br/>Data Analysts] T4[🔴 Prod - Emergency Deploy<br/>On-Demand] T5[🔴 Prod - SSH Access<br/>Emergency Only] end subgraph "Non-Production Access" T6[🟢 Dev - Developer<br/>All Developers] T7[🟢 Dev - DevOps<br/>DevOps Team] T8[🟢 Dev - Data Engineer<br/>Data Team] T9[🟢 Test - QA Full<br/>QA Team] T10[🟢 Dev - SSH Access<br/>Developers] end subgraph "Administrative Access" T11[🔵 Mgmt - Security Audit<br/>Security Team] T12[🔵 Mgmt - DevOps Admin<br/>DevOps Team] end subgraph "Connect Access" T13[🟡 Prod - Connect View<br/>Connect Team] T14[🟢 Dev - Connect Build<br/>Connect Developers] end end style T1 fill:#ffcdd2,stroke:#c62828,color:#000 style T2 fill:#fff9c4,stroke:#f9a825,color:#000 style T3 fill:#fff9c4,stroke:#f9a825,color:#000 style T4 fill:#ffcdd2,stroke:#c62828,color:#000 style T5 fill:#ffcdd2,stroke:#c62828,color:#000 style T6 fill:#c8e6c9,stroke:#2e7d32,color:#000 style T7 fill:#c8e6c9,stroke:#2e7d32,color:#000 style T8 fill:#c8e6c9,stroke:#2e7d32,color:#000 style T9 fill:#c8e6c9,stroke:#2e7d32,color:#000 style T10 fill:#c8e6c9,stroke:#2e7d32,color:#000 style T11 fill:#e3f2fd,stroke:#1565c0,color:#000 style T12 fill:#e3f2fd,stroke:#1565c0,color:#000 style T13 fill:#fff9c4,stroke:#f9a825,color:#000 style T14 fill:#c8e6c9,stroke:#2e7d32,color:#000 ``` ### Deep Link Configuration Examples ```javascript // Okta Bookmark App Configuration for Real Permission Sets const tiles = [ // Production Tiles { name: "AWS Prod - DevOps Power", url: buildDeepLink("065532173824", "ps-devops-poweruser"), icon: "aws-red-gear.svg", color: "#D32F2F", groups: ["AWS-DevOps-Team"], description: "DevOps PowerUser access to production" }, { name: "AWS Prod - Developer Read", url: buildDeepLink("065532173824", "ps-developer-prod-readonly"), icon: "aws-yellow-eye.svg", color: "#FFA000", groups: ["AWS-Developers", "AWS-DevOps-Team"], description: "Read-only access to production resources" }, { name: "AWS Prod - SSH Access", url: buildDeepLink("065532173824", "ps-developer-prod-ssh"), icon: "aws-red-terminal.svg", color: "#D32F2F", groups: ["AWS-Developers", "AWS-DevOps-Team"], description: "Session Manager SSH to production (1 hour max)" }, { name: "AWS Prod - Data Query", url: buildDeepLink("065532173824", "ps-dataanalyst-prod"), icon: "aws-yellow-chart.svg", color: "#FFA000", groups: ["AWS-Data-Team"], description: "Query-only access to production data" }, // Development Tiles { name: "AWS Dev - Developer Full", url: buildDeepLink("658413592781", "ps-developer-nonprod-standard"), icon: "aws-green-code.svg", color: "#388E3C", groups: ["AWS-Developers"], description: "Full development access" }, { name: "AWS Dev - SSH Access", url: buildDeepLink("658413592781", "ps-developer-nonprod-ssh"), icon: "aws-green-terminal.svg", color: "#388E3C", groups: ["AWS-Developers"], description: "Full SSH access to development instances" }, { name: "AWS Dev - Data Engineer", url: buildDeepLink("658413592781", "ps-dataengineer-nonprod"), icon: "aws-green-pipeline.svg", color: "#388E3C", groups: ["AWS-Data-Engineers"], description: "Data pipeline development" }, // Connect Tiles { name: "AWS Prod - Connect View", url: buildDeepLink("065532173824", "ps-connect-developer-prod"), icon: "aws-yellow-phone.svg", color: "#FFA000", groups: ["AWS-Connect-Team"], description: "View Connect flows and metrics" }, { name: "AWS Dev - Connect Build", url: buildDeepLink("658413592781", "ps-connect-developer-nonprod"), icon: "aws-green-phone.svg", color: "#388E3C", groups: ["AWS-Connect-Developers"], description: "Build and test contact flows" }, // Management Account { name: "AWS Mgmt - Security Audit", url: buildDeepLink("087797848983", "ps-security-auditor"), icon: "aws-blue-shield.svg", color: "#1976D2", groups: ["AWS-Security-Team"], description: "Security audit access" } ]; function buildDeepLink(accountId, permissionSetId) { const baseUrl = "https://d-9267a80d73.awsapps.com/start"; const instanceId = "790720f893d1c6d2"; return `${baseUrl}#/saml/custom/${instanceId}/accounts/${accountId}/permission-sets/${permissionSetId}`; } ``` ## Slack Automation Implementation ### Access Request Flow ```mermaid graph TD subgraph "Slack Request Flow" U[User: /aws-access request] --> FORM[Select:<br/>- Account<br/>- Permission Set<br/>- Duration<br/>- Reason] FORM --> RISK{Risk Assessment} RISK -->|Low Risk| AUTO[Auto-Approve:<br/>- Developer-Prod-ReadOnly<br/>- Security-Auditor<br/>- Connect-Developer-Prod] RISK -->|Medium Risk| MGR[Manager Approval:<br/>- Developer-Prod-Deploy<br/>- DataEngineer-Prod<br/>- Connect-Admin-Prod] RISK -->|High Risk| SEC[Security Approval:<br/>- DevOps-BreakGlass<br/>- Security-Incident] AUTO --> GRANT[Grant Access] MGR -->|Approved| GRANT SEC -->|Approved| GRANT GRANT --> EXPIRE[Auto-Expire<br/>After Duration] end style U fill:#e3f2fd,stroke:#1565c0,color:#000 style AUTO fill:#c8e6c9,stroke:#2e7d32,color:#000 style MGR fill:#fff9c4,stroke:#f9a825,color:#000 style SEC fill:#ffcdd2,stroke:#c62828,color:#000 ``` ### Slack Bot Permission Logic ```python # Lambda Function: Real Permission Set Handler import boto3 import json from datetime import datetime, timedelta # Permission set configuration based on our design PERMISSION_SETS = { 'Developer-Prod-ReadOnly': { 'risk': 'LOW', 'max_duration': 12, 'auto_approve': True, 'accounts': ['065532173824', '068217805200'] # Prod & Mirror }, 'Developer-Prod-Deploy': { 'risk': 'MEDIUM', 'max_duration': 2, 'requires': 'manager', 'accounts': ['065532173824', '068217805200'] }, 'Developer-NonProd-Standard': { 'risk': 'LOW', 'max_duration': 12, 'auto_approve': True, 'accounts': ['658413592781', '844077369820', '035966626420'] # Dev, Staging, Test }, 'DevOps-PowerUser': { 'risk': 'MEDIUM', 'max_duration': 8, 'auto_approve': True, 'accounts': 'ALL' }, 'DevOps-BreakGlass': { 'risk': 'CRITICAL', 'max_duration': 0.5, # 30 minutes 'requires': ['manager', 'security'], 'mfa_required': True, 'accounts': 'ALL' }, 'DataAnalyst-Prod': { 'risk': 'LOW', 'max_duration': 12, 'auto_approve': True, 'accounts': ['065532173824', '068217805200'] }, 'DataEngineer-Prod': { 'risk': 'MEDIUM', 'max_duration': 4, 'requires': 'data-lead', 'accounts': ['065532173824', '068217805200'] }, 'Security-Auditor': { 'risk': 'LOW', 'max_duration': 12, 'auto_approve': True, 'accounts': 'ALL' }, 'Security-Incident': { 'risk': 'HIGH', 'max_duration': 4, 'requires': 'security-lead', 'auto_extend': True, 'accounts': 'ALL' }, 'Connect-Developer-Prod': { 'risk': 'LOW', 'max_duration': 8, 'auto_approve': True, 'accounts': ['065532173824', '068217805200'] }, 'Connect-Admin-Prod': { 'risk': 'MEDIUM', 'max_duration': 2, 'requires': 'manager', 'blackout_hours': '8-12,13-17', # Business hours EST 'accounts': ['065532173824', '068217805200'] } } def handle_access_request(event, context): """Process Slack access request based on real permission sets""" payload = json.loads(event['body']) user_email = payload['user']['email'] permission_set = payload['submission']['permission_set'] account_id = payload['submission']['account'] reason = payload['submission']['reason'] duration = float(payload['submission']['duration']) # Validate permission set exists if permission_set not in PERMISSION_SETS: return error_response(f"Unknown permission set: {permission_set}") ps_config = PERMISSION_SETS[permission_set] # Validate account access if ps_config['accounts'] != 'ALL': if account_id not in ps_config['accounts']: return error_response(f"{permission_set} not available for this account") # Validate duration if duration > ps_config['max_duration']: return error_response(f"Max duration is {ps_config['max_duration']} hours") # Check blackout windows for Connect-Admin-Prod if 'blackout_hours' in ps_config: if is_blackout_period(ps_config['blackout_hours']): return request_exception_approval(user_email, permission_set, "Blackout period") # Process based on risk level if ps_config.get('auto_approve'): grant_access(user_email, account_id, permission_set, duration) notify_slack(f"✅ Auto-approved: {user_email} granted {permission_set} " f"to {get_account_name(account_id)} for {duration} hours") else: create_approval_request(user_email, account_id, permission_set, duration, reason, ps_config.get('requires')) notify_slack(f"⏳ Approval pending for {user_email}: {permission_set}") return success_response() ``` ### Slack Commands ```yaml /aws-access list: description: "Show your current AWS access" response: | Your current AWS access: • Production (065532173824): Developer-Prod-ReadOnly - Expires in 4h • Development (658413592781): Developer-NonProd-Standard - Expires in 8h /aws-access request: description: "Request AWS access" form_fields: - Account: [Production, Development, Staging, Test, Management] - Permission Set: [Dynamically filtered based on your team] - Duration: [1h, 2h, 4h, 8h, 12h] - Reason: [Free text, required for audit] /aws-access extend [account]: description: "Extend existing access" rules: - Can only extend if <2 hours remaining - Cannot exceed original max duration - Requires re-approval for elevated permissions /aws-access emergency: description: "Emergency break-glass access" requirements: - Triggers PagerDuty - Requires incident ticket - Creates audit event - Maximum 30 minutes ``` ## Migration Execution Plan ### Phase 1: Foundation Setup ```bash #!/bin/bash # Create core permission sets first # Developer permission sets aws sso-admin create-permission-set \ --instance-arn $INSTANCE_ARN \ --name "Developer-Prod-ReadOnly" \ --description "Read-only access to production resources" \ --session-duration "PT12H" aws sso-admin create-permission-set \ --instance-arn $INSTANCE_ARN \ --name "Developer-NonProd-Standard" \ --description "Standard developer access to non-production" \ --session-duration "PT12H" # DevOps permission sets aws sso-admin create-permission-set \ --instance-arn $INSTANCE_ARN \ --name "DevOps-PowerUser" \ --description "DevOps power user access" \ --session-duration "PT8H" # Attach policies aws sso-admin put-inline-policy-to-permission-set \ --instance-arn $INSTANCE_ARN \ --permission-set-arn $PS_ARN \ --inline-policy file://policies/developer-prod-readonly.json ``` ### Phase 2: User Migration Matrix | Current IAM Role | Users | New Permission Set Assignments | |-----------------|-------|--------------------------------| | ManagementAccount-DevOps-Role | Dom, Tim, Josh | DevOps-PowerUser (base) + Individual adds | | → Dom specifically | | + S3-Admin permission set | | → Tim specifically | | + EC2-Admin permission set | | → Josh specifically | | + RDS-Admin permission set | | ManagementAccount-Developers-Role | 5 users | Developer-Prod-ReadOnly + Developer-NonProd-Standard | | ManagementAccount-Security-Role | 3 users | Security-Auditor (base) | | ManagementAccount-Admins-Role | 2 users | Removed, use DevOps-BreakGlass on-demand | ### Phase 3: Parallel Running ```mermaid graph LR subgraph Phase1["Week 1-2: Both Systems Active"] OLD["Old IAM Tiles<br/>Marked as OLD"] NEW["New Identity Center Tiles<br/>Marked as NEW"] BOTH[Both Available] end subgraph Phase2["Week 3-4: Validation"] TEST[Pilot Users Test] MONITOR[Monitor Usage] ADJUST[Adjust Permissions] end subgraph Phase3["Week 5+: Cutover"] DISABLE[Disable Old Tiles] REMOVE[Remove IAM Roles] COMPLETE[Migration Complete] end OLD --> TEST NEW --> TEST TEST --> MONITOR MONITOR --> ADJUST ADJUST --> DISABLE DISABLE --> REMOVE REMOVE --> COMPLETE style OLD fill:#ffccbc,stroke:#d84315,color:#000 style NEW fill:#c8e6c9,stroke:#2e7d32,color:#000 ``` ## Success Metrics ```yaml Technical Metrics: - Authentication success rate: >99.9% - Time to grant access via Slack: <2 minutes (auto), <10 minutes (approval) - Permission sets in use: Track actual vs assigned Security Metrics: - Standing privilege reduction: Target 80% reduction - Time-bound access percentage: >60% of all access - Audit compliance: 100% tracked in CloudTrail + DynamoDB User Experience: - Tile clicks to console: Still 1 click (maintained) - Access request satisfaction: >90% - Support tickets: -50% reduction expected Operational: - Manual IAM changes: -95% reduction - Individual vs shared permissions: 100% individual - Permission reviews: Automated weekly ``` ## Rollback Plan ```bash #!/bin/bash # Emergency rollback procedure echo "=== EMERGENCY ROLLBACK INITIATED ===" # 1. Re-enable old IAM federation tiles in Okta echo "Step 1: Reactivate old AWS IAM tiles in Okta" echo " Navigate to Okta Admin > Applications > Inactive" echo " Reactivate all 'OLD-AWS-*' applications" # 2. Notify all users curl -X POST $SLACK_WEBHOOK \ -d '{"text":"🚨 Reverting to old AWS access. Use original tiles (not NEW- prefix)."}' # 3. Verify IAM roles still exist for role in ManagementAccount-DevOps-Role ManagementAccount-Admins-Role; do aws iam get-role --role-name $role done # 4. Keep Identity Center active but unused echo "Identity Center remains configured for retry" echo "=== ROLLBACK COMPLETE ===" ``` ## Appendix: Permission Set Details ### Complete Permission Set Inventory | Permission Set | Risk | Max Duration | Auto-Approve | Approval Required | Accounts | |---------------|------|--------------|---------------|-------------------|----------| | Developer-Prod-ReadOnly | Low | 12h | ✅ | - | Prod/Mirror | | Developer-Prod-Deploy | Medium | 2h | ❌ | Manager | Prod/Mirror | | Developer-Prod-SSH | High | 1h | ❌ | Manager | Prod/Mirror | | Developer-NonProd-Standard | Low | 12h | ✅ | - | Dev/Stage/Test | | Developer-NonProd-Admin | Medium | 4h | ❌ | Manager | Dev/Stage/Test | | Developer-NonProd-SSH | Low | 12h | ✅ | - | Dev/Stage/Test | | DevOps-PowerUser | Medium | 8h | ✅ | - | All | | DevOps-Infrastructure | Medium | 4h | ❌ | Manager | All | | DevOps-Security | Medium | 4h | ❌ | Manager | All | | DevOps-BreakGlass | Critical | 30m | ❌ | Manager + Security | All | | DataScientist-Prod | Low | 8h | ✅ | - | Prod/Mirror | | DataScientist-NonProd | Low | 12h | ✅ | - | Dev/Stage/Test | | DataEngineer-Prod | Medium | 4h | ❌ | Data Lead | Prod/Mirror | | DataEngineer-NonProd | Low | 12h | ✅ | - | Dev/Stage/Test | | DataAnalyst-Prod | Low | 12h | ✅ | - | Prod/Mirror | | Security-Auditor | Low | 12h | ✅ | - | All | | Security-Incident | High | 4h | ❌ | Security Lead | All | | Security-Admin | Medium | 8h | ❌ | Manager | Management | | QA-Tester | Low | 8h | ✅ | - | Stage/Test | | QA-Engineer | Medium | 4h | ❌ | QA Lead | Stage/Test | | Connect-Developer-Prod | Low | 8h | ✅ | - | Prod/Mirror | | Connect-Developer-NonProd | Low | 12h | ✅ | - | Dev/Stage/Test | | Connect-Admin-Prod | Medium | 2h | ❌ | Manager | Prod/Mirror | | Connect-Admin-NonProd | Medium | 8h | ❌ | Manager | Dev/Stage/Test | ### Production Access Quick Reference | Team | Read Access | Write Access | SSH Access | Database | Approval | |------|------------|--------------|------------|----------|----------| | **Developers** | ✅ Beanstalk, CloudWatch | 🕐 Deploy only (2hr) | 🕐 Session Manager (1hr) | ❌ None | Manager | | **DevOps** | ✅ Everything | ✅ Everything except IAM | ✅ Full SSH | ✅ Full | None/2-person | | **Data** | ✅ S3, endpoints | ❌ None | ❌ None | 🕐 Read-only | Auto/Manager | | **Security** | ✅ Everything | 🕐 Incident (4hr) | ✅ Forensics | ✅ Read | Auto/Security | | **QA** | 👁️ Monitoring | ❌ None | ❌ None | ❌ None | N/A | | **Connect** | ✅ View flows | 🕐 Emergency (2hr) | ❌ None | ❌ None | Manager | **SSH Notes:** - Developer SSH in production uses Session Manager only with full recording - DevOps has unrestricted SSH access as part of PowerUser permissions - Security team has SSH for forensics during incidents - All production SSH sessions are logged to S3 bucket: `hbf-session-logs`