Vault

  • Canonical Telco
Channel Revision Published Runs on
latest/edge 89 31 Jan 2024
Ubuntu 22.04 Ubuntu 20.04
latest/edge 9 27 Jan 2023
Ubuntu 22.04 Ubuntu 20.04
1.16/stable 280 04 Oct 2024
Ubuntu 22.04
1.16/candidate 280 04 Oct 2024
Ubuntu 22.04
1.16/beta 280 04 Oct 2024
Ubuntu 22.04
1.16/edge 291 19 Nov 2024
Ubuntu 22.04
1.15/stable 248 24 Jul 2024
Ubuntu 22.04
1.15/candidate 248 24 Jul 2024
Ubuntu 22.04
1.15/beta 248 24 Jul 2024
Ubuntu 22.04
1.15/edge 248 10 Jul 2024
Ubuntu 22.04
juju deploy vault-k8s --channel 1.16/stable
Show information

Platform:

charms.vault_k8s.v0.vault_kv

Library for the vault-kv relation.

This library contains the Requires and Provides classes for handling the vault-kv interface.

Getting Started

From a charm directory, fetch the library using charmcraft:

charmcraft fetch-lib charms.vault_k8s.v0.vault_kv
Requirer charm

The requirer charm is the charm requiring a secret value store. In this example, the requirer charm is requiring a secret value store.

import secrets

from charms.vault_k8s.v0 import vault_kv
from ops.charm import CharmBase, InstallEvent
from ops.main import main
from ops.model import ActiveStatus, BlockedStatus

NONCE_SECRET_LABEL = "nonce"


class ExampleRequirerCharm(CharmBase):
    def __init__(self, *args):
        super().__init__(*args)
        self.interface = vault_kv.VaultKvRequires(
            self,
            "vault-kv",
            "my-suffix",
        )

        self.framework.observe(self.on.install, self._on_install)
        self.framework.observe(self.interface.on.connected, self._on_connected)
        self.framework.observe(self.interface.on.ready, self._on_ready)
        self.framework.observe(self.interface.on.gone_away, self._on_gone_away)
        self.framework.observe(self.on.update_status, self._on_update_status)

    def _on_install(self, event: InstallEvent):
        self.unit.add_secret(
            {"nonce": secrets.token_hex(16)},
            label=NONCE_SECRET_LABEL,
            description="Nonce for vault-kv relation",
        )
        self.unit.status = BlockedStatus("Waiting for vault-kv relation")

    def _on_connected(self, event: vault_kv.VaultKvConnectedEvent):
        relation = self.model.get_relation(event.relation_name, event.relation_id)
        egress_subnets = [str(subnet) for subnet in self.model.get_binding(relation).network.egress_subnets][0].subnet]
        egress_subnets.append(str(self.model.get_binding(relation).network.interfaces[0].subnet))
        self.interface.request_credentials(relation, egress_subnets, self.get_nonce())

    def _on_ready(self, event: vault_kv.VaultKvReadyEvent):
        relation = self.model.get_relation(event.relation_name, event.relation_id)
        if relation is None:
            return
        vault_url = self.interface.get_vault_url(relation)
        ca_certificate = self.interface.get_ca_certificate(relation)
        mount = self.interface.get_mount(relation)

        unit_credentials = self.interface.get_unit_credentials(relation)
        # unit_credentials is a juju secret id
        secret = self.model.get_secret(id=unit_credentials)
        secret_content = secret.get_content(refresh=True)
        role_id = secret_content["role-id"]
        role_secret_id = secret_content["role-secret-id"]

        self._configure(vault_url, ca_certificate, mount, role_id, role_secret_id)

        self.unit.status = ActiveStatus()

    def _on_gone_away(self, event: vault_kv.VaultKvGoneAwayEvent):
        self.unit.status = BlockedStatus("Waiting for vault-kv relation")

    def _configure(
        self,
        vault_url: str,
        ca_certificate: str,
        mount: str,
        role_id: str,
        role_secret_id: str,
    ):
        pass

    def _on_update_status(self, event):
        # Check somewhere that egress subnet has not changed i.e. pod has not been rescheduled
        # Update status might not be the best place
        binding = self.model.get_binding("vault-kv")
        if binding is not None:
            egress_subnets = [str(subnet) for subnet in self.model.get_binding(relation).network.egress_subnets][0].subnet]
            egress_subnets.append(str(self.model.get_binding(relation).network.interfaces[0].subnet))
            relation = self.model.get_relation(relation_name="vault-kv")
            self.interface.request_credentials(relation, egress_subnets, self.get_nonce())

    def get_nonce(self):
        secret = self.model.get_secret(label=NONCE_SECRET_LABEL)
        nonce = secret.get_content(refresh=True)["nonce"]
        return nonce


if __name__ == "__main__":
    main(ExampleRequirerCharm)

You can integrate both charms by running:

juju integrate <vault provider charm> <vault requirer charm>

Index

class LogAdapter

Description

