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
- Credential Management Overhead: Basic auth credentials must be manually shared with team members, stored in 1Password, and updated periodically
- No Single Sign-On (SSO): Users must remember separate credentials for documentation access rather than using their existing Google workspace accounts
- Limited Access Control: Basic auth provides all-or-nothing access without granular control based on user attributes or domains
- No Audit Trail: Limited visibility into who accessed the documentation and when
- 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:
- Infrastructure-as-Code from Day One: All resources version-controlled and reviewable via CDK
- Simpler Migration: Deploy to new account rather than modify existing manual configuration
- Account Isolation: Documentation infrastructure separate from production AdGem services
- Reproducibility: Can recreate entire stack in other environments if needed
- Best Practices: Leverage CDK patterns and TypeScript type safety
- 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-docsoradaction-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 (
CfnUserPoolor 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 name:
- 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.ymlin repository root - Branch:
mainwith auto-deploy enabled
- Repository: GitHub
- Amplify Branch (
Branch)- Access control: Cognito User Pool authentication
- Environment variables for build if needed
- Domain Configuration (optional future enhancement)
- Custom domain:
docs.adaction.comor similar - Route53 + ACM certificate management
- Custom domain:
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
- Secrets Management: Google OAuth credentials stored in AWS Secrets Manager, referenced by CDK stack
- Domain Whitelist Updates: Update Lambda environment variables via CDK code changes and redeploy
- Testing: CDK stack tests validate construct configuration before deployment
- CI/CD: GitHub Actions workflow for
cdk synth,cdk diff, andcdk deploy - 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
- Improved User Experience
- Single sign-on via Google eliminates need to manage separate credentials
- Seamless authentication flow familiar to users
-
No more sharing/managing basic auth credentials
-
Infrastructure-as-Code Benefits
- All infrastructure changes version-controlled in GitHub
- Changes reviewed via pull requests before deployment
- Complete audit trail of infrastructure modifications
- Reproducible deployments across environments
-
TypeScript provides compile-time validation of infrastructure
-
Enhanced Security
- OAuth 2.0 standard security model
- Domain-based access control prevents unauthorized access
- Audit logging for compliance and security monitoring
- No shared credentials to rotate or leak
-
Account isolation from production services
-
Operational Excellence
- No manual credential distribution or rotation
- Automatic access via approved email domains
- Infrastructure changes deployed via CI/CD pipeline
- Easy to add/remove authorized domains (code change + deploy)
-
CDK tests validate infrastructure before deployment
-
Better Access Control
- Granular control via domain whitelist Lambda
- Easy to add/remove authorized domains via code
- Can add individual Cognito users if needed outside domain whitelist
-
CloudWatch Logs provide comprehensive authentication trail
-
Clean Architecture
- Documentation infrastructure isolated in dedicated AWS account
- No dependencies on manually-configured AdGem account resources
- Clear separation of concerns (docs vs. production services)
- Foundation for additional shared tooling infrastructure
Negative Outcomes
- Increased Initial Complexity
- More AWS resources to manage (Cognito, Lambda, Amplify, new account)
- CDK codebase to develop and maintain
- Team needs familiarity with CDK and Cognito concepts
-
Initial development time for CDK stacks
-
Additional AWS Account Management
- One more AWS account to include in organization policies
- Need to set up cross-account access if integration with other accounts needed
-
Additional account in billing/cost tracking systems
-
External Dependency
- Relies on Google OAuth availability
- If Google has outages, documentation access could be impacted
-
Mitigation: Cognito also supports direct user creation as fallback
-
Migration Effort
- Need AWS account creation approval process
- CDK stack development and testing time
- Users must re-authenticate after migration to new URL
- Need to update bookmarks and links
-
Mitigation: Parallel deployment minimizes risk; old system remains available
-
Cost Considerations
- New AWS account (no base cost, usage-based only)
- Cognito MAU costs (~$0.28/month for 50 users)
- Lambda invocations for domain whitelisting (negligible, within free tier)
- Amplify hosting (comparable to current costs)
-
Overall estimated additional cost: < $5/month
-
Team Learning Curve
- Team needs to learn/maintain CDK TypeScript codebase
- Understanding Cognito concepts for troubleshooting
- Learning new authentication flow for end users
- Mitigation: Comprehensive documentation and training
Risks
- CDK Deployment Failure
- Likelihood: Low
- Impact: High (infrastructure not created correctly)
-
Mitigation: CDK unit tests, thorough code review, manual testing in dev environment before production, CI/CD pipeline validation
-
AWS Account Approval Delays
- Likelihood: Medium
- Impact: Medium (delayed implementation timeline)
-
Mitigation: Start account request process early, escalate if needed, consider manual Option 2 as fallback
-
Google OAuth Misconfiguration
- Likelihood: Low (reduced by IaC)
- Impact: High (authentication failures)
-
Mitigation: CDK code review, test with multiple users in deployed environment, comprehensive error handling
-
Domain Whitelist Errors
- Likelihood: Low (reduced by code review)
- Impact: Medium (authorized users blocked or unauthorized users allowed)
-
Mitigation: Lambda code with clear domain list, CDK tests, thorough testing, CloudWatch monitoring, easy rollback via code change
-
CDK Stack Drift or Corruption
- Likelihood: Low
- Impact: High (infrastructure inconsistencies)
-
Mitigation: Regular
cdk diffchecks, infrastructure monitoring, no manual console changes policy, state management best practices -
User Access Issues Post-Migration
- Likelihood: Low (parallel deployment reduces risk)
- Impact: Medium (users cannot access new docs)
-
Mitigation: Parallel deployment allows thorough testing before cutover, old system remains available as fallback, immediate monitoring
-
Team CDK Knowledge Gap
- Likelihood: Medium
- Impact: Medium (difficulty maintaining infrastructure)
- 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
- AWS CDK Documentation
- AWS CDK TypeScript API Reference
- Amazon Cognito Documentation
- AWS Amplify CDK Construct
- AWS Amplify Access Control
- Google OAuth 2.0 Documentation
- Cognito Lambda Triggers
- Migration Guide (Note: This manual guide is now superseded by the CDK approach but retained for reference)
- PR #85: docs: add AWS Cognito migration guide and ADR
- PR #102: fix: correct ADR 0042 filename anomaly
- PR #127: docs: backfill PR reference links for existing ADRs
- PR #137: feat: add cross-links and update all site URLs to custom domains
Related ADRs
- 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