End-to-end reference implementation for C2PA signing and verification on a fully serverless AWS stack (API Gateway + Lambda + S3 + DynamoDB + KMS + CloudFront). Signing keys live in AWS KMS asymmetric keys (ECC_NIST_P256) and the trust anchor (Root CA) lives in the same stack, so the repo is self-contained for end-to-end testing.
Companion article (Japanese): 【AWS×C2PA】署名・検証パイプラインをサーバーレスで組む.
Source: docs/c2pa-aws-serverless-demo.mmd (Mermaid).
- Frontend: Vite + React + TypeScript (served from S3 via CloudFront).
- Backend: Python 3.12 Lambda × 4 (upload / verify / list-assets / delete-asset).
- API: API Gateway REST API (regional), one stage
v1. - IaC: Terraform (AWS Provider 6.x).
- Keys: 2 KMS asymmetric keys — Root CA + leaf signer.
- Auth: IP allowlist via AWS WAF v2, attached to both CloudFront and the REST API stage.
- AWS CLI with an SSO profile (e.g.
AWS_PROFILE=c2pa) so Terraform can hit the AWS APIs. miseinstalled (brew install miseor similar).- Docker is NOT required — the Lambda layer is built from manylinux wheels with
uv pip install.
mise install # terraform / python / uv / node
mise run install # uv sync + npm install
cp terraform/terraform.tfvars.example terraform/terraform.tfvars
# Open terraform.tfvars and add your own IP to allowed_ips.allowed_ips is required — terraform plan fails if it is empty. Every browser-facing path (CloudFront and API Gateway) is gated by this list.
mise run tf-init
mise run layer-build # produces build/layer.zip for the Lambda layer
mise run tf-apply # provisions KMS / S3 / DynamoDB / Lambda / APIGW / CloudFront / WAF
mise run certs # issues Root CA + leaf certificates and uploads them to the certs bucket
mise run front-build # Vite build
mise run front-deploy # syncs to S3 and invalidates CloudFrontAfter tf-apply finishes the outputs include the CloudFront domain. Open it in a browser and walk through Upload → Assets → Verify.
- Upload tab: drop a JPEG and click "Upload & sign". Status flips to
signedimmediately. - Assets tab: confirm the row appears with the signed asset link.
- Verify tab: drop the same (or any C2PA-signed) file. Expected:
validation_state = Trustedfor assets signed by this stack,Validfor foreign C2PA-signed files.
mise run tf-destroyKMS keys go into a 7-day PendingDeletion window (configurable via kms_deletion_window_in_days).
terraform/— AWS resource definitions (KMS, S3, DynamoDB, Lambda, API Gateway, CloudFront, WAF).lambda/{upload,verify,list_assets,delete_asset}/— Lambda handlers.scripts/issue-certs.py— issues Root CA and leaf certs via KMS.scripts/build-layer.sh— builds the Lambda layer (c2pa-python, cryptography, asn1crypto).scripts/deploy-frontend.sh— syncs the Vite build to S3.frontend/— Vite + React UI.

