ssm-parameter-store 26.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ssm_parameter_store/__init__.py +4 -0
- ssm_parameter_store/stores.py +89 -0
- ssm_parameter_store/version.py +6 -0
- ssm_parameter_store-26.8.0.dist-info/METADATA +234 -0
- ssm_parameter_store-26.8.0.dist-info/RECORD +7 -0
- ssm_parameter_store-26.8.0.dist-info/WHEEL +4 -0
- ssm_parameter_store-26.8.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
import boto3
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EC2ParameterStore:
|
|
10
|
+
def __init__(self, **client_kwargs):
|
|
11
|
+
self.client = boto3.client('ssm', **client_kwargs)
|
|
12
|
+
self.path_delimiter = '/'
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def set_env(parameter_dict):
|
|
16
|
+
for k, v in parameter_dict.items():
|
|
17
|
+
os.environ.setdefault(k, v)
|
|
18
|
+
|
|
19
|
+
def _get_paginated_parameters(self, client_method, strip_path=True, **get_kwargs):
|
|
20
|
+
next_token = None
|
|
21
|
+
parameters = []
|
|
22
|
+
while True:
|
|
23
|
+
result = client_method(**get_kwargs)
|
|
24
|
+
parameters += result.get('Parameters')
|
|
25
|
+
next_token = result.get('NextToken')
|
|
26
|
+
if next_token is None:
|
|
27
|
+
break
|
|
28
|
+
get_kwargs.update({'NextToken': next_token})
|
|
29
|
+
return dict(self.extract_parameter(p, strip_path=strip_path) for p in parameters)
|
|
30
|
+
|
|
31
|
+
def extract_parameter(self, parameter, strip_path=True):
|
|
32
|
+
key = parameter['Name']
|
|
33
|
+
if strip_path:
|
|
34
|
+
key_parts = key.split(self.path_delimiter)
|
|
35
|
+
key = key_parts[-1]
|
|
36
|
+
value = parameter['Value']
|
|
37
|
+
if parameter['Type'] == 'StringList':
|
|
38
|
+
value = value.split(',')
|
|
39
|
+
return (key, value)
|
|
40
|
+
|
|
41
|
+
def get_parameter(self, name, decrypt=True, strip_path=True):
|
|
42
|
+
result = self.client.get_parameter(Name=name, WithDecryption=decrypt)
|
|
43
|
+
p = result['Parameter']
|
|
44
|
+
return dict([self.extract_parameter(p, strip_path=strip_path)])
|
|
45
|
+
|
|
46
|
+
def get_parameters(self, names, decrypt=True, strip_path=True):
|
|
47
|
+
get_kwargs = {'Names': names, 'WithDecryption': decrypt}
|
|
48
|
+
return self._get_paginated_parameters(
|
|
49
|
+
client_method=self.client.get_parameters,
|
|
50
|
+
strip_path=strip_path,
|
|
51
|
+
**get_kwargs
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def get_parameters_by_path(self, path, decrypt=True, recursive=True, strip_path=True):
|
|
55
|
+
get_kwargs = {'Path': path, 'WithDecryption': decrypt, 'Recursive': recursive}
|
|
56
|
+
return self._get_paginated_parameters(
|
|
57
|
+
client_method=self.client.get_parameters_by_path,
|
|
58
|
+
strip_path=strip_path,
|
|
59
|
+
**get_kwargs
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def get_parameters_with_hierarchy(self, path, decrypt=True, strip_path=True):
|
|
63
|
+
"""Recursively get all parameters under path, keeping the hierarchy
|
|
64
|
+
as a structure of nested dictionaries.
|
|
65
|
+
"""
|
|
66
|
+
# Get a flat dictionary
|
|
67
|
+
get_kwargs = {'Path': path, 'WithDecryption': decrypt, 'Recursive': True}
|
|
68
|
+
flat = self._get_paginated_parameters(
|
|
69
|
+
client_method=self.client.get_parameters_by_path,
|
|
70
|
+
strip_path=False,
|
|
71
|
+
**get_kwargs
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Convert to a nested dictionary and strip leading path component
|
|
75
|
+
result = {}
|
|
76
|
+
|
|
77
|
+
for key, value in flat.items():
|
|
78
|
+
if strip_path:
|
|
79
|
+
key = key[len(path):]
|
|
80
|
+
if key and key[0] == "/":
|
|
81
|
+
key = key[1:]
|
|
82
|
+
|
|
83
|
+
leafdict = result
|
|
84
|
+
key_segments = key.split("/")
|
|
85
|
+
for key_segment in key_segments[:-1]:
|
|
86
|
+
leafdict = leafdict.setdefault(key_segment, {})
|
|
87
|
+
leafdict[key_segments[-1]] = value
|
|
88
|
+
|
|
89
|
+
return result
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: ssm-parameter-store
|
|
3
|
+
Version: 26.8.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Author: Chris Tippett
|
|
6
|
+
Author-email: Chris Tippett <git@christippett.dev>
|
|
7
|
+
Requires-Dist: boto3>=1.43.81
|
|
8
|
+
Requires-Dist: setuptools>=84.0.0
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
SSM Parameter Store
|
|
13
|
+
=============================================================
|
|
14
|
+
|
|
15
|
+
[](https://pypi.python.org/pypi/ssm-parameter-store)
|
|
16
|
+
[](https://travis-ci.org/christippett/ssm-parameter-store)
|
|
17
|
+
[](https://coveralls.io/github/christippett/ssm-parameter-store?branch=master)
|
|
18
|
+
[](https://pypi.python.org/pypi/ssm-parameter-store)
|
|
19
|
+
[](https://github.com/christippett/ssm-parameter-store)
|
|
20
|
+
|
|
21
|
+
Description
|
|
22
|
+
===========
|
|
23
|
+
|
|
24
|
+
This is a simple Python wrapper for getting values from AWS Systems Manager
|
|
25
|
+
Parameter Store.
|
|
26
|
+
|
|
27
|
+
The module supports getting a single parameter, multiple parameters or all parameters matching a particular path.
|
|
28
|
+
|
|
29
|
+
All parameters are returned as a Python `dict`.
|
|
30
|
+
|
|
31
|
+
Installation
|
|
32
|
+
============
|
|
33
|
+
|
|
34
|
+
Install with `pip`:
|
|
35
|
+
|
|
36
|
+
``` bash
|
|
37
|
+
pip install ssm-parameter-store
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Usage
|
|
41
|
+
=====
|
|
42
|
+
|
|
43
|
+
Import the module and create a new instance of `EC2ParameterStore`.
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from ssm_parameter_store import EC2ParameterStore
|
|
47
|
+
|
|
48
|
+
store = EC2ParameterStore()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
AWS Credentials
|
|
52
|
+
---------------
|
|
53
|
+
|
|
54
|
+
`ssm-parameter-store` uses `boto3` under the hood and therefore inherits
|
|
55
|
+
the same mechanism for looking up AWS credentials. See [configuring
|
|
56
|
+
credentials](https://boto3.readthedocs.io/en/latest/guide/configuration.html#configuring-credentials)
|
|
57
|
+
in the Boto 3 documentation for more information.
|
|
58
|
+
|
|
59
|
+
`EC2ParameterStore` accepts all `boto3` client parameters as keyword arguments.
|
|
60
|
+
|
|
61
|
+
For example:
|
|
62
|
+
|
|
63
|
+
``` python
|
|
64
|
+
from ssm_parameter_store import EC2ParameterStore
|
|
65
|
+
|
|
66
|
+
store = EC2ParameterStore(
|
|
67
|
+
aws_access_key_id=ACCESS_KEY,
|
|
68
|
+
aws_secret_access_key=SECRET_KEY,
|
|
69
|
+
aws_session_token=SESSION_TOKEN, # optional
|
|
70
|
+
region_name='us-west-2'
|
|
71
|
+
)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Examples
|
|
75
|
+
========
|
|
76
|
+
|
|
77
|
+
Given the following parameters:
|
|
78
|
+
|
|
79
|
+
``` bash
|
|
80
|
+
# set default AWS region
|
|
81
|
+
AWS_DEFAULT_REGION=us-west-2
|
|
82
|
+
|
|
83
|
+
# add parameters
|
|
84
|
+
aws ssm put-parameter --name "param1" --value "value1" --type SecureString
|
|
85
|
+
aws ssm put-parameter --name "param2" --value "value2" --type SecureString
|
|
86
|
+
|
|
87
|
+
# add parameters organised by hierarchy
|
|
88
|
+
aws ssm put-parameter --name "/dev/app/secret" --value "dev_secret" --type SecureString
|
|
89
|
+
aws ssm put-parameter --name "/dev/db/postgres_username" --value "dev_username" --type SecureString
|
|
90
|
+
aws ssm put-parameter --name "/dev/db/postgres_password" --value "dev_password" --type SecureString
|
|
91
|
+
aws ssm put-parameter --name "/prod/app/secret" --value "prod_secret" --type SecureString
|
|
92
|
+
aws ssm put-parameter --name "/prod/db/postgres_username" --value "prod_username" --type SecureString
|
|
93
|
+
aws ssm put-parameter --name "/prod/db/postgres_password" --value "prod_password" --type SecureString
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
Get a single parameter
|
|
98
|
+
----------------------
|
|
99
|
+
|
|
100
|
+
``` python
|
|
101
|
+
parameter = store.get_parameter('param1', decrypt=True)
|
|
102
|
+
|
|
103
|
+
assert parameter == {
|
|
104
|
+
'param1': 'value1'
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Get multiple parameters
|
|
109
|
+
-----------------------
|
|
110
|
+
|
|
111
|
+
``` python
|
|
112
|
+
parameters = store.get_parameters(['param1', 'param2'])
|
|
113
|
+
|
|
114
|
+
assert parameters == {
|
|
115
|
+
'param1': 'value1',
|
|
116
|
+
'param2': 'value2',
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Get parameters by path
|
|
121
|
+
----------------------
|
|
122
|
+
|
|
123
|
+
``` python
|
|
124
|
+
parameters = store.get_parameters_by_path('/dev/', recursive=True)
|
|
125
|
+
|
|
126
|
+
assert parameters == {
|
|
127
|
+
'secret': 'dev_secret',
|
|
128
|
+
'postgres_username': 'dev_username',
|
|
129
|
+
'postgres_password': 'dev_password',
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
By default `get_parameters_by_path` strips the path from each parameter name. To return a parameter's full name, set `strip_path` to `False`.
|
|
134
|
+
|
|
135
|
+
``` python
|
|
136
|
+
parameters = store.get_parameters_by_path('/dev/', strip_path=False, recursive=True)
|
|
137
|
+
|
|
138
|
+
assert parameters == {
|
|
139
|
+
'/dev/app/secret': 'dev_secret',
|
|
140
|
+
'/dev/db/postgres_username': 'dev_username',
|
|
141
|
+
'/dev/db/postgres_password': 'dev_password'
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Get parameters with original hierarchy
|
|
146
|
+
--------------------------------------
|
|
147
|
+
You can also get parameters by path, but in a nested structure that models the path hierarchy.
|
|
148
|
+
|
|
149
|
+
``` python
|
|
150
|
+
parameters = store.get_parameters_with_hierarchy('/dev/')
|
|
151
|
+
|
|
152
|
+
assert parameters == {
|
|
153
|
+
'app': {
|
|
154
|
+
'secret': 'dev_secret',
|
|
155
|
+
},
|
|
156
|
+
'db': {
|
|
157
|
+
'postgres_username': 'dev_username',
|
|
158
|
+
'postgres_password': 'dev_password',
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
By default `get_parameters_with_hierarchy` strips the leading path component. To return the selected parameters
|
|
164
|
+
with the full hierarchy, set `strip_path` to `False`.
|
|
165
|
+
|
|
166
|
+
``` python
|
|
167
|
+
parameters = store.get_parameters_with_hierarchy('/dev/', strip_path=False)
|
|
168
|
+
|
|
169
|
+
assert parameters == {
|
|
170
|
+
'dev': {
|
|
171
|
+
'app': {
|
|
172
|
+
'secret': 'dev_secret',
|
|
173
|
+
},
|
|
174
|
+
'db': {
|
|
175
|
+
'postgres_username': 'dev_username',
|
|
176
|
+
'postgres_password': 'dev_password',
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
Populating Environment Variables
|
|
184
|
+
================================
|
|
185
|
+
|
|
186
|
+
The module includes a static method on `EC2ParameterStore` to help populate environment variables. This can be helpful when integrating with a library like [`django-environ`](https://github.com/joke2k/django-environ).
|
|
187
|
+
|
|
188
|
+
Example
|
|
189
|
+
-------
|
|
190
|
+
Given the following parameters:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
aws ssm put-parameter --name "/prod/django/SECRET_KEY" --value "-$y_^@69bm69+z!fawbdf=h_10+zjzfwr8_c=$$&j@-%p$%ct^" --type SecureString
|
|
194
|
+
aws ssm put-parameter --name "/prod/django/DATABASE_URL" --value "psql://user:pass@db-prod.xyz123.us-west-2.rds.amazonaws.com:5432/db" --type SecureString
|
|
195
|
+
aws ssm put-parameter --name "/prod/django/REDIS_URL" --value "redis://redis-prod.edc1ba.0001.usw2.cache.amazonaws.com:6379" --type SecureString
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
import environ
|
|
200
|
+
from ssm_parameter_store import EC2ParameterStore
|
|
201
|
+
|
|
202
|
+
env = environ.Env(
|
|
203
|
+
DEBUG=(bool, False)
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Get parameters and populate os.environ (region not required if AWS_DEFAULT_REGION environment variable set)
|
|
207
|
+
parameter_store = EC2ParameterStore(region_name='us-west-2')
|
|
208
|
+
django_parameters = parameter_store.get_parameters_by_path('/prod/django/', strip_path=True)
|
|
209
|
+
EC2ParameterStore.set_env(django_parameters)
|
|
210
|
+
|
|
211
|
+
# False if not in os.environ
|
|
212
|
+
DEBUG = env('DEBUG')
|
|
213
|
+
|
|
214
|
+
# Raises django's ImproperlyConfigured exception if SECRET_KEY not in os.environ
|
|
215
|
+
SECRET_KEY = env('SECRET_KEY')
|
|
216
|
+
|
|
217
|
+
DATABASES = {
|
|
218
|
+
# read os.environ['DATABASE_URL'] and raises ImproperlyConfigured exception if not found
|
|
219
|
+
'default': env.db(),
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
CACHES = {
|
|
223
|
+
'default': env.cache('REDIS_URL'),
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Related Projects
|
|
228
|
+
================
|
|
229
|
+
|
|
230
|
+
- **[param-store](https://github.com/LabD/python-param-store)** –
|
|
231
|
+
Python module to store secrets in secret stores
|
|
232
|
+
- **[ssm-cache](https://github.com/alexcasalboni/ssm-cache-python)** –
|
|
233
|
+
AWS System Manager Parameter Store caching client for Python
|
|
234
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
ssm_parameter_store/__init__.py,sha256=ZtdsNKGNga0r8SAWQz3fPRRShl06bfEspqLDhHIW3Qs,119
|
|
2
|
+
ssm_parameter_store/stores.py,sha256=SGWXvEtC9YTtvbq_Zx5gTW-Yk5iTqUiuGJ3osKxKYSM,3179
|
|
3
|
+
ssm_parameter_store/version.py,sha256=K_XsbYhe_xoL2DuCugHuVI2MFtfXNoCg1KXsnhzUy4U,199
|
|
4
|
+
ssm_parameter_store-26.8.0.dist-info/WHEEL,sha256=Lkz__M3n3EKWmzMwHnFILNW2SHO43bOxmbqnBjwb--4,80
|
|
5
|
+
ssm_parameter_store-26.8.0.dist-info/entry_points.txt,sha256=Bt18Vw-a4Hgvm6ps1zqpfhlfKO3U8F0YpTZyGzuD9FQ,66
|
|
6
|
+
ssm_parameter_store-26.8.0.dist-info/METADATA,sha256=0QzTFCnPJHAZaNgh2HNwN9EznkTjiojkqqWK0Ne0nhc,7052
|
|
7
|
+
ssm_parameter_store-26.8.0.dist-info/RECORD,,
|