Adapter for the logger to prepend a prefix to all log lines. None

Methods

LogAdapter. process( self , msg , kwargs )

Description

Decides the format for the prepended text. None

class VaultKvProviderSchema

Description

Provider side of the vault-kv interface. None

class AppVaultKvRequirerSchema

Description

App schema of the requirer side of the vault-kv interface. None

class UnitVaultKvRequirerSchema

Description

Unit schema of the requirer side of the vault-kv interface. None

class ProviderSchema

Description

The schema for the provider side of this interface. None

class RequirerSchema

Description

The schema for the requirer side of this interface. None

class KVRequest

Description

This class represents a kv request from an interface Requirer. None

def get_egress_subnets_list_from_relation_data(relation_databag)

Return the egress_subnet as a list.

Arguments

relation_databag

the relation databag of the unit or the app.

Description

This function converts the string with values separated by commas to a list.

def is_requirer_data_valid(
    app_data,
    unit_data
)

Description

Return whether the requirer data is valid. None

def is_provider_data_valid(data)

Description

Return whether the provider data is valid. None

class VaultKvGoneAwayEvent

Description

VaultKvGoneAwayEvent Event. None

class VaultKvClientDetachedEvent

Description

VaultKvClientDetachedEvent Event. None

Methods

VaultKvClientDetachedEvent. __init__( self , handle , unit_name: str )

VaultKvClientDetachedEvent. snapshot( self )

Description

Return snapshot data that should be persisted. None

VaultKvClientDetachedEvent. restore( self , snapshot )

Description

Restore the event from a snapshot. None

class NewVaultKvClientAttachedEvent

Description

New vault kv client attached event. None

Methods

NewVaultKvClientAttachedEvent. __init__( self , handle , relation_id: int , app_name: str , unit_name: str , mount_suffix: str , egress_subnets , nonce: str )

NewVaultKvClientAttachedEvent. snapshot( self )

Description

Return snapshot data that should be persisted. None

NewVaultKvClientAttachedEvent. restore( self , snapshot )

Description

Restore the value state from a given snapshot. None

class VaultKvProviderEvents

Description

List of events that the Vault Kv provider charm can leverage. None

class VaultKvProvides

Description

Class to be instanciated by the providing side of the relation. None

Methods

VaultKvProvides. __init__( self , charm , relation_name: str )

VaultKvProvides. set_vault_url( self , relation , vault_url: str )

Description

Set the vault_url on the relation. None

VaultKvProvides. set_ca_certificate( self , relation , ca_certificate: str )

Description

Set the ca_certificate on the relation. None

VaultKvProvides. set_mount( self , relation , mount: str )

Description

Set the mount on the relation. None

VaultKvProvides. set_egress_subnets( self , relation , egress_subnets )

Description

Set the egress_subnets on the relation. None

VaultKvProvides. set_unit_credentials( self , relation , nonce: str , secret )

Description

Set the unit credentials on the relation. None

VaultKvProvides. remove_unit_credentials( self , relation , nonce )

Description

Remove nonce(s) from the relation. None

VaultKvProvides. get_credentials( self , relation )

Description

Get the unit credentials from the relation. None

VaultKvProvides. get_outstanding_kv_requests( self , relation_id )

Description

Get the outstanding requests for the relation. None

VaultKvProvides. get_kv_requests( self , relation_id )

Description

Get all KV requests for the relation. None

class VaultKvBaseEvent

Description

Base class for VaultKV requirer events. None

Methods

VaultKvBaseEvent. __init__( self , handle , relation_id: int , relation_name: str )

VaultKvBaseEvent. snapshot( self )

Description

Return snapshot data that should be persisted. None

VaultKvBaseEvent. restore( self , snapshot )

Description

Restore the value state from a given snapshot. None

class VaultKvConnectedEvent

Description

VaultKvConnectedEvent Event. None

class VaultKvReadyEvent

Description

VaultKvReadyEvent Event. None

class VaultKvRequireEvents

Description

List of events that the Vault Kv requirer charm can leverage. None

class VaultKvRequires

Description

Class to be instanciated by the requiring side of the relation. None

Methods

VaultKvRequires. __init__( self , charm , relation_name: str , mount_suffix: str )

VaultKvRequires. request_credentials( self , relation , egress_subnet , nonce: str )

Request credentials from the vault-kv relation.

Description

Generated secret ids are tied to the unit egress_subnet, so if the egress_subnet changes a new secret id must be generated.

A change in egress_subnets can happen when the pod is rescheduled to a different node by the underlying substrate without a change from Juju.

VaultKvRequires. get_vault_url( self , relation )

Description

Return the vault_url from the relation. None

VaultKvRequires. get_ca_certificate( self , relation )

Description

Return the ca_certificate from the relation. None

VaultKvRequires. get_mount( self , relation )

Description

Return the mount from the relation. None

VaultKvRequires. get_unit_credentials( self , relation )

Return the unit credentials from the relation.

Description

Unit credentials are stored in the relation data as a Juju secret id.