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, and describe-key as 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-provenance signs with the project's standard KMS key, referenced by the alias alias/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 with create-key, sign, verify, and describe-key. The same key must be used for signing and verifying, or verification will fail.

COMMANDS

create-provenance
amzn-api-provenance --service <service> create-provenance

Builds, signs, verifies, and writes the provenance record for the named service. Requires --service. Reads botocore-version.json and botocore-metadata.api from --input-path (default: the current directory) and locates the built <dist>-<version>.tar.gz tarball 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, a file:// reference to a file whose contents are signed (KMS RAW signing 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-file is required; the message is a literal string or a file:// reference (same 4096-byte limit). Prints the KMS Verify response; SignatureValid in the output is the result. This is the KMS-side check; for offline verification a consumer uses openssl instead (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 with alias/ automatically (with a warning). Defaults are ECC_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-pem

Writes 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 the Amazon::API GitHub repository (see "THE PUBLISHED PUBLIC KEY").

OPTIONS

--service, -s <name>

Botocore service to produce a record for (e.g. sts, sqs). Required by create-provenance.

--input-path, -i <dir>

Directory containing the build inputs botocore-version.json and botocore-metadata.api. Defaults to the current working directory.

--output-path, -o <file>

Destination for sign and export-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. Default ECC_NIST_P256.

--key-usage <usage>

KMS key usage used by create-key. Default SIGN_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. Default ECDSA_SHA_256 (matching the default ECC_NIST_P256 key).

--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 commit and version. 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.json model 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.json consumed (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::API generator 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::API version 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 .pm members, taken in sorted order. Scope: this digest covers the generated Perl modules -- the code a consumer runs. It does not directly cover the .api shape blob, POD, or MANIFEST. 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 .pm digest 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):

  1. Check out Amazon::API at the record's Amazon::API::BuildInfo::GIT_SHA, and botocore at the record's botocore.commit.

  2. Confirm the botocore inputs: the SHA-256 of service-2.json and paginators-1.json for the service must match the service-2.json and paginators-1.json fields in the record.

  3. Rebuild the distribution (make cpan-dist SERVICE=sts) and recompute the .pm digest as described in "THE PROVENANCE RECORD"; it must equal the record's digest.

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.