pgpkms

command module
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2026 License: MIT Imports: 6 Imported by: 0

README

PGP KMS

Go

A Go command-line tool that integrates AWS Key Management Service (KMS) with PGP cryptography, enabling you to use AWS KMS asymmetric keys for PGP signing operations and export KMS public keys as PGP-compatible key blocks.

This project is inspired by https://github.com/hf/kmspgp, but tries to mimic the gpg command line interface and implements clearsign.

Features

  • Export KMS public keys as PGP public key blocks
  • Sign data using AWS KMS asymmetric keys with PGP formatting
  • Clear text signing for human-readable signed messages
  • Flexible input/output - works with files or stdin/stdout
  • ASCII armoring support for text-safe output

Installation

Prerequisites
  • Go 1.24.0 or later
  • AWS credentials configured (via AWS CLI, environment variables, or IAM roles)
  • AWS KMS asymmetric key (RSA or ECDSA) with SIGN_VERIFY usage
Build from source
git clone https://github.com/vinnterab/pgpkms.git
cd pgpkms
go build -o pgpkms

AWS KMS Key Requirements

Your AWS KMS key must be:

  • Asymmetric (not symmetric)
  • Key usage: SIGN_VERIFY
  • Key spec: RSA or ECDSA (e.g., RSA_2048, ECC_NIST_P256)

Usage

Export PGP Public Key

Export a KMS public key as a PGP public key block:

# Export with name and email
pgpkms --export -u arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012 \
       --export-name "John Doe" \
       --export-email "john@example.com"

# Export with ASCII armor
pgpkms --export -u arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012 \
       --export-name "John Doe" \
       --export-email "john@example.com" \
       --armor
Sign Files

Sign a file using a KMS key:

# Sign a file (creates input.txt.asc)
pgpkms --sign -u arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012 input.txt

# Sign with custom output file
pgpkms --sign -u arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012 \
       input.txt -o signature.sig

# Sign data from stdin to stdout
echo "Hello, World!" | pgpkms --sign -u arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012

# Sign data from an already-open file descriptor
pgpkms --enable-special-filenames --sign \
       -u arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012 \
       -&3

When --enable-special-filenames is set, positional input filenames may use GPG-style special filename syntax. -&N reads input from the already-open file descriptor N.

Clear Text Signing

Create human-readable signed messages:

# Clear sign a file
pgpkms --clear-sign -u arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012 message.txt

# Clear sign from stdin
echo "This is a test message" | pgpkms --clear-sign -u arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012

Command Line Options

Flag Short Description
--sign -s Sign a file using KMS key
--detach-sign -b Make a detached signature
--detach Alias for --detach-sign
--clear-sign Create a clear text signature
--clearsign Alias for --clear-sign
--export Export KMS public key as PGP key block
--export-name Name for the exported PGP key
--export-email Email for the exported PGP key
--export-comment Comment for the exported PGP key
--armor -a Use ASCII armored format for output
--armour Alias for --armor
--local-user -u Key ID, ARN, alias, UID, fingerprint, or key ID hex
--output -o Output file (default: input file + .asc)
--digest-algo Hash algorithm: sha1, sha256, sha384, sha512 (default: sha256)
--list-secret-keys -K List signing keys in GPG-compatible format
--with-colons Print key listings delimited by colons
--version Display version information (Formatted to be GPG compatible)
--status-fd Write status info to a file descriptor
--logger-fd Write log info to a file descriptor
--exit-on-status-write-error Exit if writing to status-fd fails
--enable-progress-filter Enable progress indicator reporting
--enable-special-filenames Enable GPG special filenames such as -&N for positional input
--charset No-op. Accepted for GPG compatibility
--batch No-op. Accepted for GPG compatibility
--no-tty No-op. Accepted for GPG compatibility
--no-greeting No-op. Accepted for GPG compatibility
--no-sk-comments No-op. Accepted for GPG compatibility
--homedir No-op. Accepted for GPG compatibility
--lc-ctype No-op. Accepted for GPG compatibility

Examples

