Deploy with Docker (EC2 or bare metal)¶
Audience: DevOps who want a production-shaped docker run on an EC2
instance (or similar host) after subscribing on AWS Marketplace.
When you are done: You have pulled the Marketplace image, attached an IAM
instance profile with CheckoutLicense, and completed a masked run.
Prerequisites: Deployment options · Customer install
1. Subscribe and authenticate to Marketplace ECR¶
From your subscription page, copy the Marketplace ECR image URI and region.
On an EC2 instance in the subscribing account:
export AWS_REGION=us-east-1
aws ecr get-login-password --region "$AWS_REGION" \
| docker login --username AWS --password-stdin \
<account-id>.dkr.ecr.us-east-1.amazonaws.com
docker pull <marketplace-ecr-uri-from-subscription>
Pin a stable version tag from your subscription — not :latest.
2. Attach CheckoutLicense IAM to the host¶
The instance profile (or task role if using ECS Anywhere) must allow:
{
"Action": [
"license-manager:CheckoutLicense",
"license-manager:CheckInLicense"
],
"Resource": "*"
}
Standalone policy: iam-task-role.json.
Do not attach aws-marketplace:GetEntitlements, RegisterUsage, or
MeterUsage — container contract listings do not use them.
3. Create mask-rules.yaml¶
Scaffold from the source DB with privaci init, then review with privaci plan.
Do not hand-write the config:
export SOURCE_DB_URL='postgresql://user:pass@source-host:5432/app'
docker run --rm --read-only --tmpfs /tmp \
-e SOURCE_DB_URL \
-v "$(pwd):/work" -w /work \
<marketplace-ecr-uri>:<tag> \
init --source "$SOURCE_DB_URL" --output /work/mask-rules.yaml
docker run --rm --read-only --tmpfs /tmp \
-e SOURCE_DB_URL \
-v "$(pwd)/mask-rules.yaml:/config/mask-rules.yaml:ro" \
<marketplace-ecr-uri>:<tag> \
plan --config /config/mask-rules.yaml --source "$SOURCE_DB_URL"
Full flow: Quickstart — create mask-rules.yaml.
4. One-shot masking run¶
Replace placeholders. With an instance profile, omit static AWS_* credential
env vars — the SDK picks up the role automatically.
export AWS_REGION=us-east-1
export SOURCE_DB_URL='postgresql://user:pass@source-host:5432/app'
export TARGET_DB_URL='postgresql://user:pass@target-host:5432/staging'
export ANONYMIZATION_SALT="$(openssl rand -hex 32)"
docker run --rm --read-only --tmpfs /tmp \
-e AWS_REGION \
-e SOURCE_DB_URL -e TARGET_DB_URL -e ANONYMIZATION_SALT \
-v "$(pwd)/mask-rules.yaml:/config/mask-rules.yaml:ro" \
<marketplace-ecr-uri>:<tag> \
run --config /config/mask-rules.yaml
Expected: exit 0. Exit 5 → Licensing.
Staging listing override¶
When testing against a container staging listing before the production image bakes the ProductSKU:
export PRIVACI_MARKETPLACE_PRODUCT_SKU='<staging-product-sku>'
Production Marketplace images do not require this variable.
4. Compliance report (optional)¶
Requires Compliance tier and a signing key — see Signed reports.
RUN_ID='<uuid from run output>'
docker run --rm --read-only --tmpfs /tmp \
-e TARGET_DB_URL \
-e PRIVACI_REPORT_SIGNING_KEY_PEM="$(cat report-signing.pem)" \
-v "$(pwd)/out:/out" \
<marketplace-ecr-uri>:<tag> \
report --run "${RUN_ID}" --format json --output /out/report.json
5. Production hardening¶
| Practice | Why |
|---|---|
| Instance in private subnet + NAT | Postgres stays in-VPC |
| Secrets from SSM/Secrets Manager | Never bake DSNs into AMIs |
| Cron or systemd timer | Schedule recurring staging refreshes |
| Pin image tag | Reproducible runs; upgrade deliberately |
| Move to ECS when ready | Deploy on AWS ECS — same image, managed RunTask |
GHCR fallback (non-production)¶
Contributors and pre-fulfillment smoke may use:
docker pull ghcr.io/boundarylogic/privaci-commercial:<tag>
This path does not replace Marketplace ECR for paid production deployments.