Skip to content

0042: Migrate Architecture Docs from Basic Auth to AWS Cognito with Google SSO

STATUS

Deferred

CONTEXT

The architecture-docs repository hosts our Architecture Decision Records (ADRs) and technical documentation at https://eng.adaction.com. Currently, the site is protected using AWS Amplify's basic authentication, which requires maintaining username/password credentials and lacks integration with our organization's identity management.

Current State Challenges

  1. Credential Management Overhead: Basic auth credentials must be manually shared with team members, stored in 1Password, and updated periodically
  2. No Single Sign-On (SSO): Users must remember separate credentials for documentation access rather than using their existing Google workspace accounts
  3. Limited Access Control: Basic auth provides all-or-nothing access without granular control based on user attributes or domains
  4. No Audit Trail: Limited visibility into who accessed the documentation and when
  5. Poor User Experience: Additional login step disconnected from primary authentication system

Requirements

  • Replace basic authentication with a more modern, maintainable solution
  • Integrate with existing Google workspace identity provider
  • Maintain access control restricted to authorized team members
  • Support domain-based access control (e.g., @adaction.com, @adgem.com)
  • Provide audit logging for authentication events
  • Maintain zero-downtime migration capability with rollback option
  • Document the solution for future maintenance

Considered Options

Option 1: Continue with Basic Authentication - Maintain status quo with username/password - Pros: No migration effort, simple configuration - Cons: All existing challenges remain unresolved

Option 2: AWS Cognito with Google as Federated Identity Provider - Use Amazon Cognito User Pool with Google OAuth integration - Implement domain whitelist via Lambda trigger - Integrate with AWS Amplify access control - Pros: Native AWS integration, SSO via Google, granular access control, audit logging - Cons: Additional AWS resources to manage, slightly more complex setup

Option 3: Third-party Auth Provider (Auth0, Okta) - Use external authentication service - Pros: Feature-rich, potentially easier management UI - Cons: Additional vendor cost, data leaves AWS ecosystem, requires third-party integration

Option 4: VPN or IP Allowlist - Restrict access to corporate network/VPN only - Pros: Simple network-level control - Cons: Doesn't solve credential sharing issue, limits remote access flexibility, no audit trail

Option 5: Public Documentation (No Auth) - Remove authentication entirely - Pros: Easiest user access - Cons: Unacceptable security posture for internal architectural decisions

Option 6: Create New AWS Account with CDK-Managed Infrastructure - Create a new AWS account dedicated to documentation infrastructure - Manage all infrastructure (Amplify, Cognito, Lambda) via AWS CDK (TypeScript) - Host architecture-docs Amplify app in the new account - Implement Cognito + Google SSO with full IaC from day one - Pros: - Complete infrastructure-as-code from the start - Isolated from main AdGem account (172122050326) - Version-controlled infrastructure changes - Reproducible and testable infrastructure - Cleaner separation of concerns - No need to work around existing manual configurations - Can leverage CDK best practices and patterns - Easier to implement security and compliance standards - Simpler migration (deploy to new account vs. modify existing) - Cons: - Additional AWS account to manage - Need to set up cross-account access/permissions if needed - Initial CDK stack development time - Requires AWS account creation approval - Potential AWS account costs (though minimal for this use case) - Team needs to learn/maintain CDK codebase

DECISION

DEFERRAL NOTE (January 2026): This ADR is deferred pending the implementation of centralized authentication per ADR 0039: Centralized Authentication Service using Amazon Cognito. Once the centralized Cognito infrastructure is operational for production services, we will evaluate whether architecture-docs can leverage the existing Cognito User Pool rather than creating a separate AWS account. This approach would reduce infrastructure duplication and align with the organization's centralized authentication strategy.

CHOSEN OPTION: Create New AWS Account with CDK-Managed Infrastructure (Option 6)

We will create a new AWS account dedicated to hosting the architecture-docs site, with all infrastructure managed via AWS CDK (TypeScript). This approach addresses both the authentication requirements and the underlying infrastructure management challenges.

Current State Challenges

