hvac

Header image

HashiCorp Vault API client for Python 2.7/3.x

Travis CI codecov Documentation Status PyPI version Twitter - @python_hvac Gitter chat

Tested against the latest release, HEAD ref, and 3 previous major versions (counting back from the latest release) of Vault. Currently supports Vault v0.10.4 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/ much 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:

 >>> client.secrets.kv.default_kv_version = '1'
 >>> create_response = client.secrets.kv.create_or_update_secret('foo', secret=dict(baz='bar'))
 >>> read_response = client.secrets.kv.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.delete_secret('foo')

Generic usage:

Note

The following read() and write() methods are roughly equivalent to the equivalent Vault CLI commands. These methods do not offer the same level of validation that hvac methods specific to individual auth methods and secrets engines provide.

 >>> client.write('secret/foo', baz='bar', lease='1h')
 >>> read_response = client.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
 >>> client.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: ...