NAME
amzn-api-provenance - create, sign, and verify provenance records for generated Amazon::API service distributions
SYNOPSIS
# produce a signed record for a built service distribution
amzn-api-provenance --service sts create-provenance
# verify a record's signature via KMS
amzn-api-provenance --key-alias alias/provenance-signing \
--signature-file Amazon-API-STS-1.43.103.sig \
file://Amazon-API-STS-1.43.103.json verify
# bring-your-own-key utilities
amzn-api-provenance --key-alias alias/my-signing create-key
amzn-api-provenance --key-alias alias/my-signing --output-path msg.sig sign file://msg.txt
amzn-api-provenance --output-path provenance-pub.pem export-pem
DESCRIPTION
Amazon::API::Provenance creates a signed provenance record for a generated Amazon::API service distribution (for example Amazon::API::STS). A provenance record answers a single question that a consumer downloading a prebuilt distribution cannot otherwise answer for themselves: are these bytes the faithful, untampered output of a known set of public inputs?
The record does not ask you to trust the build server. It records the public inputs the distribution was generated from -- the botocore commit and the SHA-256 of the exact service-2.json and paginators-1.json consumed, plus the Amazon::API version and git SHA of the generator -- together with a digest of the built modules, and it is signed with an AWS KMS asymmetric key whose public half is published. A consumer can verify the signature offline with nothing but openssl and the published public key, and an auditor can go further and reproduce the distribution from the recorded inputs to confirm the bytes independently (see "VERIFYING A RECORD").
This module is normally run as the amzn-api-provenance command during the distribution build (make cpan-dist), not called as a library.
This runs in your own AWS account
Every command here operates against your AWS account: create-key, create-provenance, sign, and verify call KMS (and SSM) with your credentials, create and use a KMS asymmetric key, and incur the associated AWS costs. Use --profile to select a named AWS profile. The official published records were produced in the Amazon::API project's account -- running these commands does not re-sign or alter those; it produces your own records signed with your own key.
Most people never need to run this module at all. To consume a prebuilt distribution and check it, you only need openssl and the published public key (see "VERIFYING A RECORD") -- no AWS account, no credentials, nothing from this module.
Where it is useful:
You run your own private DarkPAN and want to publish your own signed provenance records for the service distributions you build.
You want
create-key,sign,verify, anddescribe-keyas general KMS-backed signing utilities for messages you produce and check with your own key.
If neither applies, you are a consumer, not a producer -- skip to "VERIFYING A RECORD".
Managed key vs. your own key
The commands operate in one of two modes:
Managed mode (default).
create-provenancesigns with the project's standard KMS key, referenced by the aliasalias/provenance-signing. The key id is looked up in AWS SSM Parameter Store and the key is created on demand the first time it is needed. This is the mode the official build pipeline uses; you do not manage keys directly.Bring-your-own-key mode. Name your own key with
--key-alias(or--key-id) and manage it withcreate-key,sign,verify, anddescribe-key. The same key must be used for signing and verifying, or verification will fail.
COMMANDS
- create-provenance
-
amzn-api-provenance --service <service> create-provenanceBuilds, signs, verifies, and writes the provenance record for the named service. Requires
--service. Readsbotocore-version.jsonandbotocore-metadata.apifrom--input-path(default: the current directory) and locates the built<dist>-<version>.tar.gztarball in the current directory. On success it writes two files (see "OUTPUT FILES"), re-verifies the signature it just produced via KMS, and prints the names of the files written. If verification fails the command exits non-zero and the record is not trusted. - sign
-
amzn-api-provenance --key-alias <alias> [--output-path <file>] \ [--signing-algorithm <alg>] <message>Signs a message with the named KMS key and writes the raw signature to
--output-path(or standard output). The message is either a literal string argument or, more usefully, afile://reference to a file whose contents are signed (KMSRAWsigning is limited to messages of 4096 bytes). Use this in bring-your-own-key mode to sign an arbitrary message -- including a provenance record you produced yourself -- with a key other than the managed default. - verify
-
amzn-api-provenance --key-alias <alias> --signature-file <sig> \ [--signing-algorithm <alg>] <message>Verifies a message against a signature with the named KMS key.
--signature-fileis required; the message is a literal string or afile://reference (same 4096-byte limit). Prints the KMSVerifyresponse;SignatureValidin the output is the result. This is the KMS-side check; for offline verification a consumer usesopensslinstead (see "VERIFYING A RECORD"). - create-key
-
amzn-api-provenance [--key-spec <spec>] [--key-usage <usage>] \ [--key-description <text>] create-key <key-alias>Creates a KMS asymmetric signing key and its alias. The alias may be given as the positional argument or via
--key-alias; a bare name is prefixed withalias/automatically (with a warning). Defaults areECC_NIST_P256/SIGN_VERIFY. Prints the KMS create-key and create-alias responses as JSON. - describe-key
-
amzn-api-provenance describe-key <key-id-or-alias>Prints the KMS metadata for the given key id or alias as JSON. Useful for confirming a key's spec, usage, and state before signing.
- export-pem
-
amzn-api-provenance [--output-path <file>] export-pemWrites the public half of the signing key in PEM form to
--output-path(or standard output). This is the key a consumer verifies against; the authoritative published copy lives in theAmazon::APIGitHub repository (see "THE PUBLISHED PUBLIC KEY").
OPTIONS
- --service, -s <name>
-
Botocore service to produce a record for (e.g.
sts,sqs). Required bycreate-provenance. - --input-path, -i <dir>
-
Directory containing the build inputs
botocore-version.jsonandbotocore-metadata.api. Defaults to the current working directory. - --output-path, -o <file>
-
Destination for
signandexport-pem. Defaults to standard output. - --key-alias, -k <alias>
-
KMS key alias to sign or verify with. Defaults to
alias/provenance-signing. - --key-id <id>
-
KMS key id (or alias) to sign or verify with, as an alternative to
--key-alias. - --key-spec <spec>
-
KMS key spec used by
create-key. DefaultECC_NIST_P256. - --key-usage <usage>
-
KMS key usage used by
create-key. DefaultSIGN_VERIFY. - --key-description <text>
-
Description recorded on a key created by
create-key. Defaults to the alias. - --signature-file <file>
-
Signature to check. Required by
verify. - --signing-algorithm <alg>
-
KMS signing algorithm for
sign/verify. DefaultECDSA_SHA_256(matching the defaultECC_NIST_P256key). - --profile <name>
-
Named AWS profile to use for KMS/SSM calls.
- --log-level, -l <level>
-
Log4perl level (default
info).
THE PROVENANCE RECORD
The record is a canonical (sorted-key) JSON object. Canonical encoding matters: the signature is over the exact bytes, so the same record always serializes identically and re-verifies. The fields are:
- provenance_version
-
Schema version of the record itself (currently
1). - hash_algo
-
The digest algorithm used throughout the record (
sha256). - botocore
-
An object identifying the botocore source the service was generated from -- its
commitandversion. This, with the two file digests below, lets a verifier fetch the exact upstream inputs. - service-2.json
-
SHA-256 of the exact botocore
service-2.jsonmodel consumed. Because AWS revises a model in place without changing its api-version, this digest -- not the version string -- is what distinguishes one revision of a service model from another. - paginators-1.json
-
SHA-256 of the
paginators-1.jsonconsumed (absent if the service has no paginators file). Both inputs are recorded because both feed the generated output. - Amazon::API::BuildInfo::GIT_SHA
-
The git commit of the
Amazon::APIgenerator that produced the distribution. A version number alone is insufficient -- generation logic can change without a version bump -- so the SHA pins the generator for independent reproduction. - Amazon::API::BuildInfo::VERSION
-
The
Amazon::APIversion that produced the distribution. - module_name
-
The generated module (e.g.
Amazon::API::STS). - service
-
The service and its api-version date (e.g.
sts/2011-06-15). - tarball
-
The distribution filename (e.g.
Amazon-API-STS-1.43.103.tar.gz), so the record is self-identifying. - digest
-
The output digest that binds the built code: the SHA-256 of the concatenated, per-file SHA-256 hashes of the distribution's
.pmmembers, taken in sorted order. Scope: this digest covers the generated Perl modules -- the code a consumer runs. It does not directly cover the.apishape blob, POD, orMANIFEST. Those derived artifacts are covered indirectly: they are a deterministic function of the same botocore inputs already pinned above, so tampering with them would be caught by reproducing the build ("Tier 2: reproduce and compare"). The.pmdigest binds the code directly; the recorded botocore-input digests plus reproducibility bind everything derived from those inputs.
OUTPUT FILES
create-provenance writes two files, named after the distribution tarball with .tar.gz stripped:
<basename>.json # the canonical provenance record
<basename>.sig # the detached KMS signature (raw DER)
For Amazon-API-STS-1.43.103.tar.gz these are Amazon-API-STS-1.43.103.json and Amazon-API-STS-1.43.103.sig. The name is derived mechanically from the tarball name so that, given a distribution, a consumer can compute the names of its record and signature without a lookup.
DISTRIBUTION ON THE DarkPAN
On the official Amazon::API DarkPAN (https://cpan.openbedrock.net/orepan2) the record and signature for each published distribution live under a /signature directory, named as above. Given a tarball Amazon-API-STS-1.43.103.tar.gz, its record and signature are:
https://cpan.openbedrock.net/orepan2/signature/Amazon-API-STS-1.43.103.json
https://cpan.openbedrock.net/orepan2/signature/Amazon-API-STS-1.43.103.sig
THE PUBLISHED PUBLIC KEY
The authoritative public key is published in the Amazon::API GitHub repository (Amazon-API.pem at the repository root), deliberately not alongside the artifacts on the DarkPAN. Keeping the key in a separate trust domain from the artifacts is the point: a verifier who obtains the key from GitHub and checks DarkPAN artifacts against it is not relying on the DarkPAN to vouch for itself. A compromise of the DarkPAN alone cannot forge a record that verifies against the repository-hosted key.
VERIFYING A RECORD
Two levels of verification are available, requiring progressively less trust in the publisher's infrastructure.
Tier 1: verify the signature
Fetch the record and signature for the distribution, obtain the public key from the GitHub repository (not the DarkPAN), and verify with openssl -- no AWS access and no tooling from this project required:
openssl dgst -sha256 -verify Amazon-API.pem \
-signature Amazon-API-STS-1.43.103.sig \
Amazon-API-STS-1.43.103.json
Verified OK confirms the record was signed by the holder of the private key and has not been altered. This establishes that the recorded inputs and digests are authentic; it does not by itself prove the tarball matches them.
(The verify command performs the equivalent check server-side via KMS, which requires AWS credentials; the openssl form above is the offline path a consumer uses.)
Tier 2: reproduce and compare
To confirm the distribution's bytes independently -- trusting none of the publisher's infrastructure -- reproduce the build from the recorded inputs and compare. This requires the Amazon::API project checked out, not the installed module (only the cloned project can build a distribution):
Check out
Amazon::APIat the record'sAmazon::API::BuildInfo::GIT_SHA, and botocore at the record'sbotocore.commit.Confirm the botocore inputs: the SHA-256 of
service-2.jsonandpaginators-1.jsonfor the service must match theservice-2.jsonandpaginators-1.jsonfields in the record.Rebuild the distribution (
make cpan-dist SERVICE=sts) and recompute the.pmdigest as described in "THE PROVENANCE RECORD"; it must equal the record'sdigest.
Because the build is deterministic, a matching digest proves the published tarball is the faithful output of the recorded, publicly verifiable inputs.
SEE ALSO
Amazon::API, Amazon::API::AutoBuilder, https://cpan.openbedrock.net/orepan2
AUTHOR
Rob Lauer - <rlauer@treasurersbriefcase.com>
LICENSE
This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.