The existing architecture-docs deployment runs in the main AdGem AWS account (172122050326), which is not managed via Infrastructure-as-Code. All Amplify configuration exists only in the AWS Console, making it difficult to version control, reproduce, audit, and maintain. Rather than adding manual Cognito configuration to an already manually-managed setup, we will start fresh with a fully IaC-managed approach.

Why Option 6 Over Option 2

While Option 2 (manual Cognito setup in existing account) would solve the authentication problem, Option 6 provides significantly more value:

  1. Infrastructure-as-Code from Day One: All resources version-controlled and reviewable via CDK
  2. Simpler Migration: Deploy to new account rather than modify existing manual configuration
  3. Account Isolation: Documentation infrastructure separate from production AdGem services
  4. Reproducibility: Can recreate entire stack in other environments if needed
  5. Best Practices: Leverage CDK patterns and TypeScript type safety
  6. Future-Proof: Foundation for managing other shared infrastructure as code

Solution Overview

Deploy architecture-docs to a new AWS account with complete CDK-managed infrastructure providing Amazon Cognito authentication with Google as a federated identity provider. This solution delivers:

Implementation Architecture

CDK Stack Structure: All infrastructure will be defined in TypeScript CDK stacks within the provision/ directory of the architecture-docs repository.

1. New AWS Account Setup

  • Account name: architecture-docs or adaction-docs
  • Purpose: Dedicated to documentation and shared tooling infrastructure
  • Integration with organization's AWS Organization for SSO and billing
  • Cost allocation tags for tracking

2. CDK Stack: Cognito Authentication

  • User Pool Resource (CfnUserPool or L2 construct)
    • User pool name: architecture-docs-user-pool
    • Self-signup disabled (controlled access)
    • Email verification enabled
    • Hosted UI configured
    • CloudWatch logging enabled
  • User Pool Domain (UserPoolDomain)
    • Cognito-provided domain for hosted auth UI
  • User Pool Client (UserPoolClient)
    • OAuth 2.0 flows: Authorization Code Grant
    • Scopes: openid, email, profile
    • Callback URLs configured for Amplify domain
  • Google Identity Provider (UserPoolIdentityProviderGoogle)
    • Google OAuth client ID and secret (from Secrets Manager)
    • Attribute mapping: email → email, name → name, sub → username
    • Scopes: openid email profile

3. CDK Stack: Domain Whitelist Lambda

  • Lambda Function (Function)
    • Runtime: Python 3.12
    • Handler: Domain whitelist validation logic
    • Environment variables: ALLOWED_DOMAINS (comma-separated list)
    • Attached to Cognito User Pool as pre-authentication trigger
  • Lambda Execution Role
    • CloudWatch Logs write permissions
    • Cognito trigger invocation permissions (managed automatically by CDK)

4. CDK Stack: Amplify Application

  • Amplify App Resource (App)
    • Repository: GitHub AdAction/architecture-docs
    • Build spec: References amplify.yml in repository root
    • Branch: main with auto-deploy enabled
  • Amplify Branch (Branch)
    • Access control: Cognito User Pool authentication
    • Environment variables for build if needed
  • Domain Configuration (optional future enhancement)
    • Custom domain: docs.adaction.com or similar
    • Route53 + ACM certificate management

5. CDK Stack: Supporting Resources

  • Secrets Manager Secrets
    • Google OAuth client ID and secret
    • Referenced by Cognito identity provider construct
  • CloudWatch Log Groups
    • Lambda function logs (retention: 30 days)
    • Cognito authentication audit logs
  • IAM Roles and Policies
    • Amplify service role for GitHub repository access
    • Lambda execution role (managed by CDK)

6. Repository Structure

