From deead852b5439f41250b4057ceaaa0d06f0f182f Mon Sep 17 00:00:00 2001 From: Rob Gil Date: Sun, 15 Dec 2019 14:19:52 -0500 Subject: [PATCH 1/4] 169163334 - Initial secrets-tool commit Adds admin_users map and keyvault policy This adds an admin_users map as well as a new policy in the keyvault module. When run, this will apply an administrator policy for users in the admin_users map. With these permissions, the admin users will be able to manage secrets and keys in keyvault. 169163334 - Initial secrets-tool commit Adds admin_users map and keyvault policy This adds an admin_users map as well as a new policy in the keyvault module. When run, this will apply an administrator policy for users in the admin_users map. With these permissions, the admin users will be able to manage secrets and keys in keyvault. 170237669 - Makes the read only policy for keyvault optional and only create the policy if a principal_id is passed 170237669 - Adds new operator keyvault for secrets This is a new keyvault specifically for storing operator secrets and things that would not be accessible to applications. The primary use case for this is for launching things like postgres (root postgres creds) and other services which would require secrets to be added to the terraform configuration. This approach avoids adding secrets to terraform. An accompanying script will be added to populate the new keyvault. --- terraform/.gitignore | 1 + terraform/modules/keyvault/main.tf | 25 ++++++- terraform/modules/keyvault/variables.tf | 5 ++ terraform/providers/dev/keyvault.tf | 16 +++-- terraform/providers/dev/variables.tf | 8 +++ terraform/secrets-tool/.gitignore | 4 ++ terraform/secrets-tool/commands/__init__.py | 0 terraform/secrets-tool/commands/secrets.py | 35 ++++++++++ terraform/secrets-tool/commands/terraform.py | 67 +++++++++++++++++++ terraform/secrets-tool/config.py | 28 ++++++++ terraform/secrets-tool/logging.yaml | 60 +++++++++++++++++ terraform/secrets-tool/requirements.txt | 54 +++++++++++++++ terraform/secrets-tool/secrets-tool | 52 ++++++++++++++ terraform/secrets-tool/utils/__init__.py | 0 .../secrets-tool/utils/keyvault/__init__.py | 0 terraform/secrets-tool/utils/keyvault/auth.py | 10 +++ terraform/secrets-tool/utils/keyvault/keys.py | 19 ++++++ .../secrets-tool/utils/keyvault/secrets.py | 26 +++++++ 18 files changed, 402 insertions(+), 8 deletions(-) create mode 100644 terraform/secrets-tool/.gitignore create mode 100644 terraform/secrets-tool/commands/__init__.py create mode 100644 terraform/secrets-tool/commands/secrets.py create mode 100644 terraform/secrets-tool/commands/terraform.py create mode 100644 terraform/secrets-tool/config.py create mode 100644 terraform/secrets-tool/logging.yaml create mode 100644 terraform/secrets-tool/requirements.txt create mode 100755 terraform/secrets-tool/secrets-tool create mode 100644 terraform/secrets-tool/utils/__init__.py create mode 100644 terraform/secrets-tool/utils/keyvault/__init__.py create mode 100644 terraform/secrets-tool/utils/keyvault/auth.py create mode 100644 terraform/secrets-tool/utils/keyvault/keys.py create mode 100644 terraform/secrets-tool/utils/keyvault/secrets.py diff --git a/terraform/.gitignore b/terraform/.gitignore index 3fa8c86b..f75853bd 100644 --- a/terraform/.gitignore +++ b/terraform/.gitignore @@ -1 +1,2 @@ .terraform +.vscode/ diff --git a/terraform/modules/keyvault/main.tf b/terraform/modules/keyvault/main.tf index 51437c45..d5153831 100644 --- a/terraform/modules/keyvault/main.tf +++ b/terraform/modules/keyvault/main.tf @@ -19,7 +19,8 @@ resource "azurerm_key_vault" "keyvault" { } } -resource "azurerm_key_vault_access_policy" "keyvault" { +resource "azurerm_key_vault_access_policy" "keyvault_k8s_policy" { + count = length(var.principal_id) > 0 ? 1 : 0 key_vault_id = azurerm_key_vault.keyvault.id tenant_id = data.azurerm_client_config.current.tenant_id @@ -34,3 +35,25 @@ resource "azurerm_key_vault_access_policy" "keyvault" { ] } +# Admin Access +resource "azurerm_key_vault_access_policy" "keyvault_admin_policy" { + for_each = var.admin_principals + key_vault_id = azurerm_key_vault.keyvault.id + + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = each.value + + key_permissions = [ + "get", + "list", + "create", + "update", + "delete", + ] + + secret_permissions = [ + "get", + "list", + "set", + ] +} \ No newline at end of file diff --git a/terraform/modules/keyvault/variables.tf b/terraform/modules/keyvault/variables.tf index 2333d228..d2484793 100644 --- a/terraform/modules/keyvault/variables.tf +++ b/terraform/modules/keyvault/variables.tf @@ -27,3 +27,8 @@ variable "principal_id" { type = string description = "The service principal_id of the k8s cluster" } + +variable "admin_principals" { + type = map + description = "A list of user principals who need access to manage the keyvault" +} diff --git a/terraform/providers/dev/keyvault.tf b/terraform/providers/dev/keyvault.tf index 25e448de..aca74e78 100644 --- a/terraform/providers/dev/keyvault.tf +++ b/terraform/providers/dev/keyvault.tf @@ -1,9 +1,11 @@ module "keyvault" { - source = "../../modules/keyvault" - name = var.name - region = var.region - owner = var.owner - environment = var.environment - tenant_id = var.tenant_id - principal_id = "f9bcbe58-8b73-4957-aee2-133dc3e58063" + source = "../../modules/keyvault" + name = var.name + region = var.region + owner = var.owner + environment = var.environment + tenant_id = var.tenant_id + principal_id = "f9bcbe58-8b73-4957-aee2-133dc3e58063" + admin_principals = var.admin_users } + diff --git a/terraform/providers/dev/variables.tf b/terraform/providers/dev/variables.tf index 7fcb6ee0..24c59503 100644 --- a/terraform/providers/dev/variables.tf +++ b/terraform/providers/dev/variables.tf @@ -71,3 +71,11 @@ variable "tenant_id" { type = string default = "b5ab0e1e-09f8-4258-afb7-fb17654bc5b3" } + +variable "admin_users" { + type = map + default = { + "Rob Gil" = "2ca63d41-d058-4e06-aef6-eb517a53b631" + "Daniel Corrigan" = "d5bb69c2-3b88-4e96-b1a2-320400f1bf1b" + } +} diff --git a/terraform/secrets-tool/.gitignore b/terraform/secrets-tool/.gitignore new file mode 100644 index 00000000..43f82f3f --- /dev/null +++ b/terraform/secrets-tool/.gitignore @@ -0,0 +1,4 @@ +bin/ +include/ +lib/ + diff --git a/terraform/secrets-tool/commands/__init__.py b/terraform/secrets-tool/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/terraform/secrets-tool/commands/secrets.py b/terraform/secrets-tool/commands/secrets.py new file mode 100644 index 00000000..7dbd16e7 --- /dev/null +++ b/terraform/secrets-tool/commands/secrets.py @@ -0,0 +1,35 @@ +import click +import logging +from utils.keyvault.secrets import SecretsClient + +logger = logging.getLogger(__name__) + +#loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict] +#print(loggers) + +@click.group() +@click.option('--keyvault', required=True, help="Specify the keyvault to operate on") +@click.pass_context +def secrets(ctx, keyvault): + ctx.ensure_object(dict) + ctx.obj['keyvault'] = keyvault + +@click.command('create') +@click.option('--key', 'key', required=True, help="Key for the secret to create") +@click.option('--value', 'value', required=True, prompt=True, hide_input=True, confirmation_prompt=True, help="Value for the secret to create") +@click.pass_context +def create_secret(ctx, key, value): + """Creates a secret in the specified KeyVault""" + keyvault = SecretsClient(vault_url=ctx.obj['keyvault']) + keyvault.set_secret(key, value) + +@click.command('list') +@click.pass_context +def list_secrets(ctx): + """Lists the secrets in the specified KeyVault""" + keyvault = SecretsClient(vault_url=ctx.obj['keyvault']) + click.echo(keyvault.list_secrets()) + + +secrets.add_command(create_secret) +secrets.add_command(list_secrets) \ No newline at end of file diff --git a/terraform/secrets-tool/commands/terraform.py b/terraform/secrets-tool/commands/terraform.py new file mode 100644 index 00000000..f34db59d --- /dev/null +++ b/terraform/secrets-tool/commands/terraform.py @@ -0,0 +1,67 @@ +import os +import click +import logging +import subprocess + +from utils.keyvault.secrets import SecretsClient + +logger = logging.getLogger(__name__) + +PROCESS='terraform' + +@click.group() +@click.pass_context +def terraform(ctx): + pass + +@click.command('plan') +@click.pass_context +def plan(ctx): + keyvault = SecretsClient(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") + # Set env variables for TF + for secret in keyvault.list_secrets(): + name = 'TF_VAR_' + secret + val = keyvault.get_secret(secret) + #print(val) + os.environ[name] = val + env = os.environ.copy() + command = "{} {}".format(PROCESS, 'plan') + with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc: + for line in proc.stdout: + logging.info(line.decode("utf-8") ) + +@click.command('apply') +@click.pass_context +def apply(ctx): + keyvault = SecretsClient(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") + # Set env variables for TF + for secret in keyvault.list_secrets(): + name = 'TF_VAR_' + secret + val = keyvault.get_secret(secret) + #print(val) + os.environ[name] = val + env = os.environ.copy() + command = "{} {}".format(PROCESS, 'apply -auto-approve') + with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc: + for line in proc.stdout: + logging.info(line.decode("utf-8") ) + +@click.command('destroy') +@click.pass_context +def destroy(ctx): + keyvault = SecretsClient(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") + # Set env variables for TF + for secret in keyvault.list_secrets(): + name = 'TF_VAR_' + secret + val = keyvault.get_secret(secret) + #print(val) + os.environ[name] = val + env = os.environ.copy() + command = "{} {}".format(PROCESS, 'destroy') + with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc: + for line in proc.stdout: + logging.info(line.decode("utf-8") ) + +terraform.add_command(plan) +terraform.add_command(apply) +terraform.add_command(destroy) \ No newline at end of file diff --git a/terraform/secrets-tool/config.py b/terraform/secrets-tool/config.py new file mode 100644 index 00000000..46284914 --- /dev/null +++ b/terraform/secrets-tool/config.py @@ -0,0 +1,28 @@ +import os +import yaml +import logging.config +import logging +import coloredlogs + +LOGGING_PATH=os.path.dirname(os.path.abspath(__file__)) + +def setup_logging(default_path='{}/logging.yaml'.format(LOGGING_PATH), default_level=logging.INFO, env_key='LOG_CFG'): + path = default_path + value = os.getenv(env_key, None) + if value: + path = value + if os.path.exists(path): + with open(path, 'rt') as f: + try: + config = yaml.safe_load(f.read()) + logging.config.dictConfig(config) + coloredlogs.install() + except Exception as e: + print(e) + print('Error in Logging Configuration. Using default configs') + logging.basicConfig(level=default_level) + coloredlogs.install(level=default_level) + else: + logging.basicConfig(level=default_level) + coloredlogs.install(level=default_level) + print('Failed to load configuration file. Using default configs') diff --git a/terraform/secrets-tool/logging.yaml b/terraform/secrets-tool/logging.yaml new file mode 100644 index 00000000..3aaf1619 --- /dev/null +++ b/terraform/secrets-tool/logging.yaml @@ -0,0 +1,60 @@ +version: 1 +disable_existing_loggers: true + +formatters: + standard: + format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + error: + format: "%(levelname)s %(name)s.%(funcName)s(): %(message)s" + +handlers: + console: + class: logging.StreamHandler + level: DEBUG + formatter: standard + stream: ext://sys.stdout + + file_handler: + class: logging.handlers.RotatingFileHandler + level: INFO + formatter: standard + filename: secrets-tool.log + maxBytes: 10485760 # 10MB + backupCount: 20 + encoding: utf8 + +root: + level: INFO + handlers: [console] + propogate: yes + +loggers: + root: + level: INFO + handlers: [console] + propogate: no + click: + level: INFO + handlers: [console] + propogate: yes + azure.keyvault: + level: INFO + handlers: [console] + propogate: yes + azure.core: + level: ERROR + handlers: [console] + propogate: no + utils.keyvault.secrets: + level: DEBUG + handlers: [console] + propogate: yes + commands: + level: INFO + handlers: [console] + propogate: yes + main: + level: INFO + handlers: [console] + propogate: no + diff --git a/terraform/secrets-tool/requirements.txt b/terraform/secrets-tool/requirements.txt new file mode 100644 index 00000000..fd1bf88f --- /dev/null +++ b/terraform/secrets-tool/requirements.txt @@ -0,0 +1,54 @@ +adal==1.2.2 +antlr4-python3-runtime==4.7.2 +applicationinsights==0.11.9 +argcomplete==1.10.3 +astroid==2.3.3 +azure-cli-core==2.0.77 +azure-cli-nspkg==3.0.4 +azure-cli-telemetry==1.0.4 +azure-common==1.1.23 +azure-core==1.1.1 +azure-identity==1.1.0 +azure-keyvault==4.0.0 +azure-keyvault-keys==4.0.0 +azure-keyvault-secrets==4.0.0 +azure-mgmt-resource==4.0.0 +azure-nspkg==3.0.2 +bcrypt==3.1.7 +certifi==2019.11.28 +cffi==1.13.2 +chardet==3.0.4 +Click==7.0 +colorama==0.4.3 +coloredlogs==10.0 +cryptography==2.8 +humanfriendly==4.18 +idna==2.8 +isodate==0.6.0 +isort==4.3.21 +jmespath==0.9.4 +knack==0.6.3 +lazy-object-proxy==1.4.3 +mccabe==0.6.1 +msal==1.0.0 +msal-extensions==0.1.3 +msrest==0.6.10 +msrestazure==0.6.2 +oauthlib==3.1.0 +paramiko==2.7.1 +portalocker==1.5.2 +pycparser==2.19 +Pygments==2.5.2 +PyJWT==1.7.1 +pylint==2.4.4 +PyNaCl==1.3.0 +pyOpenSSL==19.1.0 +python-dateutil==2.8.1 +PyYAML==5.2 +requests==2.22.0 +requests-oauthlib==1.3.0 +six==1.13.0 +tabulate==0.8.6 +typed-ast==1.4.0 +urllib3==1.25.7 +wrapt==1.11.2 diff --git a/terraform/secrets-tool/secrets-tool b/terraform/secrets-tool/secrets-tool new file mode 100755 index 00000000..58079e3e --- /dev/null +++ b/terraform/secrets-tool/secrets-tool @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# CLI +import click + +import config +import logging + +from commands.secrets import secrets +from commands.terraform import terraform + +config.setup_logging() +logger = logging.getLogger(__name__) + +PROCESS='terraform' + +# Define core command group +@click.group() +def cli(): + pass + +# Add additional command groups +cli.add_command(secrets) +cli.add_command(terraform) + + +if __name__ == "__main__": + try: + cli() + except Exception as e: + print(e) + +''' + try: + keyvault = secrets(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") + keyvault.set_secret('dbuser','foo') + #print(keyvault.get_secret('db-user').value) + + # Set env variables for TF + for secret in keyvault.list_secrets(): + name = 'TF_VAR_' + secret + val = keyvault.get_secret(secret) + #print(val) + os.environ[name] = val + env = os.environ.copy() + command = "{} {}".format(PROCESS, sys.argv[1]) + with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc: + for line in proc.stdout: + logging.info(line.decode("utf-8") ) + + except Exception as e: + print(e, traceback.print_stack) +''' \ No newline at end of file diff --git a/terraform/secrets-tool/utils/__init__.py b/terraform/secrets-tool/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/terraform/secrets-tool/utils/keyvault/__init__.py b/terraform/secrets-tool/utils/keyvault/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/terraform/secrets-tool/utils/keyvault/auth.py b/terraform/secrets-tool/utils/keyvault/auth.py new file mode 100644 index 00000000..d69367c2 --- /dev/null +++ b/terraform/secrets-tool/utils/keyvault/auth.py @@ -0,0 +1,10 @@ +import logging + +from azure.identity import InteractiveBrowserCredential + +logger = logging.getLogger(__name__) + +class Auth: + def __init__(self, vault_url, *args, **kwargs): + self.credentials = InteractiveBrowserCredential() + self.vault_url = vault_url \ No newline at end of file diff --git a/terraform/secrets-tool/utils/keyvault/keys.py b/terraform/secrets-tool/utils/keyvault/keys.py new file mode 100644 index 00000000..2db0cb95 --- /dev/null +++ b/terraform/secrets-tool/utils/keyvault/keys.py @@ -0,0 +1,19 @@ +import logging +from azure.keyvault.keys import KeyClient +from .auth import Auth + +logger = logging.getLogger(__name__) + +KEY_SIZE=2048 +KEY_TYPE='rsa' + +class keys(Auth): + def __init__(self, *args, **kwargs): + super(keys, self).__init__(*args, **kwargs) + self.key_client = KeyClient(vault_url=self.vault_url, credential=self.credentials) + + def get_key(self): + return self.key_client + + def create_key(self): + pass \ No newline at end of file diff --git a/terraform/secrets-tool/utils/keyvault/secrets.py b/terraform/secrets-tool/utils/keyvault/secrets.py new file mode 100644 index 00000000..1c554146 --- /dev/null +++ b/terraform/secrets-tool/utils/keyvault/secrets.py @@ -0,0 +1,26 @@ +import logging +from .auth import Auth +from azure.keyvault.secrets import SecretClient + +logger = logging.getLogger(__name__) + +class SecretsClient(Auth): + def __init__(self, *args, **kwargs): + super(SecretsClient, self).__init__(*args, **kwargs) + self.secret_client = SecretClient(vault_url=self.vault_url, credential=self.credentials) + + def get_secret(self, key): + secret = self.secret_client.get_secret(key) + return secret.value + + def set_secret(self, key: str, value: str): + secret = self.secret_client.set_secret(key, value) + logger.debug('Set value for key: {}'.format(key)) + return secret + + def list_secrets(self): + secrets = list() + secret_properties = self.secret_client.list_properties_of_secrets() + for secret in secret_properties: + secrets.append(secret.name) + return secrets \ No newline at end of file From aa89505650e9f7873067d79f9abd8ea54a2365e3 Mon Sep 17 00:00:00 2001 From: Rob Gil Date: Thu, 16 Jan 2020 12:51:20 -0500 Subject: [PATCH 2/4] 169163334 - Abstracts terraform wrapper code The terraform wrapper is now abstracted in to a utility class for working with terraform. The terraform module was also updated to support configurable keyvault servers. Logging for this new module was also added, so the terraform output is seen on the console. --- terraform/secrets-tool/commands/terraform.py | 62 +++++++------------ terraform/secrets-tool/logging.yaml | 4 ++ .../secrets-tool/utils/terraform/__init__.py | 0 .../secrets-tool/utils/terraform/wrapper.py | 61 ++++++++++++++++++ 4 files changed, 88 insertions(+), 39 deletions(-) create mode 100644 terraform/secrets-tool/utils/terraform/__init__.py create mode 100644 terraform/secrets-tool/utils/terraform/wrapper.py diff --git a/terraform/secrets-tool/commands/terraform.py b/terraform/secrets-tool/commands/terraform.py index f34db59d..8fcdf55a 100644 --- a/terraform/secrets-tool/commands/terraform.py +++ b/terraform/secrets-tool/commands/terraform.py @@ -4,64 +4,48 @@ import logging import subprocess from utils.keyvault.secrets import SecretsClient +from utils.terraform.wrapper import TFWrapper logger = logging.getLogger(__name__) PROCESS='terraform' @click.group() +@click.option('--keyvault', required=True, help="Specify the keyvault to operate on") @click.pass_context -def terraform(ctx): - pass +def terraform(ctx, keyvault): + ctx.ensure_object(dict) + ctx.obj['keyvault'] = keyvault @click.command('plan') @click.pass_context def plan(ctx): - keyvault = SecretsClient(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") - # Set env variables for TF - for secret in keyvault.list_secrets(): - name = 'TF_VAR_' + secret - val = keyvault.get_secret(secret) - #print(val) - os.environ[name] = val - env = os.environ.copy() - command = "{} {}".format(PROCESS, 'plan') - with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc: - for line in proc.stdout: - logging.info(line.decode("utf-8") ) + keyvault = SecretsClient(vault_url=ctx.obj['keyvault']) + tf = TFWrapper(keyvault) + tf.plan() @click.command('apply') @click.pass_context def apply(ctx): - keyvault = SecretsClient(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") - # Set env variables for TF - for secret in keyvault.list_secrets(): - name = 'TF_VAR_' + secret - val = keyvault.get_secret(secret) - #print(val) - os.environ[name] = val - env = os.environ.copy() - command = "{} {}".format(PROCESS, 'apply -auto-approve') - with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc: - for line in proc.stdout: - logging.info(line.decode("utf-8") ) + keyvault = SecretsClient(vault_url=ctx.obj['keyvault']) + tf = TFWrapper(keyvault) + tf.apply() @click.command('destroy') @click.pass_context def destroy(ctx): - keyvault = SecretsClient(vault_url="https://cloudzero-dev-keyvault.vault.azure.net/") - # Set env variables for TF - for secret in keyvault.list_secrets(): - name = 'TF_VAR_' + secret - val = keyvault.get_secret(secret) - #print(val) - os.environ[name] = val - env = os.environ.copy() - command = "{} {}".format(PROCESS, 'destroy') - with subprocess.Popen(command, env=env, stdout=subprocess.PIPE, shell=True) as proc: - for line in proc.stdout: - logging.info(line.decode("utf-8") ) + keyvault = SecretsClient(vault_url=ctx.obj['keyvault']) + tf = TFWrapper(keyvault) + tf.destroy() + +@click.command('init') +@click.pass_context +def init(ctx): + keyvault = SecretsClient(vault_url=ctx.obj['keyvault']) + tf = TFWrapper(keyvault) + tf.init() terraform.add_command(plan) terraform.add_command(apply) -terraform.add_command(destroy) \ No newline at end of file +terraform.add_command(destroy) +terraform.add_command(init) \ No newline at end of file diff --git a/terraform/secrets-tool/logging.yaml b/terraform/secrets-tool/logging.yaml index 3aaf1619..3e31ffd4 100644 --- a/terraform/secrets-tool/logging.yaml +++ b/terraform/secrets-tool/logging.yaml @@ -49,6 +49,10 @@ loggers: level: DEBUG handlers: [console] propogate: yes + utils.terraform.wrapper: + level: DEBUG + handlers: [console] + propogate: yes commands: level: INFO handlers: [console] diff --git a/terraform/secrets-tool/utils/terraform/__init__.py b/terraform/secrets-tool/utils/terraform/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/terraform/secrets-tool/utils/terraform/wrapper.py b/terraform/secrets-tool/utils/terraform/wrapper.py new file mode 100644 index 00000000..96d44396 --- /dev/null +++ b/terraform/secrets-tool/utils/terraform/wrapper.py @@ -0,0 +1,61 @@ +import os +import logging +import subprocess + +logger = logging.getLogger(__name__) + +class TFWrapper: + """ + Command wrapper for terraform that injects secrets + from keyvault in to environment variables which + can then be used by terraform + """ + def __init__(self, keyvault: object): + self.keyvault = keyvault + self.env = '' + self.terraform_path = 'terraform' + + self._set_env() + + def _set_env(self): + # Prefix variables with TF_VAR_ + for secret in self.keyvault.list_secrets(): + name = 'TF_VAR_' + secret + val = self.keyvault.get_secret(secret) + os.environ[name] = val + # Set the environment with new vars + self.env = os.environ.copy() + return None + + def _run_tf(self, option: str): + try: + command = '{} {}'.format(self.terraform_path, option) + with subprocess.Popen(command, env=self.env, stdout=subprocess.PIPE, shell=True) as proc: + for line in proc.stdout: + logging.info(line.decode("utf-8")) + except Exception as e: + print(e) + + def plan(self): + """ + terraform plan + """ + self._run_tf(option='plan') + + def init(self): + """ + terraform init + """ + self._run_tf(option='init') + + def apply(self): + """ + terraform apply + """ + self._run_tf(option='apply -auto-approve') + + def destroy(self): + """ + terraform destroy + """ + self._run_tf(option='destroy') \ No newline at end of file From b9a7efe6ba3fc6fb38834039ead82f3425b5f976 Mon Sep 17 00:00:00 2001 From: Rob Gil Date: Thu, 16 Jan 2020 13:30:14 -0500 Subject: [PATCH 3/4] Revised Pipfiles --- terraform/secrets-tool/Pipfile | 63 ++ terraform/secrets-tool/Pipfile.lock | 670 +++++++++++++++++++ terraform/secrets-tool/commands/terraform.py | 2 - 3 files changed, 733 insertions(+), 2 deletions(-) create mode 100644 terraform/secrets-tool/Pipfile create mode 100644 terraform/secrets-tool/Pipfile.lock diff --git a/terraform/secrets-tool/Pipfile b/terraform/secrets-tool/Pipfile new file mode 100644 index 00000000..60c1fc5a --- /dev/null +++ b/terraform/secrets-tool/Pipfile @@ -0,0 +1,63 @@ +[[source]] +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +requests = "==2.22.0" +adal = "==1.2.2" +antlr4-python3-runtime = "==4.7.2" +applicationinsights = "==0.11.9" +argcomplete = "==1.10.3" +astroid = "==2.3.3" +azure-cli-core = "==2.0.77" +azure-cli-nspkg = "==3.0.4" +azure-cli-telemetry = "==1.0.4" +azure-common = "==1.1.23" +azure-core = "==1.1.1" +azure-identity = "==1.1.0" +azure-keyvault = "==4.0.0" +azure-keyvault-keys = "==4.0.0" +azure-keyvault-secrets = "==4.0.0" +azure-mgmt-resource = "==4.0.0" +azure-nspkg = "==3.0.2" +bcrypt = "==3.1.7" +certifi = "==2019.11.28" +cffi = "==1.13.2" +chardet = "==3.0.4" +click = "==7.0" +colorama = "==0.4.3" +coloredlogs = "==10.0" +cryptography = "==2.8" +humanfriendly = "==4.18" +idna = "==2.8" +isodate = "==0.6.0" +isort = "==4.3.21" +jmespath = "==0.9.4" +knack = "==0.6.3" +lazy-object-proxy = "==1.4.3" +mccabe = "==0.6.1" +msal = "==1.0.0" +msal-extensions = "==0.1.3" +msrest = "==0.6.10" +msrestazure = "==0.6.2" +oauthlib = "==3.1.0" +paramiko = "==2.7.1" +portalocker = "==1.5.2" +pycparser = "==2.19" +Pygments = "==2.5.2" +PyJWT = "==1.7.1" +pylint = "==2.4.4" +PyNaCl = "==1.3.0" +pyOpenSSL = "==19.1.0" +python-dateutil = "==2.8.1" +PyYAML = "==5.2" +requests-oauthlib = "==1.3.0" +six = "==1.13.0" +tabulate = "==0.8.6" +typed-ast = "==1.4.0" +urllib3 = "==1.25.7" +wrapt = "==1.11.2" + +[dev-packages] +pytest = "*" diff --git a/terraform/secrets-tool/Pipfile.lock b/terraform/secrets-tool/Pipfile.lock new file mode 100644 index 00000000..49b109bc --- /dev/null +++ b/terraform/secrets-tool/Pipfile.lock @@ -0,0 +1,670 @@ +{ + "_meta": { + "hash": { + "sha256": "83c0cc35bbf74c0b7620a5b7f4f9fab4324e86442e12284d1b9ffcc12a371696" + }, + "pipfile-spec": 6, + "requires": {}, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.python.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "adal": { + "hashes": [ + "sha256:5a7f1e037c6290c6d7609cab33a9e5e988c2fbec5c51d1c4c649ee3faff37eaf", + "sha256:fd17e5661f60634ddf96a569b95d34ccb8a98de60593d729c28bdcfe360eaad1" + ], + "index": "pypi", + "version": "==1.2.2" + }, + "antlr4-python3-runtime": { + "hashes": [ + "sha256:168cdcec8fb9152e84a87ca6fd261b3d54c8f6358f42ab3b813b14a7193bb50b" + ], + "index": "pypi", + "markers": "python_version >= '3.0'", + "version": "==4.7.2" + }, + "applicationinsights": { + "hashes": [ + "sha256:30a11aafacea34f8b160fbdc35254c9029c7e325267874e3c68f6bdbcd6ed2c3", + "sha256:b88bc5a41385d8e516489128d5e63f8c52efe597a3579b1718d1ab2f7cf150a2" + ], + "index": "pypi", + "version": "==0.11.9" + }, + "argcomplete": { + "hashes": [ + "sha256:a37f522cf3b6a34abddfedb61c4546f60023b3799b22d1cd971eacdc0861530a", + "sha256:d8ea63ebaec7f59e56e7b2a386b1d1c7f1a7ae87902c9ee17d377eaa557f06fa" + ], + "index": "pypi", + "version": "==1.10.3" + }, + "astroid": { + "hashes": [ + "sha256:71ea07f44df9568a75d0f354c49143a4575d90645e9fead6dfb52c26a85ed13a", + "sha256:840947ebfa8b58f318d42301cf8c0a20fd794a33b61cc4638e28e9e61ba32f42" + ], + "index": "pypi", + "version": "==2.3.3" + }, + "azure-cli-core": { + "hashes": [ + "sha256:4281b71cf9a8278f665765c97eb3dae61fbf2dac916fc032c4acdf5ed2065210", + "sha256:d14a733dd6d6019c23dbd0b459026fef0978901d263382a1fdb71852293b9e6a" + ], + "index": "pypi", + "version": "==2.0.77" + }, + "azure-cli-nspkg": { + "hashes": [ + "sha256:1bde56090f548c6435bd3093995cf88e4c445fb040604df8b5b5f70780d79181", + "sha256:9a1e4f3197183470e4afecfdd45c92320f6753555b06a70651f89972332ffaf6" + ], + "index": "pypi", + "version": "==3.0.4" + }, + "azure-cli-telemetry": { + "hashes": [ + "sha256:1f239d544d309c29e827982cc20113eb57037dba16db6cdd2e0283e437e0e577", + "sha256:7b18d7520e35e134136a0f7de38403a7dbce7b1e835065bd9e965579815ddf2f" + ], + "index": "pypi", + "version": "==1.0.4" + }, + "azure-common": { + "hashes": [ + "sha256:53b1195b8f20943ccc0e71a17849258f7781bc6db1c72edc7d6c055f79bd54e3", + "sha256:99ef36e74b6395329aada288764ce80504da16ecc8206cb9a72f55fb02e8b484" + ], + "index": "pypi", + "version": "==1.1.23" + }, + "azure-core": { + "hashes": [ + "sha256:4d047fd4e46a958c9b63f9d5cb52e6bf7dfc5c2a1c2a81b968499335a94bb5cb", + "sha256:b44fe5b46d2bb0260cafb737ab5ee89a16d478fc1885dabe21c426c4df205502" + ], + "index": "pypi", + "version": "==1.1.1" + }, + "azure-identity": { + "hashes": [ + "sha256:0c8e540e1b75d48c54e5cd8d599f7ea5ccf4dae260c35bebb0c8d34d22b7c4f6", + "sha256:75f4ad9abfd191bd5f3de4c6dc29980b138bf5dfbbef9bca5c548a6048473bde" + ], + "index": "pypi", + "version": "==1.1.0" + }, + "azure-keyvault": { + "hashes": [ + "sha256:76f75cb83929f312a08616d426ad6f597f1beae180131cf445876fb88f2c8ef1", + "sha256:e85f5bd6cb4f10b3248b99bbf02e3acc6371d366846897027d4153f18025a2d7" + ], + "index": "pypi", + "version": "==4.0.0" + }, + "azure-keyvault-keys": { + "hashes": [ + "sha256:2983fa42e20a0e6bf6b87976716129c108e613e0292d34c5b0f0c8dc1d488e89", + "sha256:38c27322637a2c52620a8b96da1942ad6a8d22d09b5a01f6fa257f7a51e52ed0" + ], + "index": "pypi", + "version": "==4.0.0" + }, + "azure-keyvault-secrets": { + "hashes": [ + "sha256:2eae9264a8f6f59277e1a9bfdbc8b0a15969ee5a80d8efe403d7744805b4a481", + "sha256:97a602406a833e8f117c540c66059c818f4321a35168dd17365fab1e4527d718" + ], + "index": "pypi", + "version": "==4.0.0" + }, + "azure-mgmt-resource": { + "hashes": [ + "sha256:2b909f137469c7bfa541554c3d22eb918e9191c07667a42f2c6fc684e24ac83f", + "sha256:5022263349e66dba5ddadd3bf36208d82a00e0f1bb3288e32822fc821ccd1f76" + ], + "index": "pypi", + "version": "==4.0.0" + }, + "azure-nspkg": { + "hashes": [ + "sha256:1d0bbb2157cf57b1bef6c8c8e5b41133957364456c43b0a43599890023cca0a8", + "sha256:31a060caca00ed1ebd369fc7fe01a56768c927e404ebc92268f4d9d636435e28", + "sha256:e7d3cea6af63e667d87ba1ca4f8cd7cb4dfca678e4c55fc1cedb320760e39dd0" + ], + "index": "pypi", + "version": "==3.0.2" + }, + "bcrypt": { + "hashes": [ + "sha256:0258f143f3de96b7c14f762c770f5fc56ccd72f8a1857a451c1cd9a655d9ac89", + "sha256:0b0069c752ec14172c5f78208f1863d7ad6755a6fae6fe76ec2c80d13be41e42", + "sha256:19a4b72a6ae5bb467fea018b825f0a7d917789bcfe893e53f15c92805d187294", + "sha256:5432dd7b34107ae8ed6c10a71b4397f1c853bd39a4d6ffa7e35f40584cffd161", + "sha256:6305557019906466fc42dbc53b46da004e72fd7a551c044a827e572c82191752", + "sha256:69361315039878c0680be456640f8705d76cb4a3a3fe1e057e0f261b74be4b31", + "sha256:6fe49a60b25b584e2f4ef175b29d3a83ba63b3a4df1b4c0605b826668d1b6be5", + "sha256:74a015102e877d0ccd02cdeaa18b32aa7273746914a6c5d0456dd442cb65b99c", + "sha256:763669a367869786bb4c8fcf731f4175775a5b43f070f50f46f0b59da45375d0", + "sha256:8b10acde4e1919d6015e1df86d4c217d3b5b01bb7744c36113ea43d529e1c3de", + "sha256:9fe92406c857409b70a38729dbdf6578caf9228de0aef5bc44f859ffe971a39e", + "sha256:a190f2a5dbbdbff4b74e3103cef44344bc30e61255beb27310e2aec407766052", + "sha256:a595c12c618119255c90deb4b046e1ca3bcfad64667c43d1166f2b04bc72db09", + "sha256:c9457fa5c121e94a58d6505cadca8bed1c64444b83b3204928a866ca2e599105", + "sha256:cb93f6b2ab0f6853550b74e051d297c27a638719753eb9ff66d1e4072be67133", + "sha256:ce4e4f0deb51d38b1611a27f330426154f2980e66582dc5f438aad38b5f24fc1", + "sha256:d7bdc26475679dd073ba0ed2766445bb5b20ca4793ca0db32b399dccc6bc84b7", + "sha256:ff032765bb8716d9387fd5376d987a937254b0619eff0972779515b5c98820bc" + ], + "index": "pypi", + "version": "==3.1.7" + }, + "certifi": { + "hashes": [ + "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", + "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" + ], + "index": "pypi", + "version": "==2019.11.28" + }, + "cffi": { + "hashes": [ + "sha256:0b49274afc941c626b605fb59b59c3485c17dc776dc3cc7cc14aca74cc19cc42", + "sha256:0e3ea92942cb1168e38c05c1d56b0527ce31f1a370f6117f1d490b8dcd6b3a04", + "sha256:135f69aecbf4517d5b3d6429207b2dff49c876be724ac0c8bf8e1ea99df3d7e5", + "sha256:19db0cdd6e516f13329cba4903368bff9bb5a9331d3410b1b448daaadc495e54", + "sha256:2781e9ad0e9d47173c0093321bb5435a9dfae0ed6a762aabafa13108f5f7b2ba", + "sha256:291f7c42e21d72144bb1c1b2e825ec60f46d0a7468f5346841860454c7aa8f57", + "sha256:2c5e309ec482556397cb21ede0350c5e82f0eb2621de04b2633588d118da4396", + "sha256:2e9c80a8c3344a92cb04661115898a9129c074f7ab82011ef4b612f645939f12", + "sha256:32a262e2b90ffcfdd97c7a5e24a6012a43c61f1f5a57789ad80af1d26c6acd97", + "sha256:3c9fff570f13480b201e9ab69453108f6d98244a7f495e91b6c654a47486ba43", + "sha256:415bdc7ca8c1c634a6d7163d43fb0ea885a07e9618a64bda407e04b04333b7db", + "sha256:42194f54c11abc8583417a7cf4eaff544ce0de8187abaf5d29029c91b1725ad3", + "sha256:4424e42199e86b21fc4db83bd76909a6fc2a2aefb352cb5414833c030f6ed71b", + "sha256:4a43c91840bda5f55249413037b7a9b79c90b1184ed504883b72c4df70778579", + "sha256:599a1e8ff057ac530c9ad1778293c665cb81a791421f46922d80a86473c13346", + "sha256:5c4fae4e9cdd18c82ba3a134be256e98dc0596af1e7285a3d2602c97dcfa5159", + "sha256:5ecfa867dea6fabe2a58f03ac9186ea64da1386af2159196da51c4904e11d652", + "sha256:62f2578358d3a92e4ab2d830cd1c2049c9c0d0e6d3c58322993cc341bdeac22e", + "sha256:6471a82d5abea994e38d2c2abc77164b4f7fbaaf80261cb98394d5793f11b12a", + "sha256:6d4f18483d040e18546108eb13b1dfa1000a089bcf8529e30346116ea6240506", + "sha256:71a608532ab3bd26223c8d841dde43f3516aa5d2bf37b50ac410bb5e99053e8f", + "sha256:74a1d8c85fb6ff0b30fbfa8ad0ac23cd601a138f7509dc617ebc65ef305bb98d", + "sha256:7b93a885bb13073afb0aa73ad82059a4c41f4b7d8eb8368980448b52d4c7dc2c", + "sha256:7d4751da932caaec419d514eaa4215eaf14b612cff66398dd51129ac22680b20", + "sha256:7f627141a26b551bdebbc4855c1157feeef18241b4b8366ed22a5c7d672ef858", + "sha256:8169cf44dd8f9071b2b9248c35fc35e8677451c52f795daa2bb4643f32a540bc", + "sha256:aa00d66c0fab27373ae44ae26a66a9e43ff2a678bf63a9c7c1a9a4d61172827a", + "sha256:ccb032fda0873254380aa2bfad2582aedc2959186cce61e3a17abc1a55ff89c3", + "sha256:d754f39e0d1603b5b24a7f8484b22d2904fa551fe865fd0d4c3332f078d20d4e", + "sha256:d75c461e20e29afc0aee7172a0950157c704ff0dd51613506bd7d82b718e7410", + "sha256:dcd65317dd15bc0451f3e01c80da2216a31916bdcffd6221ca1202d96584aa25", + "sha256:e570d3ab32e2c2861c4ebe6ffcad6a8abf9347432a37608fe1fbd157b3f0036b", + "sha256:fd43a88e045cf992ed09fa724b5315b790525f2676883a6ea64e3263bae6549d" + ], + "index": "pypi", + "version": "==1.13.2" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "index": "pypi", + "version": "==3.0.4" + }, + "click": { + "hashes": [ + "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", + "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + ], + "index": "pypi", + "version": "==7.0" + }, + "colorama": { + "hashes": [ + "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff", + "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1" + ], + "index": "pypi", + "version": "==0.4.3" + }, + "coloredlogs": { + "hashes": [ + "sha256:34fad2e342d5a559c31b6c889e8d14f97cb62c47d9a2ae7b5ed14ea10a79eff8", + "sha256:b869a2dda3fa88154b9dd850e27828d8755bfab5a838a1c97fbc850c6e377c36" + ], + "index": "pypi", + "version": "==10.0" + }, + "cryptography": { + "hashes": [ + "sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c", + "sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595", + "sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad", + "sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651", + "sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2", + "sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff", + "sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d", + "sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42", + "sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d", + "sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e", + "sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912", + "sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793", + "sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13", + "sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7", + "sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0", + "sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879", + "sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f", + "sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9", + "sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2", + "sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf", + "sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8" + ], + "index": "pypi", + "version": "==2.8" + }, + "humanfriendly": { + "hashes": [ + "sha256:23057b10ad6f782e7bc3a20e3cb6768ab919f619bbdc0dd75691121bbde5591d", + "sha256:33ee8ceb63f1db61cce8b5c800c531e1a61023ac5488ccde2ba574a85be00a85" + ], + "index": "pypi", + "version": "==4.18" + }, + "idna": { + "hashes": [ + "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", + "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c" + ], + "index": "pypi", + "version": "==2.8" + }, + "isodate": { + "hashes": [ + "sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8", + "sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81" + ], + "index": "pypi", + "version": "==0.6.0" + }, + "isort": { + "hashes": [ + "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", + "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd" + ], + "index": "pypi", + "version": "==4.3.21" + }, + "jmespath": { + "hashes": [ + "sha256:3720a4b1bd659dd2eecad0666459b9788813e032b83e7ba58578e48254e0a0e6", + "sha256:bde2aef6f44302dfb30320115b17d030798de8c4110e28d5cf6cf91a7a31074c" + ], + "index": "pypi", + "version": "==0.9.4" + }, + "knack": { + "hashes": [ + "sha256:b1ac92669641b902e1aef97138666a21b8852f65d83cbde03eb9ddebf82ce121", + "sha256:bd240163d4e2ce9fc8535f77519358da0afd6c0ca19f001c639c3160b57630a9" + ], + "index": "pypi", + "version": "==0.6.3" + }, + "lazy-object-proxy": { + "hashes": [ + "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d", + "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449", + "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08", + "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a", + "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50", + "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd", + "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239", + "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb", + "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea", + "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e", + "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156", + "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142", + "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442", + "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62", + "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db", + "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531", + "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383", + "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a", + "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357", + "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4", + "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0" + ], + "index": "pypi", + "version": "==1.4.3" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "index": "pypi", + "version": "==0.6.1" + }, + "msal": { + "hashes": [ + "sha256:c944b833bf686dfbc973e9affdef94b77e616cb52ab397e76cde82e26b8a3373", + "sha256:ecbe3f5ac77facad16abf08eb9d8562af3bc7184be5d4d90c9ef4db5bde26340" + ], + "index": "pypi", + "version": "==1.0.0" + }, + "msal-extensions": { + "hashes": [ + "sha256:59e171a9a4baacdbf001c66915efeaef372fb424421f1a4397115a3ddd6205dc", + "sha256:c5a32b8e1dce1c67733dcdf8aa8bebcff5ab123e779ef7bc14e416bd0da90037" + ], + "index": "pypi", + "version": "==0.1.3" + }, + "msrest": { + "hashes": [ + "sha256:56b8b5b4556fb2a92cac640df267d560889bdc9e2921187772d4691d97bc4e8d", + "sha256:f5153bfe60ee757725816aedaa0772cbfe0bddb52cd2d6db4cb8b4c3c6c6f928" + ], + "index": "pypi", + "version": "==0.6.10" + }, + "msrestazure": { + "hashes": [ + "sha256:63db9f646fffc9244b332090e679d1e5f283ac491ee0cc321f5116f9450deb4a", + "sha256:fecb6a72a3eb5483e4deff38210d26ae42d3f6d488a7a275bd2423a1a014b22c" + ], + "index": "pypi", + "version": "==0.6.2" + }, + "oauthlib": { + "hashes": [ + "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889", + "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea" + ], + "index": "pypi", + "version": "==3.1.0" + }, + "paramiko": { + "hashes": [ + "sha256:920492895db8013f6cc0179293147f830b8c7b21fdfc839b6bad760c27459d9f", + "sha256:9c980875fa4d2cb751604664e9a2d0f69096643f5be4db1b99599fe114a97b2f" + ], + "index": "pypi", + "version": "==2.7.1" + }, + "portalocker": { + "hashes": [ + "sha256:6f57aabb25ba176462dc7c63b86c42ad6a9b5bd3d679a9d776d0536bfb803d54", + "sha256:dac62e53e5670cb40d2ee4cdc785e6b829665932c3ee75307ad677cf5f7d2e9f" + ], + "index": "pypi", + "version": "==1.5.2" + }, + "pycparser": { + "hashes": [ + "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" + ], + "index": "pypi", + "version": "==2.19" + }, + "pygments": { + "hashes": [ + "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b", + "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe" + ], + "index": "pypi", + "version": "==2.5.2" + }, + "pyjwt": { + "hashes": [ + "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e", + "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96" + ], + "index": "pypi", + "version": "==1.7.1" + }, + "pylint": { + "hashes": [ + "sha256:3db5468ad013380e987410a8d6956226963aed94ecb5f9d3a28acca6d9ac36cd", + "sha256:886e6afc935ea2590b462664b161ca9a5e40168ea99e5300935f6591ad467df4" + ], + "index": "pypi", + "version": "==2.4.4" + }, + "pynacl": { + "hashes": [ + "sha256:05c26f93964373fc0abe332676cb6735f0ecad27711035b9472751faa8521255", + "sha256:0c6100edd16fefd1557da078c7a31e7b7d7a52ce39fdca2bec29d4f7b6e7600c", + "sha256:0d0a8171a68edf51add1e73d2159c4bc19fc0718e79dec51166e940856c2f28e", + "sha256:1c780712b206317a746ace34c209b8c29dbfd841dfbc02aa27f2084dd3db77ae", + "sha256:2424c8b9f41aa65bbdbd7a64e73a7450ebb4aa9ddedc6a081e7afcc4c97f7621", + "sha256:2d23c04e8d709444220557ae48ed01f3f1086439f12dbf11976e849a4926db56", + "sha256:30f36a9c70450c7878053fa1344aca0145fd47d845270b43a7ee9192a051bf39", + "sha256:37aa336a317209f1bb099ad177fef0da45be36a2aa664507c5d72015f956c310", + "sha256:4943decfc5b905748f0756fdd99d4f9498d7064815c4cf3643820c9028b711d1", + "sha256:53126cd91356342dcae7e209f840212a58dcf1177ad52c1d938d428eebc9fee5", + "sha256:57ef38a65056e7800859e5ba9e6091053cd06e1038983016effaffe0efcd594a", + "sha256:5bd61e9b44c543016ce1f6aef48606280e45f892a928ca7068fba30021e9b786", + "sha256:6482d3017a0c0327a49dddc8bd1074cc730d45db2ccb09c3bac1f8f32d1eb61b", + "sha256:7d3ce02c0784b7cbcc771a2da6ea51f87e8716004512493a2b69016326301c3b", + "sha256:a14e499c0f5955dcc3991f785f3f8e2130ed504fa3a7f44009ff458ad6bdd17f", + "sha256:a39f54ccbcd2757d1d63b0ec00a00980c0b382c62865b61a505163943624ab20", + "sha256:aabb0c5232910a20eec8563503c153a8e78bbf5459490c49ab31f6adf3f3a415", + "sha256:bd4ecb473a96ad0f90c20acba4f0bf0df91a4e03a1f4dd6a4bdc9ca75aa3a715", + "sha256:bf459128feb543cfca16a95f8da31e2e65e4c5257d2f3dfa8c0c1031139c9c92", + "sha256:e2da3c13307eac601f3de04887624939aca8ee3c9488a0bb0eca4fb9401fc6b1", + "sha256:f67814c38162f4deb31f68d590771a29d5ae3b1bd64b75cf232308e5c74777e0" + ], + "index": "pypi", + "version": "==1.3.0" + }, + "pyopenssl": { + "hashes": [ + "sha256:621880965a720b8ece2f1b2f54ea2071966ab00e2970ad2ce11d596102063504", + "sha256:9a24494b2602aaf402be5c9e30a0b82d4a5c67528fe8fb475e3f3bc00dd69507" + ], + "index": "pypi", + "version": "==19.1.0" + }, + "python-dateutil": { + "hashes": [ + "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", + "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" + ], + "index": "pypi", + "version": "==2.8.1" + }, + "pyyaml": { + "hashes": [ + "sha256:0e7f69397d53155e55d10ff68fdfb2cf630a35e6daf65cf0bdeaf04f127c09dc", + "sha256:2e9f0b7c5914367b0916c3c104a024bb68f269a486b9d04a2e8ac6f6597b7803", + "sha256:35ace9b4147848cafac3db142795ee42deebe9d0dad885ce643928e88daebdcc", + "sha256:38a4f0d114101c58c0f3a88aeaa44d63efd588845c5a2df5290b73db8f246d15", + "sha256:483eb6a33b671408c8529106df3707270bfacb2447bf8ad856a4b4f57f6e3075", + "sha256:4b6be5edb9f6bb73680f5bf4ee08ff25416d1400fbd4535fe0069b2994da07cd", + "sha256:7f38e35c00e160db592091751d385cd7b3046d6d51f578b29943225178257b31", + "sha256:8100c896ecb361794d8bfdb9c11fce618c7cf83d624d73d5ab38aef3bc82d43f", + "sha256:c0ee8eca2c582d29c3c2ec6e2c4f703d1b7f1fb10bc72317355a746057e7346c", + "sha256:e4c015484ff0ff197564917b4b4246ca03f411b9bd7f16e02a2f586eb48b6d04", + "sha256:ebc4ed52dcc93eeebeae5cf5deb2ae4347b3a81c3fa12b0b8c976544829396a4" + ], + "index": "pypi", + "version": "==5.2" + }, + "requests": { + "hashes": [ + "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", + "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31" + ], + "index": "pypi", + "version": "==2.22.0" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d", + "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a", + "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc" + ], + "index": "pypi", + "version": "==1.3.0" + }, + "six": { + "hashes": [ + "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", + "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" + ], + "index": "pypi", + "version": "==1.13.0" + }, + "tabulate": { + "hashes": [ + "sha256:5470cc6687a091c7042cee89b2946d9235fe9f6d49c193a4ae2ac7bf386737c8" + ], + "index": "pypi", + "version": "==0.8.6" + }, + "typed-ast": { + "hashes": [ + "sha256:1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", + "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", + "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", + "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", + "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", + "sha256:48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", + "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", + "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", + "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", + "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", + "sha256:7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", + "sha256:838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", + "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", + "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", + "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", + "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", + "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", + "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", + "sha256:fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", + "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12" + ], + "index": "pypi", + "markers": "implementation_name == 'cpython' and python_version < '3.8'", + "version": "==1.4.0" + }, + "urllib3": { + "hashes": [ + "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293", + "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745" + ], + "index": "pypi", + "version": "==1.25.7" + }, + "wheel": { + "hashes": [ + "sha256:9515fe0a94e823fd90b08d22de45d7bde57c90edce705b22f5e1ecf7e1b653c8", + "sha256:e721e53864f084f956f40f96124a74da0631ac13fbbd1ba99e8e2b5e9cafdf64" + ], + "version": "==0.30.0" + }, + "wrapt": { + "hashes": [ + "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1" + ], + "index": "pypi", + "version": "==1.11.2" + } + }, + "develop": { + "attrs": { + "hashes": [ + "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", + "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72" + ], + "version": "==19.3.0" + }, + "importlib-metadata": { + "hashes": [ + "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359", + "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8" + ], + "markers": "python_version < '3.8'", + "version": "==1.4.0" + }, + "more-itertools": { + "hashes": [ + "sha256:1a2a32c72400d365000412fe08eb4a24ebee89997c18d3d147544f70f5403b39", + "sha256:c468adec578380b6281a114cb8a5db34eb1116277da92d7c46f904f0b52d3288" + ], + "version": "==8.1.0" + }, + "packaging": { + "hashes": [ + "sha256:aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb", + "sha256:fe1d8331dfa7cc0a883b49d75fc76380b2ab2734b220fbb87d774e4fd4b851f8" + ], + "version": "==20.0" + }, + "pluggy": { + "hashes": [ + "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", + "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + ], + "version": "==0.13.1" + }, + "py": { + "hashes": [ + "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa", + "sha256:c20fdd83a5dbc0af9efd622bee9a5564e278f6380fffcacc43ba6f43db2813b0" + ], + "version": "==1.8.1" + }, + "pyparsing": { + "hashes": [ + "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f", + "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec" + ], + "version": "==2.4.6" + }, + "pytest": { + "hashes": [ + "sha256:6b571215b5a790f9b41f19f3531c53a45cf6bb8ef2988bc1ff9afb38270b25fa", + "sha256:e41d489ff43948babd0fad7ad5e49b8735d5d55e26628a58673c39ff61d95de4" + ], + "index": "pypi", + "version": "==5.3.2" + }, + "six": { + "hashes": [ + "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd", + "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66" + ], + "index": "pypi", + "version": "==1.13.0" + }, + "wcwidth": { + "hashes": [ + "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603", + "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8" + ], + "version": "==0.1.8" + }, + "zipp": { + "hashes": [ + "sha256:8dda78f06bd1674bd8720df8a50bb47b6e1233c503a4eed8e7810686bde37656", + "sha256:d38fbe01bbf7a3593a32bc35a9c4453c32bc42b98c377f9bff7e9f8da157786c" + ], + "version": "==1.0.0" + } + } +} diff --git a/terraform/secrets-tool/commands/terraform.py b/terraform/secrets-tool/commands/terraform.py index 8fcdf55a..f1acff94 100644 --- a/terraform/secrets-tool/commands/terraform.py +++ b/terraform/secrets-tool/commands/terraform.py @@ -1,7 +1,5 @@ -import os import click import logging -import subprocess from utils.keyvault.secrets import SecretsClient from utils.terraform.wrapper import TFWrapper From 55623028df6e2c2ca3788a85afec65a6bff02927 Mon Sep 17 00:00:00 2001 From: Rob Gil Date: Thu, 16 Jan 2020 21:40:26 -0500 Subject: [PATCH 4/4] Adds a secrets generator and loader secrets-tool now has a feature to both generate secrets as well as load the generated secrets in to KeyVault. --- terraform/secrets-tool/README.md | 79 +++++++++++++++++ terraform/secrets-tool/commands/secrets.py | 14 ++- terraform/secrets-tool/sample-secrets.yaml | 7 ++ .../secrets-tool/utils/keyvault/secrets.py | 85 ++++++++++++++++++- 4 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 terraform/secrets-tool/README.md create mode 100644 terraform/secrets-tool/sample-secrets.yaml diff --git a/terraform/secrets-tool/README.md b/terraform/secrets-tool/README.md new file mode 100644 index 00000000..28b44817 --- /dev/null +++ b/terraform/secrets-tool/README.md @@ -0,0 +1,79 @@ +# secrets-tool +secrets-tool is a group of utilities used to manage secrets in Azure environments. + +*Features:* +- Generate secrets based on definitions defined in yaml +- Load secrets in to Azure KeyVault +- Wrapper for terraform to inject KeyVault secrets as environment variables + +# Use Cases +## Populating KeyVault with initial secrets +In many environments, a complete list of secrets is sometimes forgotten or not well defined. With secrets-tool, all those secrets can be defined programatically and generated when creating new environments. This avoids putting in "test" values for passwords and guessible username/password combinations. Even usernames can be generated. + +With both usernames and passwords generated, the application only needs to make a call out to KeyVault for the key that it needs (assuming the application, host, or vm has access to the secret) + +Ex. +``` +{ + 'postgres_root_user': 'EzTEzSNLKQPHuJyPdPloIDCAlcibbl', + 'postgres_root_password': "2+[A@E4:C=ubb/#R#'n' > ~/.bash_profile +. ~/.bash_profile +``` + +`$ which secrets-tool` should show the full path + +# Usage +## Defining secrets +The schema for defining secrets is very simplistic for the moment. +```yaml +--- +- postgres-root-user: + type: 'username' + length: 30 +- postgres-root-password: + type: 'password' + length: 30 +``` +In this example we're randomly generating both the username and password. `secrets-tool` is smart enough to know that a username can't have symbols in it. Passwords contain symbols, upper/lower case, and numbers. This could be made more flexible and configurable in the future. + + +## Populating secrets from secrets definition file +This process is as simple as specifying the keyvault and the definitions file. +``` +secrets-tool secrets --keyvault https://operator-dev-keyvault.vault.azure.net/ load -f ./sample-secrets.yaml +``` + +## Running terraform with KeyVault secrets +This will fetch all secrets from the keyvault specified. `secrets-tool` then converts the keys to a variable name that terraform will look for. Essentially it prepends the keys found in KeyVault with `TF_VAR` and then executes terraform as a subprocess with the injected environment variables. +``` +secrets-tool terraform --keyvault https://operator-dev-keyvault.vault.azure.net/ plan +``` \ No newline at end of file diff --git a/terraform/secrets-tool/commands/secrets.py b/terraform/secrets-tool/commands/secrets.py index 7dbd16e7..bf9d7ff6 100644 --- a/terraform/secrets-tool/commands/secrets.py +++ b/terraform/secrets-tool/commands/secrets.py @@ -1,6 +1,7 @@ import click import logging from utils.keyvault.secrets import SecretsClient +from utils.keyvault.secrets import SecretsLoader logger = logging.getLogger(__name__) @@ -30,6 +31,17 @@ def list_secrets(ctx): keyvault = SecretsClient(vault_url=ctx.obj['keyvault']) click.echo(keyvault.list_secrets()) +@click.command('load') +@click.option('-f', 'file', required=True, help="YAML file with secrets definitions") +@click.pass_context +def load_secrets(ctx, file): + """Generate and load secrets from yaml definition""" + keyvault = SecretsClient(vault_url=ctx.obj['keyvault']) + loader = SecretsLoader(yaml_file=file, keyvault=keyvault) + loader.load_secrets() + + secrets.add_command(create_secret) -secrets.add_command(list_secrets) \ No newline at end of file +secrets.add_command(list_secrets) +secrets.add_command(load_secrets) \ No newline at end of file diff --git a/terraform/secrets-tool/sample-secrets.yaml b/terraform/secrets-tool/sample-secrets.yaml new file mode 100644 index 00000000..fb5f3ace --- /dev/null +++ b/terraform/secrets-tool/sample-secrets.yaml @@ -0,0 +1,7 @@ +--- +- postgres-root-user: + type: 'username' + length: 30 +- postgres-root-password: + type: 'password' + length: 30 diff --git a/terraform/secrets-tool/utils/keyvault/secrets.py b/terraform/secrets-tool/utils/keyvault/secrets.py index 1c554146..af8b5201 100644 --- a/terraform/secrets-tool/utils/keyvault/secrets.py +++ b/terraform/secrets-tool/utils/keyvault/secrets.py @@ -1,4 +1,8 @@ import logging +import yaml +import secrets +import string +from pathlib import Path from .auth import Auth from azure.keyvault.secrets import SecretClient @@ -23,4 +27,83 @@ class SecretsClient(Auth): secret_properties = self.secret_client.list_properties_of_secrets() for secret in secret_properties: secrets.append(secret.name) - return secrets \ No newline at end of file + return secrets + +class SecretsLoader(): + """ + Helper class to load secrets definition, generate + the secrets a defined by the defintion, and then + load the secrets in to keyvault + """ + def __init__(self, yaml_file: str, keyvault: object): + assert Path(yaml_file).exists() + self.yaml_file = yaml_file + self.keyvault = keyvault + self.config = dict() + + self._load_yaml() + self._generate_secrets() + + def _load_yaml(self): + with open(self.yaml_file) as handle: + self.config = yaml.load(handle, Loader=yaml.FullLoader) + + def _generate_secrets(self): + secrets = GenerateSecrets(self.config).process_definition() + self.secrets = secrets + + def load_secrets(self): + for key, val in self.secrets.items(): + print('{} {}'.format(key,val)) + self.keyvault.set_secret(key=key, value=val) + + +class GenerateSecrets(): + """ + Read the secrets definition and generate requiesite + secrets based on the type of secret and arguments + provided + """ + def __init__(self, definitions: dict): + self.definitions = definitions + + def process_definition(self): + """ + Processes a simple definiton such as the following + ``` + - postgres_root_user: + type: 'username' + length: 30 + - postgres_root_password: + type: 'password' + length: 30 + ``` + This should be broken out to a function per definition type + if the scope extends in to tokens, salts, or other specialized + definitions. + """ + try: + secrets = dict() + for definition in self.definitions: + key = list(definition) + def_name = key[0] + secret = definition[key[0]] + assert len(str(secret['length'])) > 0 + method = getattr(self, '_generate_'+secret['type']) + value = method(secret['length']) + #print('{}: {}'.format(key[0], value)) + secrets.update({def_name: value}) + logger.debug('Setting secrets to: {}'.format(secrets)) + return secrets + except KeyError as e: + logger.error('Missing the {} key in the definition'.format(e)) + + # Types. Can be usernames, passwords, or in the future things like salted + # tokens, uuid, or other specialized types + def _generate_password(self, length: int): + self.password_characters = string.ascii_letters + string.digits + string.punctuation + return ''.join(secrets.choice(self.password_characters) for i in range(length)) + + def _generate_username(self, length: int): + self.username_characters = string.ascii_letters + return ''.join(secrets.choice(self.username_characters) for i in range(length))