Deployment — AWS
Syncret runs as a Lambda container function triggered by EventBridge CloudTrail rules. Each use case requires its own function instance and event rule — one function per monitored secret.
Prerequisites
- AWS CLI configured with sufficient permissions
- Docker with
buildxsupport - An ECR repository for the Syncret image
Supported events
| Event | CloudTrail source | Default action |
|---|---|---|
RotationSucceeded |
AWS Service Event via CloudTrail | Update target secret → optionally redeploy services |
PutSecretValue |
AWS API Call via CloudTrail | Redeploy services → optionally update target secret |
RotationFailed |
AWS Service Event via CloudTrail | Log warning, no action |
Event shapes
RotationSucceeded — emitted by AWS as a Service Event. requestParameters is null; the secret ARN lives in detail.additionalEventData.SecretId (capital S).
PutSecretValue — emitted as an API Call via CloudTrail. The secret ARN is in detail.requestParameters.secretId (lowercase s).
Syncret resolves the ARN based on eventName, not detail-type, since detail-type differs between the two event shapes.
ARN validation
After parsing, Syncret rejects any event whose secret ARN does not match SYNCRET_AWS_SECRET_ARN. This is the primary guard against the RDS rotation EventBridge rule, which fires on every RotationSucceeded in the account regardless of which secret rotated.
Step 1 — Create the IAM execution role
The Lambda function needs a role that allows it to read the source secret, optionally update the target secret, and optionally trigger ECS redeployments.
aws iam create-role \
--role-name syncret-execution-role \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}'
aws iam attach-role-policy \
--role-name syncret-execution-role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Create syncret-policy.json with the minimum required permissions — remove sections that don't apply to your use case:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": "arn:aws:secretsmanager:<region>:<account>:secret:<source-secret-name>-*"
},
{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue", "secretsmanager:PutSecretValue"],
"Resource": "arn:aws:secretsmanager:<region>:<account>:secret:<target-secret-name>-*"
},
{
"Effect": "Allow",
"Action": ["ecs:UpdateService", "ecs:DescribeServices"],
"Resource": "*"
}
]
}
aws iam put-role-policy \
--role-name syncret-execution-role \
--policy-name syncret-policy \
--policy-document file://syncret-policy.json
Step 2 — Push the image to ECR
Lambda requires images to be stored in ECR — it cannot pull from Docker Hub or other public registries directly. The public Syncret image is multi-arch (linux/amd64 and linux/arm64); Lambda requires a single-arch image, so you must specify the platform when pulling.
ARM64 (Graviton) is recommended for lower cost and better performance. The architecture you push must match the --architectures value in Step 3.
First, log in to ECR:
ECR=123456789012.dkr.ecr.us-east-1.amazonaws.com/syncret
VERSION=latest
aws ecr get-login-password --region us-east-1 \
| docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
Option A — Use the pre-built image from Docker Hub
# ARM64 (recommended)
docker pull --platform linux/arm64 fayrus/syncret:$VERSION
docker tag fayrus/syncret:$VERSION $ECR:$VERSION
docker push $ECR:$VERSION
# x86_64
docker pull --platform linux/amd64 fayrus/syncret:$VERSION
docker tag fayrus/syncret:$VERSION $ECR:$VERSION
docker push $ECR:$VERSION
Option B — Build from source
docker buildx build \
--platform linux/arm64 \
--provenance=false \
--build-arg VERSION=$VERSION \
-t $ECR:$VERSION \
--push .
Replace linux/arm64 with linux/amd64 to target x86_64.
Step 3 — Create the Lambda function
aws lambda create-function \
--function-name syncret-rds \
--package-type Image \
--code ImageUri=$ECR:$VERSION \
--architectures arm64 \
--role arn:aws:iam::123456789012:role/syncret-execution-role \
--timeout 60 \
--region us-east-1 \
--environment 'Variables={
SYNCRET_PROVIDER=aws,
SYNCRET_AWS_SECRET_ARN=arn:aws:secretsmanager:us-east-1:123456789012:secret:rds!db-00000000-0000-0000-0000-000000000000-AbCdEf,
SYNCRET_AWS_REGION=us-east-1,
SYNCRET_AWS_TARGET_SECRET_ARN=arn:aws:secretsmanager:us-east-1:123456789012:secret:my-app-secret-XyZaBc,
SYNCRET_TARGET_SECRET_KEYS=password,
SYNCRET_AWS_ECS_FORCE_DEPLOY=true,
SYNCRET_AWS_ECS_CLUSTER=my-cluster,
SYNCRET_AWS_ECS_SERVICES=backend,
SYNCRET_INSTANCE_NAME=Production,
SYNCRET_TIMEZONE=America/Lima
}'
Step 4 — Create the EventBridge rule
Each use case uses a different CloudTrail event shape and requires its own rule.
Database rotation rule
Triggers on RotationSucceeded. The ARN filter is applied inside Syncret via SYNCRET_AWS_SECRET_ARN since requestParameters is null for this event.
aws events put-rule \
--name syncret-rds-rotation \
--event-pattern '{
"source": ["aws.secretsmanager"],
"detail-type": ["AWS Service Event via CloudTrail"],
"detail": {
"eventSource": ["secretsmanager.amazonaws.com"],
"eventName": ["RotationSucceeded"]
}
}' \
--region us-east-1
aws lambda add-permission \
--function-name syncret-rds \
--statement-id syncret-rds-eventbridge \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn arn:aws:events:us-east-1:123456789012:rule/syncret-rds-rotation
aws events put-targets \
--rule syncret-rds-rotation \
--targets 'Id=syncret-rds,Arn=arn:aws:lambda:us-east-1:123456789012:function:syncret-rds' \
--region us-east-1
App settings rule
Triggers on PutSecretValue. The rule can filter by ARN prefix since requestParameters.secretId is available for this event.
aws events put-rule \
--name syncret-app-settings \
--event-pattern '{
"source": ["aws.secretsmanager"],
"detail-type": ["AWS API Call via CloudTrail"],
"detail": {
"eventSource": ["secretsmanager.amazonaws.com"],
"eventName": ["PutSecretValue"],
"requestParameters": {
"secretId": [{"prefix": "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-app-settings"}]
}
}
}' \
--region us-east-1
aws lambda add-permission \
--function-name syncret-app \
--statement-id syncret-app-eventbridge \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn arn:aws:events:us-east-1:123456789012:rule/syncret-app-settings
aws events put-targets \
--rule syncret-app-settings \
--targets 'Id=syncret-app,Arn=arn:aws:lambda:us-east-1:123456789012:function:syncret-app' \
--region us-east-1
ECS task definition
When service redeployment is enabled, Syncret only triggers new task launches — it does not inject secrets into containers. Your ECS task definition must already reference the target secret so ECS fetches the latest value at container startup:
{
"containerDefinitions": [{
"secrets": [{
"name": "DB_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-app-secret-XyZaBc:password::"
}]
}]
}
Configuration examples
Database rotation
Copies the rotated database password into an application secret and restarts services.
SYNCRET_PROVIDER=aws
SYNCRET_AWS_SECRET_ARN=arn:aws:secretsmanager:us-east-1:123456789012:secret:rds!db-0a0aa000-0a00-0a00-aaa0-0aa0a000a00a-AbdosSu
SYNCRET_AWS_REGION=us-east-1
SYNCRET_AWS_TARGET_SECRET_ARN=arn:aws:secretsmanager:us-east-1:123456789012:secret:my-app-secret-XyZaBc
SYNCRET_TARGET_SECRET_KEYS=password
SYNCRET_AWS_ECS_FORCE_DEPLOY=true
SYNCRET_AWS_ECS_CLUSTER=my-cluster
SYNCRET_AWS_ECS_SERVICES=backend
SYNCRET_INSTANCE_NAME="Production"
SYNCRET_TIMEZONE=America/Lima
SYNCRET_LOG_LEVEL=info
SYNCRET_LOG_FORMAT=json
App settings
Restarts services when an application secret changes. No target secret update needed — the app reads the source secret directly.
SYNCRET_PROVIDER=aws
SYNCRET_AWS_SECRET_ARN=arn:aws:secretsmanager:us-east-1:123456789012:secret:my-app-settings-XyZaBc
SYNCRET_AWS_REGION=us-east-1
SYNCRET_AWS_ECS_FORCE_DEPLOY=true
SYNCRET_AWS_ECS_CLUSTER=my-cluster
SYNCRET_AWS_ECS_SERVICES=app
SYNCRET_LOG_LEVEL=info
SYNCRET_LOG_FORMAT=json
Verify
Invoke the Lambda directly and check CloudWatch Logs:
aws lambda invoke \
--function-name syncret-rds \
--region us-east-1 \
--payload '{}' \
response.json && cat response.json
For a more realistic test, trigger a manual rotation with aws secretsmanager rotate-secret and confirm the Lambda executes via CloudWatch Logs.