Use when working with AWS infrastructure, credentials, DNS/domains, Route53, CloudFront, S3 buckets, or Doppler secrets. Covers credential access patterns, domain setup, subdomain creation, and cross-account operations for GainInsight projects.
Directive knowledge for AWS infrastructure, credentials, DNS, and Doppler operations across GainInsight projects.
Load this skill when you need to:
| Item | Location |
|---|---|
| Doppler project/config | gi / prd |
| Access key variable | DOMAIN_ADMIN_AWS_ACCESS_KEY_ID |
| Secret key variable | DOMAIN_ADMIN_AWS_SECRET_ACCESS_KEY |
| Parent zone (gaininsight.global) | Z08261483JJZ016GFVDDQ |
Usage pattern:
doppler run --project gi --config prd -- bash -c '
AWS_ACCESS_KEY_ID=$DOMAIN_ADMIN_AWS_ACCESS_KEY_ID \
AWS_SECRET_ACCESS_KEY=$DOMAIN_ADMIN_AWS_SECRET_ACCESS_KEY \
AWS_DEFAULT_REGION=eu-west-2 \
aws route53 <command>'
| Item | Location |
|---|---|
| Registry | project-registry CLI |
| Query command | project-registry <project> [field] |
| Update command | project-registry set <project> <field> <value> |
project-registry juncan aws # Show AWS accounts
project-registry list # All project keys
project-registry find-by-team JKN # Find project by Linear team key
| Environment | Doppler Config | Typical Use |
|---|---|---|
| Development | dev | Local development, sandboxes |
| Staging/Test | stg | Test environment, CI/CD |
| Production | prd | Production environment |
MUST use Doppler for all secrets. No .env files, no hardcoded credentials.
MUST use domain admin credentials for Route53 changes. Project-level IAM users typically lack Route53 permissions.
MUST assume OrganizationAccountAccessRole for cross-account admin operations when project IAM user lacks permissions:
CREDS=$(doppler run --project gi --config prd -- aws sts assume-role \
--role-arn arn:aws:iam::{account-id}:role/OrganizationAccountAccessRole \
--role-session-name admin-operation --output json)
MUST store new credentials in Doppler immediately after creation. Never leave credentials in terminal history or temp files.
MUST create subdomain hosted zones for new projects, not records in parent zone.
MUST add NS delegation records from parent zone to subdomain zone after creation.
MUST use ACM certificates in us-east-1 for CloudFront custom domains (CloudFront requirement).
SHOULD check project registry before creating new resources - the account/config mapping may already exist.
SHOULD use CloudFront for public S3 content with custom domains (not S3 website URLs).
SHOULD prefer S3 website endpoint as custom origin over OAC when bucket is already public (simpler, no policy changes needed).
When: You need something.project.gaininsight.global pointing to an S3 bucket or other origin.
Steps:
Request ACM certificate in us-east-1:
doppler run --project {project} --config stg -- aws acm request-certificate \
--domain-name {subdomain}.{project}.gaininsight.global \
--validation-method DNS \
--region us-east-1
Get validation CNAME from certificate:
doppler run --project {project} --config stg -- aws acm describe-certificate \
--certificate-arn {arn} --region us-east-1 \
--query "Certificate.DomainValidationOptions[0].ResourceRecord"
Add validation record using domain admin credentials:
doppler run --project gi --config prd -- bash -c '
AWS_ACCESS_KEY_ID=$DOMAIN_ADMIN_AWS_ACCESS_KEY_ID \
AWS_SECRET_ACCESS_KEY=$DOMAIN_ADMIN_AWS_SECRET_ACCESS_KEY \
aws route53 change-resource-record-sets \
--hosted-zone-id {project-zone-id} \
--change-batch '"'"'{"Changes":[{"Action":"CREATE","ResourceRecordSet":{...}}]}'"'"''
Wait for certificate validation (2-5 minutes)
Create CloudFront distribution with certificate and custom domain alias
Add CNAME record pointing subdomain to CloudFront domain
When: Setting up a new project that needs *.project.gaininsight.global
Steps:
Create hosted zone:
doppler run --project gi --config prd -- bash -c '
AWS_ACCESS_KEY_ID=$DOMAIN_ADMIN_AWS_ACCESS_KEY_ID \
AWS_SECRET_ACCESS_KEY=$DOMAIN_ADMIN_AWS_SECRET_ACCESS_KEY \
aws route53 create-hosted-zone \
--name {project}.gaininsight.global \
--caller-reference "{project}-$(date +%s)"'
Note the 4 nameservers from the response
Add NS delegation to parent zone (Z08261483JJZ016GFVDDQ):
# Add NS record with the 4 nameservers
Store zone ID in project documentation (CLAUDE.md)
When: You need admin access that the project IAM user doesn't have.
Steps:
Assume OrganizationAccountAccessRole:
CREDS=$(doppler run --project gi --config prd -- aws sts assume-role \
--role-arn arn:aws:iam::{account-id}:role/OrganizationAccountAccessRole \
--role-session-name {operation-name} --output json)
export AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r '.Credentials.AccessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r '.Credentials.SecretAccessKey')
export AWS_SESSION_TOKEN=$(echo $CREDS | jq -r '.Credentials.SessionToken')
Run commands with elevated permissions
Unset credentials when done:
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
| Problem | Cause | Solution |
|---|---|---|
| "AccessDenied" on Route53 | Using project IAM user | Use domain admin credentials |
| "AccessDenied" on bucket policy | Project user lacks s3:PutBucketPolicy | Assume OrganizationAccountAccessRole |
| ACM cert stuck pending | Validation record not added | Add CNAME to correct hosted zone |
| CloudFront 403 errors | S3 bucket policy missing | Add CloudFront service principal or use website endpoint |
| "Certificate not in us-east-1" | ACM cert in wrong region | Request new cert in us-east-1 |
| Guide | Purpose |
|---|---|
| Layer 1: Infrastructure | Complete AWS setup walkthrough |
| GiDev Server Docs | Server-specific operations |
| File | Contains |
|---|---|
project-registry CLI | All project AWS accounts, Doppler configs |
/srv/docs/CREDENTIALS.md | Credential management patterns |
/srv/docs/ADMIN.md | Server administration including Cloudflare |
Remember:
gi/prd Doppler