architecture-docs/ ├── docs/ # Documentation content (existing) │ ├── architecture-decision-records/ │ ├── cognito-migration-guide.md │ └── template/ ├── provision/ # CDK infrastructure code (NEW) │ ├── bin/ │ │ └── architecture-docs.ts # CDK app entry point │ ├── lib/ │ │ ├── cognito-stack.ts # Cognito User Pool & IdP │ │ ├── amplify-stack.ts # Amplify App configuration │ │ ├── constructs/ # Reusable CDK constructs │ │ └── lambda/ │ │ └── pre-auth-trigger/ │ │ └── index.py # Domain whitelist code │ ├── test/ │ │ └── *.test.ts # CDK stack tests │ ├── cdk.json │ ├── package.json │ ├── tsconfig.json │ └── README.md # CDK deployment instructions ├── amplify.yml # Build specification ├── mkdocs.yml # MkDocs configuration └── requirements.txt # Python dependencies for docs

Migration Strategy

Phased Deployment Approach: Deploy to new account in parallel with existing deployment, then cutover DNS/URLs when ready.

  • Phase 1: AWS Account Setup
  • Request and create new AWS account within organization
  • Configure AWS Organization integration (SSO, billing, policies)
  • Set up GitHub Actions or similar for CDK deployments

  • Phase 2: Google OAuth Configuration

  • Create or reuse Google Cloud project
  • Configure OAuth consent screen (Internal)
  • Create OAuth 2.0 credentials
  • Store credentials in AWS Secrets Manager

  • Phase 3: CDK Stack Development

  • Develop CDK stacks in provision/ directory
  • Implement Cognito stack with Google IdP
  • Implement Lambda domain whitelist
  • Implement Amplify stack with Cognito integration
  • Write CDK tests

  • Phase 4: Infrastructure Deployment

  • Deploy CDK stacks to new AWS account
  • Verify all resources created correctly
  • Test Cognito hosted UI manually

  • Phase 5: Testing & Validation

  • Test authentication with users from allowed domains
  • Test rejection of unauthorized domains
  • Verify documentation site loads correctly
  • Monitor CloudWatch Logs for errors

  • Phase 6: Cutover

  • Update GitHub webhook to point to new Amplify app
  • Update any bookmarks/links to new URL
  • Notify team of new authentication URL
  • Monitor access logs and authentication events

  • Phase 7: Decommission Old Infrastructure

  • After successful operation (e.g., 30 days), decommission old Amplify app
  • Archive basic auth credentials from 1Password

Rollback Strategy: If critical issues arise, GitHub webhook can be quickly pointed back to the original Amplify app in the AdGem account. The old infrastructure will remain running during the transition period.

CDK Implementation Notes

  1. Secrets Management: Google OAuth credentials stored in AWS Secrets Manager, referenced by CDK stack
  2. Domain Whitelist Updates: Update Lambda environment variables via CDK code changes and redeploy
  3. Testing: CDK stack tests validate construct configuration before deployment
  4. CI/CD: GitHub Actions workflow for cdk synth, cdk diff, and cdk deploy
  5. Multi-Environment: CDK context can support dev/staging/prod if needed

Rationale for CDK + New Account Approach

This approach was chosen over manual configuration (Option 2) because:

  • Infrastructure-as-Code: All infrastructure changes version-controlled, reviewed, and auditable
  • Reproducibility: Entire stack can be recreated from code if needed
  • Clean Slate: No need to navigate existing manual configurations in AdGem account
  • Account Isolation: Documentation infrastructure separated from production services
  • Simpler Migration: Deploy new vs. modify existing = lower risk of breaking current access
  • TypeScript Type Safety: CDK TypeScript provides compile-time validation of infrastructure
  • Best Practices: Can implement AWS/CDK best practices from day one
  • Future Flexibility: Foundation for managing other shared tooling infrastructure as code
  • Cost Transparency: Dedicated account makes cost tracking straightforward

Additionally, Cognito + Google SSO specifically chosen for:

  • Native AWS Integration: Seamless integration with AWS Amplify
  • Cost Effective: No per-user licensing; ~$2/month for expected usage
  • Google SSO: Single sign-on with existing Google Workspace accounts
  • Domain Whitelist: Lambda triggers enable custom authentication logic
  • Audit Capability: CloudWatch Logs provide comprehensive authentication trail
  • OAuth 2.0 Security: Industry-standard security model

CONSEQUENCES

