separate mfa from key-only aws
This commit is contained in:
parent
8c44ae5302
commit
9d9aee79d3
7 changed files with 95 additions and 74 deletions
2
build.py
2
build.py
|
@ -27,7 +27,7 @@ use_plugin("python.distutils")
|
||||||
default_task = "publish"
|
default_task = "publish"
|
||||||
|
|
||||||
name = "ddadevops"
|
name = "ddadevops"
|
||||||
version = "0.4.1.dev0"
|
version = "0.4.1.dev1"
|
||||||
summary = "tools to support builds combining gopass, terraform, dda-pallet, aws & hetzner-cloud"
|
summary = "tools to support builds combining gopass, terraform, dda-pallet, aws & hetzner-cloud"
|
||||||
description = __doc__
|
description = __doc__
|
||||||
authors = [Author("meissa GmbH", "buero@meissa-gmbh.de")]
|
authors = [Author("meissa GmbH", "buero@meissa-gmbh.de")]
|
||||||
|
|
|
@ -9,6 +9,7 @@ from .devops_build import DevopsBuild, create_devops_build_config
|
||||||
from .devops_terraform_build import DevopsTerraformBuild, create_devops_terraform_build_config
|
from .devops_terraform_build import DevopsTerraformBuild, create_devops_terraform_build_config
|
||||||
from .hetzner_mixin import HetznerMixin, add_hetzner_mixin_config
|
from .hetzner_mixin import HetznerMixin, add_hetzner_mixin_config
|
||||||
from .aws_mixin import AwsMixin, add_aws_mixin_config
|
from .aws_mixin import AwsMixin, add_aws_mixin_config
|
||||||
|
from .aws_mfa_mixin import AwsMfaMixin, add_aws_mfa_mixin_config
|
||||||
from .dda_pallet_mixin import DdaPalletMixin, add_dda_pallet_mixin_config
|
from .dda_pallet_mixin import DdaPalletMixin, add_dda_pallet_mixin_config
|
||||||
|
|
||||||
__version__ = "${version}"
|
__version__ = "${version}"
|
82
src/main/python/ddadevops/aws_mfa_mixin.py
Normal file
82
src/main/python/ddadevops/aws_mfa_mixin.py
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
from python_terraform import *
|
||||||
|
from boto3 import *
|
||||||
|
from .credential import gopass_credential_from_env_path
|
||||||
|
from .python_util import execute
|
||||||
|
from .aws_mixin import AwsMixin
|
||||||
|
|
||||||
|
|
||||||
|
def add_aws_mfa_mixin_config(config, account_id, region,
|
||||||
|
mfa_role='developer', mfa_account_prefix='', mfa_login_account_suffix='main'):
|
||||||
|
config.update({'AwsMfaMixin':
|
||||||
|
{'account_id': account_id,
|
||||||
|
'region': region,
|
||||||
|
'mfa_role': mfa_role,
|
||||||
|
'mfa_account_prefix': mfa_account_prefix,
|
||||||
|
'mfa_login_account_suffix': mfa_login_account_suffix}})
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
class AwsMfaMixin(AwsMixin):
|
||||||
|
|
||||||
|
def __init__(self, project, config):
|
||||||
|
super().__init__(project, config)
|
||||||
|
project.build_depends_on('boto3')
|
||||||
|
project.build_depends_on('mfa')
|
||||||
|
aws_mfa_mixin_config = config['AwsMfaMixin']
|
||||||
|
self.account_id = aws_mfa_mixin_config['account_id']
|
||||||
|
self.region = aws_mfa_mixin_config['region']
|
||||||
|
self.mfa_role = aws_mfa_mixin_config['mfa_role']
|
||||||
|
self.mfa_account_prefix = aws_mfa_mixin_config['mfa_account_prefix']
|
||||||
|
self.mfa_login_account_suffix = aws_mfa_mixin_config['mfa_login_account_suffix']
|
||||||
|
|
||||||
|
def project_vars(self):
|
||||||
|
ret = super().project_vars()
|
||||||
|
ret.update({'account_name': self.account_name,
|
||||||
|
'account_id': self.account_id,
|
||||||
|
'region': self.region,
|
||||||
|
'mfa_role': self.mfa_role,
|
||||||
|
'mfa_account_prefix': self.mfa_account_prefix,
|
||||||
|
'mfa_login_account_suffix': self.mfa_login_account_suffix})
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def get_username_from_account(self, p_account_name):
|
||||||
|
login_id = execute('cat ~/.aws/accounts | grep -A 2 "\[' + p_account_name +
|
||||||
|
'\]" | grep username | awk -F= \'{print $2}\'', shell=True)
|
||||||
|
return login_id
|
||||||
|
|
||||||
|
def get_account_id_from_account(self, p_account_name):
|
||||||
|
account_id = execute('cat ~/.aws/accounts | grep -A 2 "\[' + p_account_name +
|
||||||
|
'\]" | grep account | awk -F= \'{print $2}\'', shell=True)
|
||||||
|
return account_id
|
||||||
|
|
||||||
|
def get_mfa(self, mfa_path='aws'):
|
||||||
|
mfa_token = execute('mfa otp ' + mfa_path, shell=True)
|
||||||
|
return mfa_token
|
||||||
|
|
||||||
|
def write_aws_config(self, to_profile, key, secret):
|
||||||
|
execute('aws configure --profile ' + to_profile +
|
||||||
|
' set ' + key + ' ' + secret, shell=True)
|
||||||
|
|
||||||
|
def get_mfa_session(self, toke=None):
|
||||||
|
from_account_name = self.mfa_account_prefix + self.mfa_login_account_suffix
|
||||||
|
from_account_id = self.get_account_id_from_account(from_account_name)
|
||||||
|
to_account_name = self.mfa_account_prefix + self.account_name
|
||||||
|
to_account_id = self.get_account_id_from_account(to_account_name)
|
||||||
|
login_id = self.get_username_from_account(from_account_name)
|
||||||
|
mfa_token = self.get_mfa()
|
||||||
|
ses = Session(profile_name=from_account_name)
|
||||||
|
sts_client = ses.client('sts')
|
||||||
|
response = sts_client.assume_role(
|
||||||
|
RoleArn='arn:aws:iam::' + to_account_id + ':role/' + self.mfa_role,
|
||||||
|
RoleSessionName=to_account_id + '-' + self.account_name + '-' + self.mfa_role,
|
||||||
|
SerialNumber='arn:aws:iam::' + from_account_id + ':mfa/' + login_id,
|
||||||
|
TokenCode=mfa_token
|
||||||
|
)
|
||||||
|
|
||||||
|
self.write_aws_config(to_account_name, 'aws_access_key_id',
|
||||||
|
response['Credentials']['AccessKeyId'])
|
||||||
|
self.write_aws_config(to_account_name, 'aws_secret_access_key',
|
||||||
|
response['Credentials']['SecretAccessKey'])
|
||||||
|
self.write_aws_config(to_account_name, 'aws_session_token',
|
||||||
|
response['Credentials']['SessionToken'])
|
||||||
|
print('got token')
|
|
@ -1,19 +1,10 @@
|
||||||
from python_terraform import *
|
from python_terraform import *
|
||||||
from boto3 import *
|
|
||||||
from .credential import gopass_credential_from_env_path
|
|
||||||
from .python_util import execute
|
|
||||||
from .devops_terraform_build import DevopsTerraformBuild
|
from .devops_terraform_build import DevopsTerraformBuild
|
||||||
|
|
||||||
|
|
||||||
def add_aws_mixin_config(config, account_name, account_id, region,
|
def add_aws_mixin_config(config, account_name):
|
||||||
mfa_role='developer', mfa_account_prefix='', mfa_login_account_suffix='main'):
|
|
||||||
config.update({'AwsMixin':
|
config.update({'AwsMixin':
|
||||||
{'account_name': account_name,
|
{'account_name': account_name}})
|
||||||
'account_id': account_id,
|
|
||||||
'region': region,
|
|
||||||
'mfa_role': mfa_role,
|
|
||||||
'mfa_account_prefix': mfa_account_prefix,
|
|
||||||
'mfa_login_account_suffix': mfa_login_account_suffix}})
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,27 +12,15 @@ class AwsMixin(DevopsTerraformBuild):
|
||||||
|
|
||||||
def __init__(self, project, config):
|
def __init__(self, project, config):
|
||||||
super().__init__(project, config)
|
super().__init__(project, config)
|
||||||
project.build_depends_on('boto3')
|
|
||||||
project.build_depends_on('mfa')
|
|
||||||
aws_mixin_config = config['AwsMixin']
|
aws_mixin_config = config['AwsMixin']
|
||||||
self.account_name = aws_mixin_config['account_name']
|
self.account_name = aws_mixin_config['account_name']
|
||||||
self.account_id = aws_mixin_config['account_id']
|
|
||||||
self.region = aws_mixin_config['region']
|
|
||||||
self.mfa_role = aws_mixin_config['mfa_role']
|
|
||||||
self.mfa_account_prefix = aws_mixin_config['mfa_account_prefix']
|
|
||||||
self.mfa_login_account_suffix = aws_mixin_config['mfa_login_account_suffix']
|
|
||||||
|
|
||||||
def backend_config(self):
|
def backend_config(self):
|
||||||
return "backend." + self.account_name + "." + self.stage + ".properties"
|
return "backend." + self.account_name + "." + self.stage + ".properties"
|
||||||
|
|
||||||
def project_vars(self):
|
def project_vars(self):
|
||||||
ret = super().project_vars()
|
ret = super().project_vars()
|
||||||
ret.update({'account_name': self.account_name,
|
ret.update({'account_name': self.account_name})
|
||||||
'account_id': self.account_id,
|
|
||||||
'region': self.region,
|
|
||||||
'mfa_role': self.mfa_role,
|
|
||||||
'mfa_account_prefix': self.mfa_account_prefix,
|
|
||||||
'mfa_login_account_suffix': self.mfa_login_account_suffix})
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def init_client(self):
|
def init_client(self):
|
||||||
|
@ -69,45 +48,3 @@ class AwsMixin(DevopsTerraformBuild):
|
||||||
tf = self.init_client()
|
tf = self.init_client()
|
||||||
tf.destroy(capture_output=False, auto_approve=p_auto_approve,
|
tf.destroy(capture_output=False, auto_approve=p_auto_approve,
|
||||||
var=self.project_vars(), var_file=self.backend_config())
|
var=self.project_vars(), var_file=self.backend_config())
|
||||||
|
|
||||||
def get_username_from_account(self, p_account_name):
|
|
||||||
login_id = execute('cat ~/.aws/accounts | grep -A 2 "\[' + p_account_name +
|
|
||||||
'\]" | grep username | awk -F= \'{print $2}\'', shell=True)
|
|
||||||
return login_id
|
|
||||||
|
|
||||||
def get_account_id_from_account(self, p_account_name):
|
|
||||||
account_id = execute('cat ~/.aws/accounts | grep -A 2 "\[' + p_account_name +
|
|
||||||
'\]" | grep account | awk -F= \'{print $2}\'', shell=True)
|
|
||||||
return account_id
|
|
||||||
|
|
||||||
def get_mfa(self, mfa_path='aws'):
|
|
||||||
mfa_token = execute('mfa otp ' + mfa_path, shell=True)
|
|
||||||
return mfa_token
|
|
||||||
|
|
||||||
def write_aws_config(self, to_profile, key, secret):
|
|
||||||
execute('aws configure --profile ' + to_profile +
|
|
||||||
' set ' + key + ' ' + secret, shell=True)
|
|
||||||
|
|
||||||
def get_mfa_session(self, toke=None):
|
|
||||||
from_account_name = self.mfa_account_prefix + self.mfa_login_account_suffix
|
|
||||||
from_account_id = self.get_account_id_from_account(from_account_name)
|
|
||||||
to_account_name = self.mfa_account_prefix + self.account_name
|
|
||||||
to_account_id = self.get_account_id_from_account(to_account_name)
|
|
||||||
login_id = self.get_username_from_account(from_account_name)
|
|
||||||
mfa_token = self.get_mfa()
|
|
||||||
ses = Session(profile_name=from_account_name)
|
|
||||||
sts_client = ses.client('sts')
|
|
||||||
response = sts_client.assume_role(
|
|
||||||
RoleArn='arn:aws:iam::' + to_account_id + ':role/' + self.mfa_role,
|
|
||||||
RoleSessionName=to_account_id + '-' + self.account_name + '-' + self.mfa_role,
|
|
||||||
SerialNumber='arn:aws:iam::' + from_account_id + ':mfa/' + login_id,
|
|
||||||
TokenCode=mfa_token
|
|
||||||
)
|
|
||||||
|
|
||||||
self.write_aws_config(to_account_name, 'aws_access_key_id',
|
|
||||||
response['Credentials']['AccessKeyId'])
|
|
||||||
self.write_aws_config(to_account_name, 'aws_secret_access_key',
|
|
||||||
response['Credentials']['SecretAccessKey'])
|
|
||||||
self.write_aws_config(to_account_name, 'aws_session_token',
|
|
||||||
response['Credentials']['SessionToken'])
|
|
||||||
print('got token')
|
|
||||||
|
|
|
@ -2,13 +2,15 @@ from subprocess import run
|
||||||
from .python_util import filter_none
|
from .python_util import filter_none
|
||||||
|
|
||||||
|
|
||||||
def create_devops_build_config(stage, project_root_path, build_commons_path, module, build_dir_name='target'):
|
def create_devops_build_config(stage, project_root_path, build_commons_path, module,
|
||||||
|
build_dir_name='target'):
|
||||||
return {'stage': stage,
|
return {'stage': stage,
|
||||||
'project_root_path': project_root_path,
|
'project_root_path': project_root_path,
|
||||||
'build_commons_path': build_commons_path,
|
'build_commons_path': build_commons_path,
|
||||||
'module': module,
|
'module': module,
|
||||||
'build_dir_name': build_dir_name}
|
'build_dir_name': build_dir_name}
|
||||||
|
|
||||||
|
|
||||||
class DevopsBuild:
|
class DevopsBuild:
|
||||||
|
|
||||||
def __init__(self, project, config):
|
def __init__(self, project, config):
|
||||||
|
|
|
@ -7,15 +7,14 @@ from .devops_build import DevopsBuild, create_devops_build_config
|
||||||
|
|
||||||
|
|
||||||
def create_devops_terraform_build_config(stage, project_root_path, build_commons_path, module,
|
def create_devops_terraform_build_config(stage, project_root_path, build_commons_path, module,
|
||||||
account_name, additional_vars,
|
additional_vars,
|
||||||
build_dir_name='target',
|
build_dir_name='target',
|
||||||
terraform_build_commons_dir_name='terraform',
|
terraform_build_commons_dir_name='terraform',
|
||||||
output_json_name='output.json',
|
output_json_name='output.json',
|
||||||
use_workspace=True):
|
use_workspace=True):
|
||||||
ret = create_devops_build_config(
|
ret = create_devops_build_config(
|
||||||
stage, project_root_path, build_commons_path, module, build_dir_name)
|
stage, project_root_path, build_commons_path, module, build_dir_name)
|
||||||
ret.update({'account_name': account_name,
|
ret.update({'additional_vars': additional_vars,
|
||||||
'additional_vars': additional_vars,
|
|
||||||
'terraform_build_commons_dir_name': terraform_build_commons_dir_name,
|
'terraform_build_commons_dir_name': terraform_build_commons_dir_name,
|
||||||
'output_json_name': output_json_name,
|
'output_json_name': output_json_name,
|
||||||
'use_workspace': use_workspace})
|
'use_workspace': use_workspace})
|
||||||
|
|
|
@ -2,9 +2,9 @@ from .credential import gopass_credential_from_env_path
|
||||||
from .devops_terraform_build import DevopsTerraformBuild
|
from .devops_terraform_build import DevopsTerraformBuild
|
||||||
|
|
||||||
|
|
||||||
def add_hetzner_mixin_config(config):
|
def add_hetzner_mixin_config(config, hetzner_api_key_path_env='HETZNER_API_KEY_PATH'):
|
||||||
config.update({'HetznerMixin':
|
config.update({'HetznerMixin':
|
||||||
{'HETZNER_API_KEY_PATH_ENVIRONMENT': 'HETZNER_API_KEY_PATH'}})
|
{'HETZNER_API_KEY_PATH_ENVIRONMENT': hetzner_api_key_path_env}})
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue