This is a portfolio reference implementation. It processes synthetic data only — the fleet,
the customers and the readings are generated by data/ from a fixed seed, and no real
personal data has ever entered it. The AWS estate it deploys is stood up, driven and destroyed;
its resting state is a state bucket, a KMS key, three SSM parameters and a deploy role.
Open a GitHub issue, or contact the maintainer directly for anything you would rather not file in public. There is no bug bounty and no SLA.
No long-lived access keys exist. CI authenticates through GitHub OIDC to
watermark-deploy, whose trust policy names exactly four subjects — the deploy and destroy
environments of this repository, in both of the forms GitHub's claim can take. No IAM user can
assume it, which means no human can, from a laptop or from the console.
check_oidc_subjects.py refuses a trust policy that widens to a
branch or a wildcard.
Devices are pinned to their own topic. Each meter and charger carries its own X.509
certificate, and the IoT policy scopes publication with
${iot:Connection.Thing.ThingName} — so a compromised device can publish as itself and as
nothing else.
Data is encrypted with customer-managed keys, including one KMS key per data subject for the crypto-shredding path. Rotation is deliberately off on those keys: rotation retains the previous backing key so old ciphertext stays readable, and a shredding key that keeps a copy shreds nothing.
Access to the lakehouse is Lake Formation, and it is evaluated as well as applied.
make policy computes the full principal × resource lattice offline — 24 pairs, every reachable
set exact and every closed path closed — with no AWS account. The live estate matches it: the
account owner, with IAM administrator rights, cannot read a single column of
watermark_silver.meter_interval, and the catalogue does not list it for them.
Secrets are gated on every push. gitleaks runs in CI. No account id, credential or endpoint
is committed; the account id is resolved at deploy time from parameters infra/bootstrap
published.
- The estate is single-account, single-region, single-tenant. Everything is
eu-central-1. There is no network segmentation beyond one VPC with private subnets and interface endpoints, and no WAF, because nothing is publicly reachable. - One KMS key per data subject does not scale. Forty-one subjects here; a real fleet would be past the account quota. See ADR-0009.
- The account id is legible in terminal screenshots in
images/— inside bucket names and ARNs. It is the account this estate was destroyed in, and an account id is an identifier rather than a credential, but it is stated here rather than left to be noticed. - The processing container image is not scanned by any gate.
checkovreaches zero findings across the Terraform layers; nothing reads an ECR image scan. The image is built by CI from a pinned base, so the input is fixed and the build is checked, but advisories against that base are nobody's gate. - Erasure reaches a declared boundary, not the weights. A model trained before a request retains the subject statistically. The certificate says so on its face, quarantine plus retraining within a stated residual window is the mitigation, and machine unlearning is not claimed.