Positive Outcomes

  1. Improved User Experience
  2. Single sign-on via Google eliminates need to manage separate credentials
  3. Seamless authentication flow familiar to users
  4. No more sharing/managing basic auth credentials

  5. Infrastructure-as-Code Benefits

  6. All infrastructure changes version-controlled in GitHub
  7. Changes reviewed via pull requests before deployment
  8. Complete audit trail of infrastructure modifications
  9. Reproducible deployments across environments
  10. TypeScript provides compile-time validation of infrastructure

  11. Enhanced Security

  12. OAuth 2.0 standard security model
  13. Domain-based access control prevents unauthorized access
  14. Audit logging for compliance and security monitoring
  15. No shared credentials to rotate or leak
  16. Account isolation from production services

  17. Operational Excellence

  18. No manual credential distribution or rotation
  19. Automatic access via approved email domains
  20. Infrastructure changes deployed via CI/CD pipeline
  21. Easy to add/remove authorized domains (code change + deploy)
  22. CDK tests validate infrastructure before deployment

  23. Better Access Control

  24. Granular control via domain whitelist Lambda
  25. Easy to add/remove authorized domains via code
  26. Can add individual Cognito users if needed outside domain whitelist
  27. CloudWatch Logs provide comprehensive authentication trail

  28. Clean Architecture

  29. Documentation infrastructure isolated in dedicated AWS account
  30. No dependencies on manually-configured AdGem account resources
  31. Clear separation of concerns (docs vs. production services)
  32. Foundation for additional shared tooling infrastructure

Negative Outcomes

  1. Increased Initial Complexity
  2. More AWS resources to manage (Cognito, Lambda, Amplify, new account)
  3. CDK codebase to develop and maintain
  4. Team needs familiarity with CDK and Cognito concepts
  5. Initial development time for CDK stacks

  6. Additional AWS Account Management

  7. One more AWS account to include in organization policies
  8. Need to set up cross-account access if integration with other accounts needed
  9. Additional account in billing/cost tracking systems

  10. External Dependency

  11. Relies on Google OAuth availability
  12. If Google has outages, documentation access could be impacted
  13. Mitigation: Cognito also supports direct user creation as fallback

  14. Migration Effort

  15. Need AWS account creation approval process
  16. CDK stack development and testing time
  17. Users must re-authenticate after migration to new URL
  18. Need to update bookmarks and links
  19. Mitigation: Parallel deployment minimizes risk; old system remains available

  20. Cost Considerations

  21. New AWS account (no base cost, usage-based only)
  22. Cognito MAU costs (~$0.28/month for 50 users)
  23. Lambda invocations for domain whitelisting (negligible, within free tier)
  24. Amplify hosting (comparable to current costs)
  25. Overall estimated additional cost: < $5/month

  26. Team Learning Curve

  27. Team needs to learn/maintain CDK TypeScript codebase
  28. Understanding Cognito concepts for troubleshooting
  29. Learning new authentication flow for end users
  30. Mitigation: Comprehensive documentation and training

Risks

  1. CDK Deployment Failure
  2. Likelihood: Low
  3. Impact: High (infrastructure not created correctly)
  4. Mitigation: CDK unit tests, thorough code review, manual testing in dev environment before production, CI/CD pipeline validation

  5. AWS Account Approval Delays

  6. Likelihood: Medium
  7. Impact: Medium (delayed implementation timeline)
  8. Mitigation: Start account request process early, escalate if needed, consider manual Option 2 as fallback

  9. Google OAuth Misconfiguration

  10. Likelihood: Low (reduced by IaC)
  11. Impact: High (authentication failures)
  12. Mitigation: CDK code review, test with multiple users in deployed environment, comprehensive error handling

  13. Domain Whitelist Errors

  14. Likelihood: Low (reduced by code review)
  15. Impact: Medium (authorized users blocked or unauthorized users allowed)
  16. Mitigation: Lambda code with clear domain list, CDK tests, thorough testing, CloudWatch monitoring, easy rollback via code change

  17. CDK Stack Drift or Corruption

  18. Likelihood: Low
  19. Impact: High (infrastructure inconsistencies)
  20. Mitigation: Regular cdk diff checks, infrastructure monitoring, no manual console changes policy, state management best practices

  21. User Access Issues Post-Migration

  22. Likelihood: Low (parallel deployment reduces risk)
  23. Impact: Medium (users cannot access new docs)
  24. Mitigation: Parallel deployment allows thorough testing before cutover, old system remains available as fallback, immediate monitoring

  25. Team CDK Knowledge Gap

  26. Likelihood: Medium
  27. Impact: Medium (difficulty maintaining infrastructure)
  28. Mitigation: Comprehensive inline documentation, ADR context, team training session, clear README in provision/ directory