Complete Workflow
  1. Create a KMS key (if you don't have one):

    aws kms create-key \
      --description "PGP signing key" \
      --key-usage SIGN_VERIFY \
      --key-spec RSA_2048
    
  2. Export the public key:

    pgpkms --export -u arn:aws:kms:us-east-1:123456789012:key/your-key-id \
           --export-name "Your Name" \
           --export-email "your.email@example.com" \
           --armor > publickey.asc
    
  3. Sign a document:

    pgpkms --sign -u arn:aws:kms:us-east-1:123456789012:key/your-key-id document.txt
    
  4. Verify the signature (using standard PGP tools):

    gpg --import publickey.asc
    gpg --verify document.txt.asc
    
Integration with CI/CD

Use pgpkms in CI/CD pipelines for secure artifact signing:

# Sign release artifacts
pgpkms --sign -u $KMS_KEY_ARN release.tar.gz

# Create detached signature
pgpkms --sign -u $KMS_KEY_ARN release.tar.gz -o release.tar.gz.sig
OSTree Commit Signing

pgpkms can replace gpg for signing OSTree commits, allowing you to use AWS KMS-backed keys instead of local GPG keyrings.

Setup: Tag your KMS key with PGPName and PGPEmail tags. These tags are used to build the PGP UID when listing keys (--list-secret-keys) and when resolving keys by UID via -u. This lets OSTree (and other tools) look up keys the same way they would with GPG.

aws kms tag-resource --key-id <key-id> \
  --tags TagKey=PGPName,TagValue="OSTree Signing Key" \
         TagKey=PGPEmail,TagValue="ostree@example.com"

Usage with OSTree: Symlink or alias pgpkms as gpg in your build environment, then use OSTree's standard signing workflow:

ln -s /path/to/pgpkms /usr/local/bin/gpg
ostree commit --sign-type=gpg --gpg-sign="OSTree Signing Key" ...

OSTree passes --status-fd, --batch, --no-tty, and other GPG flags that pgpkms accepts (see no-op flags above).

Replacing gpg in toolchains

The pgpkms cli is a clone of the gpg cli. This means that tools calling gpg can instead call pgpkms without any changes. A way to achieve that is symlink pgpkms to for instance /usr/local/bin/gpg in a build container/image.

Importing Existing GPG Keys into KMS

If you have an existing GPG key and import it into AWS KMS, the PGP fingerprint and key ID computed by pgpkms will not match the original key by default. This is because the PGP v4 fingerprint includes the key's creation timestamp, and KMS reports the import date rather than the original creation date.

To preserve the original fingerprint, tag your KMS key with PGPCreationTime set to the original key's creation time in RFC 3339 format.

1. Get the original creation time from GPG
# Replace KEYID with your key's fingerprint or ID
gpg --list-keys --with-colons KEYID | awk -F: '/^pub/{print $6}'

This prints a Unix timestamp (e.g., 1583064000). Convert it to RFC 3339:

date -u -d @1583064000 +%Y-%m-%dT%H:%M:%SZ
# Output: 2020-03-01T12:00:00Z

Or as a one-liner:

date -u -d @$(gpg --list-keys --with-colons KEYID | awk -F: '/^pub/{print $6}') +%Y-%m-%dT%H:%M:%SZ

On macOS, use date -u -r TIMESTAMP +%Y-%m-%dT%H:%M:%SZ instead.

2. Tag the KMS key
aws kms tag-resource --key-id <key-id> \
  --tags TagKey=PGPCreationTime,TagValue="2020-03-01T12:00:00Z"
3. Verify the fingerprint
# List keys from KMS
./pgpkms --list-secret-keys

# Compare against the original
gpg --list-keys

The fingerprints should now match.

Note: If the PGPCreationTime tag is missing, pgpkms falls back to the KMS creation date — existing keys that were created (not imported) in KMS are unaffected.

AWS Authentication

pgpkms uses the standard AWS SDK credential chain:

  1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
  2. AWS credentials file (~/.aws/credentials)
  3. IAM roles (for EC2 instances)
  4. AWS CLI profiles
Required IAM Permissions

Your AWS credentials need the following KMS permissions:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "kms:GetPublicKey",
                "kms:DescribeKey",
                "kms:Sign"
            ],
            "Resource": "arn:aws:kms:*:*:key/*"
        }
    ]
}

Architecture

The project is organized into clean, focused packages:

  • main.go - Entry point and AWS configuration
  • cmd/ - Command-line interface and argument parsing
  • kms/ - AWS KMS integration and key management
  • pgp/ - PGP key and signature generation

Development

Running Tests
# Run all tests
go test ./...

# Run tests with coverage
go test -cover ./...

# Run tests verbosely
go test -v ./...
Code Quality

This project uses GolangCI-Lint for linting Go code. It helps maintain clean, idiomatic, and error-free code by running multiple linters efficiently. You can install GolangCI-Lint by following the official instructions here.

# Format code
go fmt ./...

# Lint code
go vet ./...

# Build
go build -o pgpkms

# golangci-lint
golangci-lint run ./...

Security Considerations

  • Key Management: KMS keys are stored securely in AWS and never leave the service
  • Audit Trail: All KMS operations are logged in AWS CloudTrail
  • Access Control: Use IAM policies to control who can use which keys
  • Key Rotation: Consider using KMS automatic key rotation for enhanced security

Limitations

  • Only supports asymmetric KMS keys with SIGN_VERIFY usage
  • Cannot generate new KMS keys (use AWS CLI or Console)
  • PGP signatures are not timestamped (KMS limitation)

Contributing

Contributions are welcome! Please ensure:

  1. Code is properly formatted (go fmt)
  2. All tests pass (go test ./...)
  3. Code passes static analysis (go vet)
  4. New features include appropriate tests

License

This project is licensed under the MIT License - see the LICENSE file for details.

Troubleshooting

Common Issues

"Key not found" errors:

  • Verify the KMS key ARN is correct
  • Ensure your AWS credentials have access to the key
  • Check that the key exists in the correct AWS region

"Invalid key usage" errors:

  • Ensure the KMS key has SIGN_VERIFY usage
  • Verify the key is asymmetric (not symmetric)

Permission errors:

  • Check IAM permissions for kms:GetPublicKey, kms:DescribeKey, and kms:Sign
  • Verify the key policy allows your principal to use the key

Output file errors:

  • Ensure the output directory is writable
  • Check that the output file doesn't already exist (pgpkms won't overwrite)

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL