drop-api-secrets-migration-evidence
drop-api Secrets Migration Evidence
Date: 2026-04-29T14:18:08Z Operator: Parisa Tabriz (Securion) MC: #10150 Outcome: BLOCKED — IAM permission gap prevents completion. Remediation documented below.
Pre-Migration State (drop-api)
Service ARN: arn:aws:apprunner:eu-west-1:324480209768:service/drop-api/bdebb303a47c409393691ef8f5530144 Status: RUNNING RuntimeEnvironmentVariables (plain-text — NAMES ONLY, no values):
- DATABASE_URL (CRITICAL — plain text, 1 of 2 secrets)
- JWT_SECRET (CRITICAL — plain text, 2 of 2 secrets)
- DROP_MODE (non-sensitive)
- PORT (non-sensitive) Total: 4 vars, 2 plain-text secrets
RuntimeEnvironmentSecrets: EMPTY (none configured) InstanceRoleArn: NULL (no instance role attached) AccessRoleArn: arn:aws:iam::324480209768:role/AppRunnerECRAccessRole (ECR pull only)
AWS Secrets Manager Verification (Step 3)
Both target secrets confirmed PRESENT and VALUES MATCH current plain-text:
| Secret Name | ARN | Value Match |
|---|---|---|
| drop/production/jwt_secret | arn:aws:secretsmanager:eu-west-1:324480209768:secret:drop/production/jwt_secret-QEsMUJ | MATCH |
| drop/production/database_url | arn:aws:secretsmanager:eu-west-1:324480209768:secret:drop/production/database_url-QEsMUJ | MATCH |
No new secrets needed. Existing SM entries are current and correct.
IAM Analysis (Step 4 — BLOCKER FOUND)
Finding 1: drop-api has NO instance role
drop-web (working SM integration) uses:
- InstanceRoleArn: arn:aws:iam::324480209768:role/drop-production-apprunner-instance
- This role has secretsmanager:GetSecretValue on drop/production/* secrets
drop-api has:
- InstanceRoleArn: NULL
Without an instance role, App Runner instances cannot call Secrets Manager. Attaching RuntimeEnvironmentSecrets without an instance role would cause service startup failure.
Finding 2: alai-cli-deployer lacks iam:PassRole
aws apprunner update-service requires iam:PassRole on both:
- The ECR access role (AppRunnerECRAccessRole) — needed even for config-only updates
- The instance role (drop-production-apprunner-instance) — needed to attach it
Exact errors:
AccessDeniedException: User alai-cli-deployer is not authorized to perform: iam:PassRole
on resource: arn:aws:iam::324480209768:role/drop-production-apprunner-instance
AccessDeniedException: User alai-cli-deployer is not authorized to perform: iam:PassRole
on resource: arn:aws:iam::324480209768:role/AppRunnerECRAccessRole
Target State (READY TO APPLY — pending IAM fix)
New source configuration built and saved to /tmp/drop-api-NEW-source-config.json (chmod 600):
RuntimeEnvironmentVariables (post-migration):
- DROP_MODE (non-sensitive, remains plain)
- PORT (non-sensitive, remains plain)
RuntimeEnvironmentSecrets (post-migration):
- DATABASE_URL → arn:aws:secretsmanager:eu-west-1:324480209768:secret:drop/production/database_url-QEsMUJ
- JWT_SECRET → arn:aws:secretsmanager:eu-west-1:324480209768:secret:drop/production/jwt_secret-QEsMUJ
InstanceRoleArn to attach: arn:aws:iam::324480209768:role/drop-production-apprunner-instance
Required IAM Grants (what must be added before migration can complete)
An IAM administrator (or role with iam:PutUserPolicy / iam:AttachUserPolicy) must grant alai-cli-deployer:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::324480209768:role/AppRunnerECRAccessRole",
"arn:aws:iam::324480209768:role/drop-production-apprunner-instance"
],
"Condition": {
"StringEquals": {
"iam:PassedToService": "build.apprunner.amazonaws.com"
}
}
}
]
}
Execute Command (ready — run after IAM grant)
aws apprunner update-service \
--service-arn arn:aws:apprunner:eu-west-1:324480209768:service/drop-api/bdebb303a47c409393691ef8f5530144 \
--source-configuration file:///tmp/drop-api-NEW-source-config.json \
--instance-configuration InstanceRoleArn=arn:aws:iam::324480209768:role/drop-production-apprunner-instance \
--profile alai-cli-deployer \
--region eu-west-1
Then verify:
aws apprunner describe-service \
--service-arn arn:aws:apprunner:eu-west-1:324480209768:service/drop-api/bdebb303a47c409393691ef8f5530144 \
--profile alai-cli-deployer --region eu-west-1 | jq '.Service.Status'
curl -sI https://app.getdrop.no/api/health | head -5
Expected: Status = RUNNING, HTTP 200.
Rollback Path
Rollback file: /tmp/drop-api-rollback-vars.json (chmod 600, contains plain-text values — /tmp only) Pre-migration full config: /tmp/drop-api-PRE-migration.json (chmod 600)
Rollback command (restores plain-text state, removes secrets indirection):
aws apprunner update-service \
--service-arn arn:aws:apprunner:eu-west-1:324480209768:service/drop-api/bdebb303a47c409393691ef8f5530144 \
--source-configuration "$(jq '.Service.SourceConfiguration' /tmp/drop-api-PRE-migration.json)" \
--instance-configuration Cpu=1024,Memory=2048 \
--profile alai-cli-deployer --region eu-west-1
Note: Rollback also requires iam:PassRole — same IAM grant needed.
Smoke Test (pending migration)
- Health endpoint: https://app.getdrop.no/api/health (per DEPLOY-MAP)
- Expected: HTTP 200, status: "ok"
- NOT YET EXECUTED — service not updated
Files (sensitive — /tmp only, never committed)
- /tmp/drop-api-PRE-migration.json (chmod 600) — full pre-state including plain values
- /tmp/drop-api-rollback-vars.json (chmod 600) — extracted plain env vars for rollback
- /tmp/drop-api-NEW-source-config.json — new source config ready to apply
No comments to display
No comments to display