Affected Systems

New AWS Account (architecture-docs account): - AWS Amplify: New app with GitHub integration and Cognito authentication - Amazon Cognito: New User Pool, domain, app client, and Google IdP configuration - AWS Lambda: New function for pre-authentication domain whitelist trigger - AWS Secrets Manager: Google OAuth client credentials storage - CloudWatch Logs: Lambda logs, Cognito authentication audit logs - IAM: Service roles for Amplify and Lambda

Existing Systems: - GitHub Repository: AdAction/architecture-docs (add provision/ directory) - GitHub Actions: New or updated workflow for CDK deployments - Google Cloud Platform: OAuth client configuration (new or reused) - AWS Organization: Add new account to organization structure

Eventually Decommissioned: - AdGem AWS Account (172122050326): Existing Amplify app with basic auth (after successful migration)

Maintenance Responsibilities

Infrastructure Maintenance: - As Needed: Update CDK stacks via pull requests and deployments - Quarterly: Review CDK dependencies and update to latest versions - After Major AWS CDK Updates: Test and update CDK code if needed

Access Management: - As Needed: Update domain whitelist via CDK code change (update Lambda environment variables) - Quarterly: Review authorized domains list for accuracy - Monthly: Review CloudWatch Logs for authentication anomalies or errors

Monitoring & Operations: - Weekly: Check CloudWatch dashboards for authentication metrics (optional) - After Incidents: Review logs, adjust monitoring/alerting if needed - Annually: Review and optimize costs for the AWS account

Documentation: - As Needed: Update provision/README.md with any deployment process changes - After Major Changes: Update this ADR or create supplementary documentation

NOTES

References

  • ADR-0039: Centralized Authentication Service using Amazon Cognito (this ADR deferred in favor of evaluating centralized approach first)
  • ADR-0015: AWS Cognito for Status Page Authentication (similar pattern)
  • ADR-0012: Amazon Cognito + Laravel Sanctum for Targeted API

Implementation Timeline

  • Week 1-2: AWS account creation and CDK stack development
  • Request and provision new AWS account
  • Set up Google OAuth credentials
  • Develop CDK stacks for Cognito, Lambda, and Amplify
  • Write CDK tests
  • Week 3: Infrastructure deployment and testing
  • Deploy CDK stacks to new account
  • Test authentication flow with various user scenarios
  • Monitor CloudWatch Logs for issues
  • Week 4: Cutover and validation
  • Update GitHub webhook to new Amplify app
  • Coordinate team testing
  • Monitor production usage
  • Decommission old infrastructure after successful validation period

Original Author

Ron White

Deferral Date

January 15, 2026

Deferral Reason

Pending implementation of centralized Cognito authentication per ADR 0039. Once the centralized Cognito User Pool is operational for production services (Targeted API, Offer API, etc.), we will evaluate whether architecture-docs can integrate with that infrastructure rather than creating a separate AWS account. This reduces infrastructure duplication and aligns with the organization's authentication consolidation strategy.

Appendix

CDK Stack Configuration Summary

Primary CDK Constructs:

// Cognito User Pool
new cognito.UserPool(this, 'ArchitectureDocsUserPool', {
  userPoolName: 'architecture-docs-user-pool',
  selfSignUpEnabled: false,
  signInAliases: { email: true },
  standardAttributes: {
    email: { required: true, mutable: false }
  }
});

