progfiguration.sitehelpers.agesecrets

Age secret file store.

Store progfiguration secrets as files. Each secret is encrypted by an Age key.

Wrap the age binary to encrypt and decrypt secret values

Exceptions

AgeParseException

Common base class for all non-exit exceptions.

MissingAgeKeyException

Common base class for all non-exit exceptions.

Classes

AgeKey

An age keypair

AgeSecret

An age-encrypted secret value

AgeSecretReference

A reference to a secret by name

AgeSecretStore

Age secret file store for progfiguration inventories.

Functions

encrypt(value, pubkeys)

Encrypt a value to a list of public age keys

decrypt(→ str)

Decrypt an encrypted age value

Module Contents

exception progfiguration.sitehelpers.agesecrets.AgeParseException

Bases: Exception

Common base class for all non-exit exceptions.

exception progfiguration.sitehelpers.agesecrets.MissingAgeKeyException

Bases: Exception

Common base class for all non-exit exceptions.

class progfiguration.sitehelpers.agesecrets.AgeKey(secret: str, public: str, created: datetime.datetime)

An age keypair

Attributes:

secret: The secret key public: The public key created: The datetime the key was created

classmethod from_output(output: str) AgeKey

Parse the output of age-keygen into an AgeKey

Here’s example output from age-keygen -y:

# created: 2022-09-28T16:01:22-05:00 # public key: age14e42u048nehghjj3ch9mmnkdh4nsujn774klqxn02mznppx3gflsuj6y5m AGE-SECRET-KEY-1ASKGXED4DVGUH7SA50DHE2UHAYQ00PV87N2RQ5J5S6AUN9MLNSGQ3TKFGJ

This function parses that output and returns an AgeKey object.

classmethod generate(path: pathlib.Path | None = None) AgeKey

Generate a new age keypair using the age-keygen binary

classmethod from_file(path: str) AgeKey

Load an age keypair from a file

class progfiguration.sitehelpers.agesecrets.AgeSecret

Bases: progfiguration.inventory.invstores.Secret

An age-encrypted secret value

secret: str

The encrypted secret value

privkey_path: str | None

The path to the private key.

If this is None, then the secret cannot be decrypted.

decrypt() str

Decrypt the secret.

class progfiguration.sitehelpers.agesecrets.AgeSecretReference

Bases: progfiguration.inventory.invstores.SecretReference

A reference to a secret by name

This is a wrapper type that allows us to pass around a reference to a secret without having to know the secret’s value.

name: str

The name of the secret

dereference(nodename: str, hoststore: progfiguration.inventory.invstores.HostStore, secretstore: progfiguration.inventory.invstores.SecretStore) Any

Get the final value of a role argument for a node.

Arguments to this method:

  • nodename: The name of the node that the argument is being applied to

  • hoststore: The inventory object

This function must retrieve or calculate the final value from its internal data and these arguments.

progfiguration.sitehelpers.agesecrets.encrypt(value: str | bytes, pubkeys: List[str])

Encrypt a value to a list of public age keys

progfiguration.sitehelpers.agesecrets.decrypt(value: str, privkey_path: str | None) str

Decrypt an encrypted age value

class progfiguration.sitehelpers.agesecrets.AgeSecretStore(controller_age_pubkey: str, decryption_age_privkey_path_list: List[str] | None = None)

Bases: progfiguration.inventory.invstores.SecretStore

Age secret file store for progfiguration inventories.

Store progfiguration secrets as files in the site’s nodes/ and groups/ submodules. Each secret is encrypted by an Age key.

Look for a decryption key in the list passed to the initializer.

The CLI arguments it accepts:

age_key

The path to an age private key to decrypt secrets.

The InventoryNode sitedata it looks for:

age_key_path

The path on the node to an age private key to decrypt secrets. If this is not set, we try to use the decryption_age_privkey_path. If this is set, but the key does not exist, we raise FileNotFoundError.

age_pubkey

The string of an age public key to encrypt secrets. If this is not set, encrypting secrets for the node (or any of its groups) will fail.

controller_age_pubkey: str

The controller’s age public key

_cache: Dict[str, Dict[str, Dict[str, progfiguration.inventory.invstores.Secret]]]

An in-memory cache.

self._cache[collection][name] = {secretname: Secret}

decryption_age_privkey_path: str = ''

If this is not empty, use this path to an age private key to decrypt secrets.

During initialization, this is set to the first item in decryption_age_privkey_path_list that exists. Can be (re-)set after initialization.

TODO: how will the cli code in core allow setting this at runtime?

_get_secrets_file(collection: Literal['node', 'group', 'special'], name: str) pathlib.Path
_load_secrets(collection: Literal['node', 'group', 'special'], name: str) Dict[str, progfiguration.inventory.invstores.Secret]

Load a secrets from a secret store.

Cache them in memory for future use.

_append_secret(collection: Literal['node', 'group', 'special'], name: str, secret_name: str, encrypted_value: str)

Append a secret to the cache.

This is used when a secret is encrypted and stored

list_secrets(collection: Literal['node', 'group', 'special'], name: str) List[str]

List secrets.

get_secret(collection: Literal['node', 'group', 'special'], name: str, secret_name: str) progfiguration.inventory.invstores.Secret

Retrieve a secret from the secret store.

This operation returns an opaque Secret type. The secret does not have to be decrypted yet, but can be, depending on the Secret implementation.

encrypt_secret(hoststore: progfiguration.inventory.invstores.HostStore, name: str, value: str, nodes: List[str], groups: List[str], controller_key: bool, store: bool = False) str

Encrypt a secret for some list of nodes and groups.

Always encrypt for the controller so that it can decrypt too.

We assume this only ever happens on the controller.

apply_cli_arguments(args: Dict[str, str]) None

Apply arguments from the command line

Arguments are passed as comma-separated key/value pairs, like --secret-store-arguments key1=value1,key2=value2.

find_node_key(node: progfiguration.inventory.nodes.InventoryNode)

If called, this function should find the decryption key for a node.

It may be called by the progfigsite command-line program if the user specifies a node. The implementation may look up the key in the node’s sitedata.