Skip to content

Commit

Permalink
Merge pull request #777 from lukpueh/test-aws
Browse files Browse the repository at this point in the history
Test AWSSigner with localstack
  • Loading branch information
lukpueh authored Apr 12, 2024
2 parents 2cab5a9 + 94d58a6 commit 91862b0
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 57 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/test-kms-aws.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Run AWS KMS tests

on:
push:
pull_request:

jobs:
local-aws-kms:
runs-on: ubuntu-latest
steps:
- name: Checkout securesystemslib
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633

- name: Set up Python
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d
with:
python-version: '3.x'
cache: 'pip'
cache-dependency-path: 'requirements*.txt'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install --upgrade tox
- name: Run tests
run: tox -e local-aws-kms
2 changes: 2 additions & 0 deletions requirements-aws.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
boto3==1.34.82
botocore==1.34.82
116 changes: 59 additions & 57 deletions tests/check_aws_signer.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,68 @@
"""This module confirms that signing using AWS KMS keys works.
"""Test AWSSigner
The purpose is to do a smoke test, not to exhaustively test every possible key
and environment combination.
For AWS, the requirements to successfully test are:
* AWS authentication details
have to be available in the environment
* The key defined in the test has to be
available to the authenticated user
Remember to replace the REDACTED fields to include the necessary values:
* keyid: Hash of the public key
* public: The public key, refer to other KMS tests to see the format
* aws_id: AWS KMS ID or alias
"""

import unittest

from securesystemslib.exceptions import UnverifiedSignatureError
from securesystemslib.signer import AWSSigner, Key, Signer


class TestAWSKMSKeys(unittest.TestCase):
"""Test that AWS KMS keys can be used to sign."""

pubkey = Key.from_dict(
"REDACTED",
{
"keytype": "rsa",
"scheme": "rsassa-pss-sha256",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nREDACTED\n-----END PUBLIC KEY-----\n"
},
},
)
aws_key_id = "REDACTED"

def test_aws_sign(self):
"""Test that AWS KMS key works for signing"""

data = "data".encode("utf-8")

signer = Signer.from_priv_key_uri(
f"awskms:{self.aws_key_id}", self.pubkey
)
sig = signer.sign(data)

self.pubkey.verify_signature(sig, data)
with self.assertRaises(UnverifiedSignatureError):
self.pubkey.verify_signature(sig, b"NOT DATA")

def test_aws_import_with_scheme(self):
"""Test that AWS KMS key can be imported with a specified scheme."""
uri, key = AWSSigner.import_(self.aws_key_id, self.pubkey.scheme)
self.assertEqual(key.keytype, self.pubkey.keytype)
self.assertEqual(uri, f"awskms:{self.aws_key_id}")

def test_aws_import_without_scheme(self):
"""Test that AWS KMS key can be imported without specifying a scheme."""
uri, key = AWSSigner.import_(self.aws_key_id)
self.assertEqual(key.keytype, self.pubkey.keytype)
self.assertEqual(uri, f"awskms:{self.aws_key_id}")
from securesystemslib.signer import AWSSigner, Signer


class TestAWSSigner(unittest.TestCase):
"""Test AWSSigner"""

def test_aws_import_sign_verify(self):
# Test full signer flow with localstack
# - see tests/scripts/init-aws-kms.sh for how keys are created
# - see tox.ini for how credentials etc. are passed via env vars
keys_and_schemes = [
(
"alias/rsa",
"rsassa-pss-sha256",
[
"rsassa-pss-sha256",
"rsassa-pss-sha384",
"rsassa-pss-sha512",
"rsa-pkcs1v15-sha256",
"rsa-pkcs1v15-sha384",
"rsa-pkcs1v15-sha512",
],
),
(
"alias/ecdsa_nistp256",
"ecdsa-sha2-nistp256",
["ecdsa-sha2-nistp256"],
),
(
"alias/ecdsa_nistp384",
"ecdsa-sha2-nistp384",
["ecdsa-sha2-nistp384"],
),
]
for aws_keyid, default_scheme, schemes in keys_and_schemes:
for scheme in schemes:
# Test import
uri, public_key = AWSSigner.import_(aws_keyid, scheme)
self.assertEqual(uri, f"{AWSSigner.SCHEME}:{aws_keyid}")
self.assertEqual(scheme, public_key.scheme)

# Test import with default_scheme
if scheme == default_scheme:
uri2, public_key2 = AWSSigner.import_(aws_keyid)
self.assertEqual(uri, uri2)
self.assertEqual(public_key, public_key2)

# Test load
signer = Signer.from_priv_key_uri(uri, public_key)
self.assertIsInstance(signer, AWSSigner)

# Test sign and verify
signature = signer.sign(b"DATA")
self.assertIsNone(
public_key.verify_signature(signature, b"DATA")
)
with self.assertRaises(UnverifiedSignatureError):
public_key.verify_signature(signature, b"NOT DATA")


if __name__ == "__main__":
Expand Down
27 changes: 27 additions & 0 deletions tests/scripts/init-aws-kms.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash

# Create test keys
awslocal kms create-key \
--key-spec RSA_4096 \
--key-usage SIGN_VERIFY

awslocal kms create-key \
--key-spec ECC_NIST_P256 \
--key-usage SIGN_VERIFY

awslocal kms create-key \
--key-spec ECC_NIST_P384 \
--key-usage SIGN_VERIFY

# Create test keyid aliases ("alias/" prefix is mandatory)
awslocal kms create-alias \
--alias-name alias/rsa \
--target-key-id $(awslocal kms list-keys --query "Keys[0].KeyId" --output text)

awslocal kms create-alias \
--alias-name alias/ecdsa_nistp256 \
--target-key-id $(awslocal kms list-keys --query "Keys[1].KeyId" --output text)

awslocal kms create-alias \
--alias-name alias/ecdsa_nistp384 \
--target-key-id $(awslocal kms list-keys --query "Keys[2].KeyId" --output text)
35 changes: 35 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,38 @@ commands =
pylint -j 0 --rcfile=pylintrc securesystemslib tests
bandit --recursive securesystemslib --exclude _vendor
mypy

# Requires docker running
[testenv:local-aws-kms]
deps =
-r{toxinidir}/requirements-pinned.txt
-r{toxinidir}/requirements-aws.txt
localstack
awscli
awscli-local

allowlist_externals =
localstack
bash

setenv =
AWS_ACCESS_KEY_ID = test
AWS_SECRET_ACCESS_KEY = test
AWS_ENDPOINT_URL = http://localhost:4566/
AWS_DEFAULT_REGION = us-east-1

commands_pre =
# Start virtual AWS KMS
localstack start --detached
localstack wait

# Create test keys
bash {toxinidir}/tests/scripts/init-aws-kms.sh

commands =
# Run tests
python -m tests.check_aws_signer

commands_post =
# Stop virtual AWS KMS
localstack stop

0 comments on commit 91862b0

Please sign in to comment.