hvacΒΆ

Header image

HashiCorp Vault API client for Python 3.x

GitHub actions badge codecov Documentation Status PyPI version Twitter - @python_hvac Gitter chat

Tested against the latest release, HEAD ref, and 3 previous minor versions (counting back from the latest release) of Vault. Current official support covers Vault v1.3.10 or later.

InstallationΒΆ

pip install hvac

If you would like to be able to return parsed HCL data as a Python dict for methods that support it:

pip install "hvac[parser]"

Getting StartedΒΆ

Initialize the ClientΒΆ

Using TLS:

>>> client = hvac.Client(url='https://localhost:8200')
>>> client.is_authenticated()
True

Using TLS with client-side certificate authentication:

>>> client = hvac.Client(
...     url='https://localhost:8200',
...     token=os.environ['VAULT_TOKEN'],
...     cert=(client_cert_path, client_key_path),
...     verify=server_cert_path,
... )
>>> client.is_authenticated()
True

Using Vault Enterprise namespace:

>>> client = hvac.Client(
...     url='https://localhost:8200',
...     namespace=os.getenv('VAULT_NAMESPACE'),
... )

Using plaintext / HTTP (not recommended for anything other than development work):

>>> client = hvac.Client(url='http://localhost:8200')

Vault Cluster - Initialize and Seal/UnsealΒΆ

>>> client.sys.is_initialized()
False

>>> shares = 5
>>> threshold = 3
>>> result = client.sys.initialize(shares, threshold)
>>> root_token = result['root_token']
>>> keys = result['keys']
>>> client.sys.is_initialized()
True

>>> client.token = root_token

>>> client.sys.is_sealed()
True
>>> # Unseal a Vault cluster with individual keys
>>> unseal_response1 = client.sys.submit_unseal_key(keys[0])
>>> unseal_response2 = client.sys.submit_unseal_key(keys[1])
>>> unseal_response3 = client.sys.submit_unseal_key(keys[2])
>>> client.sys.is_sealed()
False
>>> # Seal a previously unsealed Vault cluster.
>>> client.sys.seal()
<Response [204]>
>>> client.sys.is_sealed()
True

>>> # Unseal with multiple keys until threshold met
>>> unseal_response = client.sys.submit_unseal_keys(keys)

>>> client.sys.is_sealed()
False

Read and write to secrets enginesΒΆ

Note

Vault currently defaults the secret/ path to the KV secrets engine version 2 automatically when the Vault server is started in β€œdev” mode.

Note

Starting with Vault v1.1.0, _no_ KV secrets engine is mounted by default. I.e., outside of dev mode, a KV engine mounted under path secret/ must be explicitly enabled before use.

KV Secrets Engine - Version 2ΒΆ

 >>> # Retrieve an authenticated hvac.Client() instance
 >>> client = test_utils.create_client()
 >>>
 >>> # Write a k/v pair under path: secret/foo
 >>> create_response = client.secrets.kv.v2.create_or_update_secret(
 ...     path='foo',
 ...     secret=dict(baz='bar'),
 ... )
 >>>
 >>> # Read the data written under path: secret/foo
 >>> read_response = client.secrets.kv.read_secret_version(path='foo')
 >>> print('Value under path "secret/foo" / key "baz": {val}'.format(
 ...     val=read_response['data']['data']['baz'],
 ... ))
 Value under path "secret/foo" / key "baz": bar
 >>>
 >>> # Delete all metadata/versions for path: secret/foo
 >>> client.secrets.kv.delete_metadata_and_all_versions('foo')
 <Response [204]>

KV Secrets Engine - Version 1ΒΆ

Preferred usage:

 >>> create_response = client.secrets.kv.v1.create_or_update_secret('foo', secret=dict(baz='bar'))
 >>> read_response = client.secrets.kv.v1.read_secret('foo')
 >>> print('Value under path "secret/foo" / key "baz": {val}'.format(
 ...     val=read_response['data']['baz'],
 ... ))
 Value under path "secret/foo" / key "baz": bar
 >>> delete_response = client.secrets.kv.v1.delete_secret('foo')

AuthenticationΒΆ

Basic Token AuthenticationΒΆ

# Token
>>> client.token = os.environ['VAULT_TOKEN']
>>> client.is_authenticated()
True

LDAP Authentication ExampleΒΆ

>>> client = hvac.Client(url='https://localhost:8200')
>>> # LDAP, getpass -> user/password, bring in LDAP3 here for teststup?
>>> login_response = client.auth.ldap.login(
...     username=os.environ['LDAP_USERNAME'],
...     password=os.environ['LDAP_PASSWORD'],
... )
>>> client.is_authenticated()
True
>>> print('The client token returned from the LDAP auth method is: {token}'.format(
...     token=login_response['auth']['client_token']
... ))
The client token returned from the LDAP auth method is: ...