// Google Identity Provider
new cognito.UserPoolIdentityProviderGoogle(this, 'GoogleProvider', {
  clientId: secretsManager.Secret.fromSecretNameV2(...),
  clientSecret: secretsManager.Secret.fromSecretNameV2(...),
  scopes: ['openid', 'email', 'profile'],
  attributeMapping: {
    email: cognito.ProviderAttribute.GOOGLE_EMAIL,
    givenName: cognito.ProviderAttribute.GOOGLE_NAME,
    custom: { username: cognito.ProviderAttribute.GOOGLE_SUB }
  }
});

// Lambda Pre-Auth Trigger
const preAuthFn = new lambda.Function(this, 'PreAuthTrigger', {
  runtime: lambda.Runtime.PYTHON_3_12,
  handler: 'index.handler',
  code: lambda.Code.fromAsset('lib/lambda/pre-auth-trigger'),
  environment: {
    ALLOWED_DOMAINS: 'adaction.com,adgem.com'
  }
});

// Amplify App
new amplify.App(this, 'ArchitectureDocsApp', {
  sourceCodeProvider: new amplify.GitHubSourceCodeProvider({
    owner: 'AdAction',
    repository: 'architecture-docs',
    oauthToken: cdk.SecretValue.secretsManager('github-token')
  }),
  buildSpec: codebuild.BuildSpec.fromSourceFilename('amplify.yml')
});

Lambda Function: Domain Whitelist (Python)

Location: provision/lib/lambda/pre-auth-trigger/index.py

import os

ALLOWED_DOMAINS = os.environ.get('ALLOWED_DOMAINS', '').split(',')

def handler(event, context):
    email = event['request']['userAttributes'].get('email', '')
    domain = email.split('@')[-1].lower() if '@' in email else ''

    if domain not in ALLOWED_DOMAINS:
        raise Exception(f'Access denied: Email domain {domain} is not authorized')

    return event

Authorized Domains (configurable via CDK): - adaction.com - adgem.com

Cost Estimate

Based on estimated usage (50 users, avg 10 authentications/user/month):

  • AWS Account: $0 (no base cost, usage-based only)
  • Cognito MAU: $0.0055/MAU × 50 = $0.28/month
  • Lambda invocations: 500 invocations/month = ~$0.00 (within free tier)
  • CloudWatch Logs: Minimal storage/ingestion (< $1/month)
  • Amplify hosting: ~$1-2/month (similar to current)
  • Secrets Manager: $0.40/month/secret × 2 = $0.80/month

Total Estimated Additional Cost: < $5/month

CDK Development Checklist

CDK Stack Development: - [ ] Initialize CDK project in provision/ directory - [ ] Create Cognito stack with User Pool and Google IdP - [ ] Create Lambda stack with pre-auth trigger - [ ] Create Amplify stack with branch configuration - [ ] Write unit tests for CDK constructs - [ ] Set up GitHub Actions for CDK deployment - [ ] Document deployment process in provision/README.md

Pre-Deployment Validation: - [ ] AWS account created and accessible - [ ] Google OAuth credentials obtained and stored in Secrets Manager - [ ] CDK code reviewed by team - [ ] CDK unit tests passing - [ ] cdk synth produces valid CloudFormation templates - [ ] cdk diff reviewed for expected changes

Post-Deployment Validation: - [ ] All CDK stacks deployed successfully - [ ] Cognito User Pool created with correct configuration - [ ] Google IdP integrated and test login successful - [ ] Lambda trigger attached to Cognito - [ ] Test user from allowed domain can authenticate - [ ] Test user from denied domain is rejected - [ ] Amplify app deployed and builds successfully - [ ] Documentation site accessible via new URL - [ ] CloudWatch Logs show authentication events - [ ] No errors in Lambda or Cognito logs

Post-Migration Validation: - [ ] 5+ team members successfully authenticated - [ ] All documentation pages load correctly - [ ] Sign-out and re-authentication work - [ ] CloudWatch dashboards show healthy metrics - [ ] Old Amplify app webhook disabled - [ ] Team notified of new authentication URL - [ ] Bookmarks and links updated