Skip to content

Commit

Permalink
Add basic VaultSigner (WIP)
Browse files Browse the repository at this point in the history
VaultSigner.import_ already works for ed25519 keys,
and can be tested via

  tox -e local-vault

TODO:
- sign
- from_priv_key_uri
- test on CI

Signed-off-by: Lukas Puehringer <[email protected]>
  • Loading branch information
lukpueh committed Apr 25, 2024
1 parent 005f153 commit 549bf77
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 6 deletions.
1 change: 1 addition & 0 deletions securesystemslib/signer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from securesystemslib.signer._gcp_signer import GCPSigner
from securesystemslib.signer._gpg_signer import GPGKey, GPGSigner
from securesystemslib.signer._hsm_signer import HSMSigner
from securesystemslib.signer._vault_signer import VaultSigner
from securesystemslib.signer._key import KEY_FOR_TYPE_AND_SCHEME, Key, SSlibKey
from securesystemslib.signer._signature import Signature
from securesystemslib.signer._signer import (
Expand Down
51 changes: 51 additions & 0 deletions securesystemslib/signer/_vault_signer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""Signer implementation for HashiCorp Vault (Transit secrets engine)"""

from typing import Tuple
from base64 import b64decode

from securesystemslib.exceptions import UnsupportedLibraryError
from securesystemslib.signer._key import Key, SSlibKey
from securesystemslib.signer._signer import SecretsHandler, Signature, Signer
from securesystemslib.signer._utils import compute_default_keyid


VAULT_IMPORT_ERROR = None
try:
import hvac
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Ed25519PublicKey,
)

except ImportError:
VAULT_IMPORT_ERROR = "Signing with HashiCorp Vault requires hvac and cryptography."


class VaultSigner(Signer):
"""HashiCorp Vault Signer (Transit secrets engine) """
SCHEME = "hv"

@classmethod
def import_(cls, hv_key_name: str) -> Tuple[str, Key]:
"""Load key and signer details from vault.
Supported keytypes:
* ed25519
"""
if VAULT_IMPORT_ERROR:
raise UnsupportedLibraryError(VAULT_IMPORT_ERROR)

client = hvac.Client()

resp = client.secrets.transit.read_key(hv_key_name)

# Extract "newest" key from response
pub_b64 = sorted(resp["data"]["keys"].items())[-1][1]["public_key"]
pub_raw = b64decode(pub_b64)
pub_crypto = Ed25519PublicKey.from_public_bytes(pub_raw)

pub = SSlibKey.from_crypto(pub_crypto)
uri = f"{VaultSigner.SCHEME}:{hv_key_name}"

return uri, pub

40 changes: 40 additions & 0 deletions tests/check_vault_signer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Test AWSSigner
"""

import unittest

from securesystemslib.signer import VaultSigner


class TestVaultSigner(unittest.TestCase):
"""Test VaultSigner"""

def test_vault_import_sign_verify(self):
# Test full signer flow with vault
# - see tests/scripts/init-vault.sh for how keys are created
# - see tox.ini for how credentials etc. are passed via env vars
keys_and_schemes = [
("test-key-ed25519", "ed25519")
]
for hv_key_name, scheme in keys_and_schemes:
# Test import
uri, public_key = VaultSigner.import_(hv_key_name)
self.assertEqual(uri, f"{VaultSigner.SCHEME}:{hv_key_name}")
self.assertEqual(scheme, public_key.scheme)

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

# # 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__":
unittest.main(verbosity=1)
12 changes: 6 additions & 6 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,12 @@ commands_post =
localstack stop


# Requires docker running
# Requires `vault`
# https://developer.hashicorp.com/vault/tutorials/getting-started/getting-started-install
[testenv:local-vault]
; deps =
; hvac
deps =
-r{toxinidir}/requirements-pinned.txt
hvac

allowlist_externals =
bash
Expand All @@ -123,9 +125,7 @@ commands_pre =
bash {toxinidir}/tests/scripts/init-vault.sh

commands =
; TODO: Test AWSSigner.import_, from_priv_key_uri and sign here
; curl --header "X-Vault-Token: test-root-token" \
; http://127.0.0.1:8200/v1/transit/export/public-key/test-key-ed25519
python -m tests.check_vault_signer

commands_post =
bash {toxinidir}/tests/scripts/stop-vault.sh

0 comments on commit 549bf77

Please sign in to comment.