API usage

s1crets tries to provide the same(-ish) interface for all secret providers. Some implementation details and the feature sets are of course different though.

Caching

By default all accesses are cached into memory with a cache of 1000 entries and TTL of 15 minutes. If you want to customize that, you have two options:

Caching into the memory

You can set the cache parameters by submitting the cache_args:

import s1crets.providers.aws
ps = s1crets.providers.aws.ParameterStore(cache_args={'cache_size': 10, 'cache_ttl': 60})

Caching onto disk

Instead of keeping the cache in memory, you can persists that to disk with the diskcache module:

ps = s1crets.providers.aws.ParameterStore(cache_args={'cache_on_disk':True, 'key_cache_dir': '/data/key_cache', 'path_cache_dir': '/data/path_cache'})

BEWARE that this stores sensitive information unencrypted, you have to take care against malicious access to those files! Using diskcache can solve cache persistency (for eg. between script executions) or sharing the cache between multiple instances.

Simple API

If you are fine without submitting custom parameters like for caching and assuming a role etc, you can just use the simple API:

import s1crets
s1crets.get('aws.sm', 'prod/databases/mysql/bigdb/root')
s1crets.path_exists('aws.sm', 'prod/databases/mysql/bigdb/root')
etc.

Because the provider class itself is cached, you will get default caching with this:

>>> s1crets.get
<function get at 0x7f3f1a0dd2f0>
>>> s1crets.get
<function get at 0x7f3f1a0dd2f0>

AWS

Assuming a role

Doing operations in either store, you have to have the relevant permissions, both for the service and corresponding encryption (KMS) keys. If your current role doesn’t have those, you can switch temporarily to another role by assuming it.

An example for doing that:

import s1crets.providers.aws
ROLEARN = f'arn:aws:iam::{TARGET_ACCOUNT}:role/my-assume-role'
ps = s1crets.providers.aws.ParameterStore(sts_args={'RoleArn': ROLEARN, 'RoleSessionName': 'myscript'})

Setting a region

You can set the region manually:

import s1crets.providers.aws
ps = s1crets.providers.aws.ParameterStore(sts_args={'aws_region':'us-east-1'})
sm = s1crets.providers.aws.SecretsManager(sts_args={'aws_region':'us-east-1'})

Systems Manager Parameter Store

AWS Systems Manager Parameter Store (PS from now on) provides access to a path-like structured, / separated key-value store. You can access your parameters on the AWS SSM PS console.

Initializing the module

You can create a Parameter Store object this way:

import s1crets.providers.aws
ps = s1crets.providers.aws.ParameterStore()

Getting a secret

To get a secret:

ps.get('/prod/databases/mysql/bigdb/root')

This will return a KeyError Exception if the key doesn’t exist. If the value is JSON-decodeable, you’ll receive a dictionary.

Listing all secrets below a path

PS supports the notion of paths, so you can get all secrets below one:

ps.get_by_path('/prod/databases/mysql')

This will return a dictionary with the PS keys and their values.

Checking whether a path exists or not

You can check whether a path (and in PS case it means the path or a key) exists:

ps.path_exists('/prod/databases/mysql')

Returns a boolean.

Updating secrets

It’s possible to update values as well. This will use the same KeyId as the original value:

ps.update('/prod/databases/mysql/bigdb/root', 'S3cr3Tp4Ssw0Rd!^')

Secrets Manager

AWS Secrets Manager (SM from now on) provides access to a key-value encrypted store. You can access your secrets on the AWS SM console.

SM can store arbitrary values (even binary), but if you use the console, they will mostly be JSONs. s1crets automatically tries to parse JSON, so you’ll get a parsed result.

Initializing the module

You can create a Secrets Manager object this way:

import s1crets.providers.aws
sm = s1crets.providers.aws.SecretsManager()

Getting a secret

To get a secret:

sm.get('prod/databases/mysql/bigdb/root')

This will return a KeyError Exception if the key doesn’t exist. If the value is JSON-decodeable, you’ll receive a dictionary.

Checking whether a key exists or not

You can check whether a key exists:

sm.path_exists('prod/databases/mysql')

Returns a boolean.

Note that SM doesn’t support the notion of path, so you can only check for exact key names.

Updating secrets

It’s possible to update values as well. This will use the same encryption key as the original value:

sm.update('prod/databases/mysql/bigdb/root', 'S3cr3Tp4Ssw0Rd!^')

s1crets module

s1crets.get(provider='aws.sm', path=None, keypath=None, retry=3, timeout=5)[source]

Get a secret from the given provider

Parameters:
  • provider (str) – Secret provider (aws.sm|aws.ps)
  • path (str) – path for the given secret
  • keypath (list) – the key path for looking into a JSON secret
Returns:

The returned secret, can be string, bytes or in case of JSON, a dictionary

Return type:

secret

s1crets.get_by_path(provider='aws.sm', path=None, retry=3, timeout=5)[source]

Returns all secrets beneath a path (if the provider supports it)

Parameters:
  • provider (str) – Secret provider (aws.sm|aws.ps)
  • path (str) – path for the given secret
Returns:

List of returned secrets

Return type:

secrets (list)

s1crets.update(provider='aws.sm', path=None, value=None, retry=3, timeout=5)[source]

Updates secret with given value

Parameters:
  • provider (str) – Secret provider (aws.sm|aws.ps)
  • path (str) – path for the given secret
  • value (string, bytes) – the value to be stored
Returns:

None

s1crets.path_exists(provider='aws.sm', path=None, keypath=None, retry=3, timeout=5)[source]

Check whether the path exists in the secrets provider

Parameters:
  • provider (str) – Secret provider (aws.sm|aws.ps)
  • path (str) – path for the given secret
  • keypath (list) – the key path for looking into a JSON secret
Returns:

The returned secret, can be string, bytes or in case of JSON, a dictionary

Return type:

secret