AWS security setup
What an AWS-backed Delphi deployment needs in terms of IAM, parameter-store layout, secrets-manager structure, ECR access, and instance-profile patterns.
Parameter and secret layout
All variables live under ${NAMESPACE} (e.g. voiceai/staging, voiceai/prod). Within that:
SSM Parameter Store
/${NAMESPACE}/<service>/<VAR> String, non-sensitive
/${NAMESPACE}/media/MEDIA_TLS_FULLCHAIN_B64 etc.
Secrets Manager
${NAMESPACE}/<service>/secrets JSON object with the sensitive keys
${NAMESPACE}/media/secrets shares MEDIA_TLS_PRIVKEY_B64 + MEDIA_UPLOAD_TOKEN
common/fetch-env.sh on each host reads the per-service vars.yaml, fetches the keys, validates required-ness, and emits export VAR=... lines that get evald into the shell. Values stay in process memory; nothing lands on disk.
IAM roles
Instance profile (per service host)
Each service host needs at minimum:
| Permission | Resource |
|---|---|
ssm:GetParameter*, ssm:DescribeParameters | arn:aws:ssm:<region>:<account>:parameter/${NAMESPACE}/<service>/* |
secretsmanager:GetSecretValue | arn:aws:secretsmanager:<region>:<account>:secret:${NAMESPACE}/<service>/* |
ecr:GetAuthorizationToken | * |
ecr:BatchGetImage, ecr:GetDownloadUrlForLayer | arn:aws:ecr:<region>:<account>:repository/voiceai-* |
s3:GetObject on CONFIG_BUCKET | arn:aws:s3:::${CONFIG_BUCKET}/* |
Ops Tasker (SES on EC2)
When EMAIL_TRANSPORT=ses:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ses:SendEmail", "ses:SendRawEmail"],
"Resource": "arn:aws:ses:<region>:<account>:identity/<verified-domain-or-email>"
}
]
}
Delphi Platform role (TelWeb)
When customer-side AWS features are enabled (read-only metadata calls), TelWeb assumes a cross-account role via STS:
- TelWeb env:
DELPHI_PLATFORM_ROLE_ARN,DELPHI_EXTERNAL_ID. - Customer side: a role with the matching external ID, scoped to the metadata the platform reads.
This replaces the legacy password-based platform setup; never re-introduce shared-secret patterns.
ECR
- Login — service
init.shrunsaws ecr get-login-password | docker loginusing the instance-profile credentials. - Repositories —
voiceai-telapi,voiceai-telweb,voiceai-telphi,voiceai-telsys,voiceai-telpro,voiceai-rtpengine,voiceai-webrtc,voiceai-audioproc,voiceai-scaler,voiceai-tasker,voiceai-media-server. - Tags —
ECR_TAGis the release version (e.g.v0.9.11). Don't uselatestin production deployments.
EC2 IMDS
When apps run with HTTP_PROXY / HTTPS_PROXY (every private-network service does):
-
Add
169.254.169.254toNO_PROXYso IMDS calls aren't proxied and fail silently. -
Set the IMDS hop limit to
2so containers on the Docker bridge can reach IMDS:aws ec2 modify-instance-metadata-options \--instance-id i-xxxxxxxx \--http-put-response-hop-limit 2 \--http-tokens required
If both static keys and the instance profile are set, the AWS SDK default chain prefers static keys and the instance-profile intent is defeated. Unset static keys when the instance profile is the intended source.
See also
- Ops operations — Scaler and Tasker run here, including SES.
- Configuration model — sources and lifecycle of every variable.
- v0.9.11 release notes — proxy-aware AWS Secret / LLM paths.