Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hashi-vault-engine-name parameter #399

Merged
merged 6 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/commands/validators_exit.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
from src.common.validators import validate_eth_address
from src.common.vault_config import VaultConfig
from src.config.networks import AVAILABLE_NETWORKS
from src.config.settings import DEFAULT_HASHI_VAULT_PARALLELISM, settings
from src.config.settings import (
DEFAULT_HASHI_VAULT_ENGINE_NAME,
DEFAULT_HASHI_VAULT_PARALLELISM,
settings,
)
from src.validators.keystores.base import BaseKeystore
from src.validators.keystores.load import load_keystore

Expand Down Expand Up @@ -77,6 +81,12 @@ class ValidatorExit:
envvar='HASHI_VAULT_URL',
help='The base URL of the vault service, e.g. http://vault:8200.',
)
@click.option(
'--hashi-vault-engine-name',
envvar='HASHI_VAULT_ENGINE_NAME',
help='The name of the secret engine, e.g. keystores',
default=DEFAULT_HASHI_VAULT_ENGINE_NAME,
)
@click.option(
'--hashi-vault-token',
envvar='HASHI_VAULT_TOKEN',
Expand Down Expand Up @@ -128,6 +138,7 @@ def validators_exit(
hashi_vault_key_path: list[str] | None,
hashi_vault_token: str | None,
hashi_vault_url: str | None,
hashi_vault_engine_name: str,
hashi_vault_parallelism: int,
data_dir: str,
verbose: bool,
Expand All @@ -149,6 +160,7 @@ def validators_exit(
hashi_vault_token=hashi_vault_token,
hashi_vault_key_paths=hashi_vault_key_path,
hashi_vault_url=hashi_vault_url,
hashi_vault_engine_name=hashi_vault_engine_name,
hashi_vault_parallelism=hashi_vault_parallelism,
verbose=verbose,
log_level=log_level,
Expand Down
4 changes: 4 additions & 0 deletions src/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
DEFAULT_MIN_VALIDATORS_REGISTRATION = 1

DEFAULT_HASHI_VAULT_PARALLELISM = 8
DEFAULT_HASHI_VAULT_ENGINE_NAME = 'secret'


# pylint: disable-next=too-many-public-methods,too-many-instance-attributes
Expand Down Expand Up @@ -50,6 +51,7 @@ class Settings(metaclass=Singleton):
dappnode: bool = False
hashi_vault_key_paths: list[str] | None
hashi_vault_url: str | None
hashi_vault_engine_name: str
hashi_vault_token: str | None
hashi_vault_parallelism: int
hot_wallet_file: Path
Expand Down Expand Up @@ -111,6 +113,7 @@ def set(
dappnode: bool = False,
hashi_vault_key_paths: list[str] | None = None,
hashi_vault_url: str | None = None,
hashi_vault_engine_name: str = DEFAULT_HASHI_VAULT_ENGINE_NAME,
hashi_vault_token: str | None = None,
hashi_vault_parallelism: int = DEFAULT_HASHI_VAULT_PARALLELISM,
hot_wallet_file: str | None = None,
Expand Down Expand Up @@ -167,6 +170,7 @@ def set(
raise RuntimeError('Found duplicate addresses in hashi vault key paths')

self.hashi_vault_url = hashi_vault_url
self.hashi_vault_engine_name = hashi_vault_engine_name
self.hashi_vault_key_paths = hashi_vault_key_paths
self.hashi_vault_token = hashi_vault_token
self.hashi_vault_parallelism = hashi_vault_parallelism
Expand Down
6 changes: 6 additions & 0 deletions src/test_fixtures/hashi_vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ def _mocked_error_path(url, **kwargs) -> CallbackResult:
callback=partial(_mocked_secret_path, _hashi_vault_pk_sk_mapping_2),
repeat=True,
)
# Mocked signing keys endpoints with custom engine name
m.get(
f'{hashi_vault_url}/v1/custom/data/ethereum/signing/keystores',
callback=partial(_mocked_secret_path, _hashi_vault_pk_sk_mapping_1),
repeat=True,
)
# Mocked inacessible signing keys endpoint
m.get(
f'{hashi_vault_url}/v1/secret/data/ethereum/inaccessible/keystores',
Expand Down
7 changes: 5 additions & 2 deletions src/validators/keystores/hashi_vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
class HashiVaultConfiguration:
token: str
url: str
engine_name: str
key_paths: list[str]
parallelism: int

Expand All @@ -36,14 +37,15 @@ def from_settings(cls) -> 'HashiVaultConfiguration':
return cls(
token=settings.hashi_vault_token,
url=settings.hashi_vault_url,
engine_name=settings.hashi_vault_engine_name,
key_paths=settings.hashi_vault_key_paths,
parallelism=settings.hashi_vault_parallelism,
)

def secret_url(self, key_path: str) -> str:
return urllib.parse.urljoin(
self.url,
f'/v1/secret/data/{key_path}',
f'/v1/{self.engine_name}/data/{key_path}',
)


Expand All @@ -66,7 +68,8 @@ async def load() -> 'HashiVaultKeystore':
keys_responses = await asyncio.gather(
*[
HashiVaultKeystore._load_hashi_vault_keys(
session=session, secret_url=hashi_vault_config.secret_url(key_path)
session=session,
secret_url=hashi_vault_config.secret_url(key_path),
)
for key_path in key_chunk
]
Expand Down
33 changes: 31 additions & 2 deletions src/validators/keystores/tests/test_hashi_vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ async def test_hashi_vault_keystores_loading(
hashi_vault_url: str,
):
settings.hashi_vault_url = hashi_vault_url
settings.hashi_vault_engine_name = 'secret'
settings.hashi_vault_token = 'Secret'
settings.hashi_vault_key_paths = []
settings.hashi_vault_parallelism = 1
Expand All @@ -23,7 +24,8 @@ async def test_hashi_vault_keystores_loading(

async with ClientSession() as session:
keystore = await HashiVaultKeystore._load_hashi_vault_keys(
session=session, secret_url=config.secret_url('ethereum/signing/keystores')
session=session,
secret_url=config.secret_url('ethereum/signing/keystores'),
)

assert len(keystore) == 2
Expand All @@ -34,6 +36,7 @@ async def test_hashi_vault_keystores_not_configured(
hashi_vault_url: str,
):
settings.hashi_vault_url = hashi_vault_url
settings.hashi_vault_engine_name = 'secret'
settings.hashi_vault_token = None
settings.hashi_vault_key_path = None
settings.hashi_vault_parallelism = 1
Expand All @@ -47,6 +50,7 @@ async def test_hashi_vault_keystores_inaccessible(
hashi_vault_url: str,
):
settings.hashi_vault_url = hashi_vault_url
settings.hashi_vault_engine_name = 'secret'
settings.hashi_vault_token = 'Secret'
settings.hashi_vault_key_path = []
settings.hashi_vault_parallelism = 1
Expand All @@ -57,7 +61,8 @@ async def test_hashi_vault_keystores_inaccessible(
config = HashiVaultConfiguration.from_settings()
async with ClientSession() as session:
await HashiVaultKeystore._load_hashi_vault_keys(
session=session, secret_url=config.secret_url('ethereum/inaccessible/keystores')
session=session,
secret_url=config.secret_url('ethereum/inaccessible/keystores'),
)

@pytest.mark.usefixtures('mocked_hashi_vault')
Expand All @@ -66,6 +71,7 @@ async def test_hashi_vault_keystores_parallel(
hashi_vault_url: str,
):
settings.hashi_vault_url = hashi_vault_url
settings.hashi_vault_engine_name = 'secret'
settings.hashi_vault_token = 'Secret'
settings.hashi_vault_key_paths = [
'ethereum/signing/keystores',
Expand All @@ -84,6 +90,7 @@ async def test_hashi_vault_keystores_sequential(
hashi_vault_url: str,
):
settings.hashi_vault_url = hashi_vault_url
settings.hashi_vault_engine_name = 'secret'
settings.hashi_vault_token = 'Secret'
settings.hashi_vault_key_paths = [
'ethereum/signing/keystores',
Expand All @@ -102,6 +109,7 @@ async def test_hashi_vault_duplicates_parallel(
hashi_vault_url: str,
):
settings.hashi_vault_url = hashi_vault_url
settings.hashi_vault_engine_name = 'secret'
settings.hashi_vault_token = 'Secret'
settings.hashi_vault_key_paths = [
'ethereum/signing/keystores',
Expand All @@ -112,3 +120,24 @@ async def test_hashi_vault_duplicates_parallel(
keystore = HashiVaultKeystore({})
with pytest.raises(RuntimeError, match='Found duplicate key in path'):
await keystore.load()

@pytest.mark.usefixtures('mocked_hashi_vault')
async def test_hashi_vault_keystores_loading_custom_engine_name(
self,
hashi_vault_url: str,
):
settings.hashi_vault_url = hashi_vault_url
settings.hashi_vault_engine_name = 'custom'
settings.hashi_vault_token = 'Secret'
settings.hashi_vault_key_paths = []
settings.hashi_vault_parallelism = 1

config = HashiVaultConfiguration.from_settings()

async with ClientSession() as session:
keystore = await HashiVaultKeystore._load_hashi_vault_keys(
session=session,
secret_url=config.secret_url('ethereum/signing/keystores'),
)

assert len(keystore) == 2