Skip to content

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 5Licensing.

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.