From 4ef10bcc7033533f0cc188522df2cb75cef2259f Mon Sep 17 00:00:00 2001 From: Michiel Bijland Date: Thu, 4 Oct 2018 13:37:03 +0200 Subject: [PATCH 1/4] Initial support for azure vault --- Makefile | 2 +- setup.py | 5 ++++ src/param_store/stores.py | 48 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index dcc2dcd..334d259 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ install: - pip install -e .[docs,test] + pip install -e .[docs,test,azure] test: py.test diff --git a/setup.py b/setup.py index e4b3198..1deff51 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,10 @@ 'six>=1.1', ] +azure_require = [ + 'azure-keyvault', +] + docs_require = [ 'sphinx>=1.4.0', ] @@ -41,6 +45,7 @@ install_requires=install_requires, tests_require=tests_require, extras_require={ + 'azure': azure_require, 'docs': docs_require, 'test': tests_require, }, diff --git a/src/param_store/stores.py b/src/param_store/stores.py index aaa927e..19eac2c 100644 --- a/src/param_store/stores.py +++ b/src/param_store/stores.py @@ -1,7 +1,8 @@ from itertools import islice __all__ = [ - 'EC2ParameterStore' + 'EC2ParameterStore', + 'AzureVaultParameterStore', ] @@ -44,3 +45,48 @@ def chunk(it, size): value = parameter['Value'] result[key] = value return result + + +class AzureVaultParameterStore(BaseStore): + + def __init__(self): + import adal + from azure.keyvault import KeyVaultClient, KeyVaultAuthentication + from os import getenv + + self.vault_id = getenv("AZURE_VAULT_ID") + self.client_id = getenv("AZURE_APP_ID") + self.tenant_id = getenv("AZURE_TENANT_ID") + + # create an adal authentication context + auth_context = adal.AuthenticationContext( + 'https://login.microsoftonline.com/%s' % self.tenant_id) + + def auth_callback(server, resource, scope): + user_code_info = auth_context.acquire_user_code(resource, self.client_id) + + token = auth_context.acquire_token_with_device_code(resource=resource, + client_id=self.client_id, + user_code_info=user_code_info) + return token['token_type'], token['access_token'] + + self.client = KeyVaultClient(KeyVaultAuthentication(auth_callback)) + + def load_values(self, items): + from azure.keyvault.models import KeyVaultErrorException + from azure.keyvault import KeyVaultId + + if not items: + return {} + + result = {} + for key in items: + try: + data = self.client.get_secret("https://%s.vault.azure.net/" % self.vault_id, + key, KeyVaultId.version_none) + except KeyVaultErrorException: + continue + + result[key] = data.value + + return result From 2f4e90057ae8b1b53a04dc3c3d5009423402714d Mon Sep 17 00:00:00 2001 From: Michiel Bijland Date: Thu, 4 Oct 2018 15:35:20 +0200 Subject: [PATCH 2/4] set default and bumped version --- setup.py | 2 +- src/param_store/stores.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 1deff51..35d3d21 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ setup( name='param-store', - version='0.2.1', + version='0.2.2', description="Parameter store for secrets", long_description=long_description, url='https://github.com/labd/python-param-store', diff --git a/src/param_store/stores.py b/src/param_store/stores.py index 19eac2c..d26eaac 100644 --- a/src/param_store/stores.py +++ b/src/param_store/stores.py @@ -54,9 +54,9 @@ def __init__(self): from azure.keyvault import KeyVaultClient, KeyVaultAuthentication from os import getenv - self.vault_id = getenv("AZURE_VAULT_ID") - self.client_id = getenv("AZURE_APP_ID") - self.tenant_id = getenv("AZURE_TENANT_ID") + self.vault_id = getenv("AZURE_VAULT_ID", None) + self.client_id = getenv("AZURE_APP_ID", None) + self.tenant_id = getenv("AZURE_TENANT_ID", None) # create an adal authentication context auth_context = adal.AuthenticationContext( @@ -76,7 +76,7 @@ def load_values(self, items): from azure.keyvault.models import KeyVaultErrorException from azure.keyvault import KeyVaultId - if not items: + if not items or not self.vault_id: return {} result = {} From be43ff11f96bebe3514b60569236e2a607a41db0 Mon Sep 17 00:00:00 2001 From: Michiel Bijland Date: Thu, 4 Oct 2018 16:17:51 +0200 Subject: [PATCH 3/4] added both auth methods, we might also want to support certificate validation later on. --- setup.py | 2 +- src/param_store/stores.py | 50 +++++++++++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index 35d3d21..1deff51 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ setup( name='param-store', - version='0.2.2', + version='0.2.1', description="Parameter store for secrets", long_description=long_description, url='https://github.com/labd/python-param-store', diff --git a/src/param_store/stores.py b/src/param_store/stores.py index d26eaac..21ef17b 100644 --- a/src/param_store/stores.py +++ b/src/param_store/stores.py @@ -47,28 +47,52 @@ def chunk(it, size): return result +class AzureVaultConfigurationException(Exception): + pass + + class AzureVaultParameterStore(BaseStore): def __init__(self): - import adal from azure.keyvault import KeyVaultClient, KeyVaultAuthentication from os import getenv self.vault_id = getenv("AZURE_VAULT_ID", None) - self.client_id = getenv("AZURE_APP_ID", None) self.tenant_id = getenv("AZURE_TENANT_ID", None) - # create an adal authentication context - auth_context = adal.AuthenticationContext( - 'https://login.microsoftonline.com/%s' % self.tenant_id) - - def auth_callback(server, resource, scope): - user_code_info = auth_context.acquire_user_code(resource, self.client_id) - - token = auth_context.acquire_token_with_device_code(resource=resource, - client_id=self.client_id, - user_code_info=user_code_info) - return token['token_type'], token['access_token'] + self.app_id = getenv("AZURE_APP_ID", None) + self.client_id = getenv("AZURE_CLIENT_ID", None) + self.secret = getenv("AZURE_SECRET", None) + + if self.app_id: + import adal + + # create an adal authentication context + auth_context = adal.AuthenticationContext( + 'https://login.microsoftonline.com/%s' % self.tenant_id) + + def auth_callback(server, resource, scope): + user_code_info = auth_context.acquire_user_code(resource, self.app_id) + + token = auth_context.acquire_token_with_device_code(resource=resource, + client_id=self.app_id, + user_code_info=user_code_info) + return token['token_type'], token['access_token'] + elif self.client_id and self.secret: + from azure.common.credentials import ServicePrincipalCredentials + + def auth_callback(server, resource, scope): + credentials = ServicePrincipalCredentials( + client_id=self.client_id, + secret=self.secret, + tenant=self.tenant_id, + resource="https://vault.azure.net" + ) + token = credentials.token + return token['token_type'], token['access_token'] + else: + raise AzureVaultConfigurationException("Either set AZURE_APP_ID or " + "(AZURE_CLIENT_ID and AZURE_SECRET)") self.client = KeyVaultClient(KeyVaultAuthentication(auth_callback)) From 57ad4c865252b6c9306f7440fc1c5130046aa3ed Mon Sep 17 00:00:00 2001 From: Michiel Bijland Date: Thu, 4 Oct 2018 16:25:48 +0200 Subject: [PATCH 4/4] =?UTF-8?q?Bump=20version:=200.2.1=20=E2=86=92=200.2.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/conf.py | 4 ++-- setup.cfg | 2 +- setup.py | 2 +- src/param_store/__init__.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 81b3966..59eaf2a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -56,7 +56,7 @@ # |version| and |release|, also used in various other places throughout the # built documents. # -version = '0.2.1' +version = '0.2.2' release = version # The language for content autogenerated by Sphinx. Refer to documentation @@ -139,7 +139,7 @@ # The name for this set of Sphinx documents. # " v documentation" by default. # -# html_title = u'python-param-store v0.2.1' +# html_title = u'python-param-store v0.2.2' # A shorter title for the navigation bar. Default is the same as html_title. # diff --git a/setup.cfg b/setup.cfg index fb4aadb..f97362e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.2.1 +current_version = 0.2.2 commit = true tag = true tag_name = {new_version} diff --git a/setup.py b/setup.py index 1deff51..35d3d21 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ setup( name='param-store', - version='0.2.1', + version='0.2.2', description="Parameter store for secrets", long_description=long_description, url='https://github.com/labd/python-param-store', diff --git a/src/param_store/__init__.py b/src/param_store/__init__.py index 9f8c88c..21faa97 100644 --- a/src/param_store/__init__.py +++ b/src/param_store/__init__.py @@ -3,4 +3,4 @@ __all__ = ['Env', 'EC2ParameterStore'] -__version__ = '0.2.1' +__version__ = '0.2.2'