Ejemplo n.º 1
0
 def _create_launch_avm_state_machine_input_map(self, portfolio, product,
                                                accounts):
     input_params = {}
     input_params.update({'PortfolioName': sanitize(portfolio, True)})
     input_params.update({'ProductName': sanitize(product, True)})
     input_params.update({'ProvisioningParametersList': accounts})
     return self._create_state_machine_input_map(input_params)
    def trigger_state_machine(self):
        try:
            self.logger.info("Executing: " + self.__class__.__name__ + "/" +
                             inspect.stack()[0][3])
            sm = StateMachine(self.logger)
            account_id = self.event.get('account')
            resource_type = 'stno-console' if self.event.get('detail', {}).get('resource-type') is None \
                else account_id + '-' + self.event.get('detail', {}).get('resource-type') + '-tagged'
            state_machine_arn = environ.get('STATE_MACHINE_ARN')

            # Execute State Machine

            exec_name = "%s-%s-%s" % ('event-from', resource_type,
                                      time.strftime("%Y-%m-%dT%H-%M-%S-%s"))
            self.event.update({'StateMachineArn': state_machine_arn})

            self.logger.info("Triggering {} State Machine".format(
                state_machine_arn.split(":", 6)[6]))
            response = sm.trigger_state_machine(state_machine_arn, self.event,
                                                sanitize(exec_name))
            self.logger.info(
                "State machine triggered successfully, Execution Arn: {}".
                format(response))
        except Exception as e:
            message = {
                'FILE': __file__.split('/')[-1],
                'CLASS': self.__class__.__name__,
                'METHOD': inspect.stack()[0][3],
                'EXCEPTION': str(e)
            }
            self.logger.exception(message)
            raise
Ejemplo n.º 3
0
    def _create_stack_set_state_machine_input_map(
            self,
            stack_set_name,
            template_url,
            parameters,
            account_list=[],
            regions_list=[],
            ssm_map=None,
            capabilities='CAPABILITY_NAMED_IAM'):
        input_params = {}
        input_params.update({'StackSetName': sanitize(stack_set_name)})
        input_params.update({'TemplateURL': template_url})
        input_params.update({'Parameters': parameters})
        input_params.update({'Capabilities': capabilities})

        if len(account_list) > 0:
            input_params.update({'AccountList': account_list})
            if len(regions_list) > 0:
                input_params.update({'RegionList': regions_list})
            else:
                input_params.update({'RegionList': [self.manifest.region]})
        else:
            input_params.update({'AccountList': ''})
            input_params.update({'RegionList': ''})

        if ssm_map is not None:
            input_params.update({'SSMParameters': ssm_map})

        return self._create_state_machine_input_map(input_params)
Ejemplo n.º 4
0
    def trigger_state_machine(self):
        try:
            self.logger.info("Executing: " + self.__class__.__name__ + "/" + inspect.stack()[0][3])
            sm = StateMachine(self.logger)
            resource_type = self.event.get('ResourceType')
            request_type = self.event.get('RequestType')

            if resource_type == 'Custom::Organizations' and environ.get('sm_arn_account'):
                state_machine_arn = environ.get('sm_arn_account')
            elif resource_type == 'Custom::ServiceControlPolicy' and environ.get('sm_arn_service_control_policy'):
                state_machine_arn = environ.get('sm_arn_service_control_policy')
            elif resource_type == 'Custom::StackInstance' and environ.get('sm_arn_stack_set'):
                state_machine_arn = environ.get('sm_arn_stack_set')
            elif resource_type == 'Custom::CheckAVMExistsForAccount' and environ.get('sm_arn_check_avm_exists'):
                state_machine_arn = environ.get('sm_arn_check_avm_exists')
            elif resource_type == 'Custom::ADConnector' and environ.get('sm_arn_ad_connector'):
                state_machine_arn = environ.get('sm_arn_ad_connector')
            elif resource_type == 'Custom::HandShakeStateMachine' and environ.get('sm_arn_handshake_sm'):
                state_machine_arn = environ.get('sm_arn_handshake_sm')
            else:
                self.logger.error("ResourceType Not Supported {} or Env. Variable not found".format(resource_type))
                raise Exception("ResourceType Not Supported {} or Env. Variable not found".format(resource_type))

            # Execute State Machine
            if resource_type == 'Custom::StackInstance':
                exec_name = "%s-%s-%s-%s" % ('AVM-CR', request_type,
                                             trim_length(self.event.get('ResourceProperties', {}).get('StackSetName'), 45),
                                             time.strftime("%Y-%m-%dT%H-%M-%S"))
            elif resource_type == 'Custom::Organizations':
                exec_name = "%s-%s-%s-%s" % ('AVM-CR', request_type,
                                             trim_length(self.event.get('ResourceProperties', {}).get('OUName') + '-' +
                                                         self.event.get('ResourceProperties', {}).get('AccountName'), 45),
                                             time.strftime("%Y-%m-%dT%H-%M-%S"))
            elif resource_type == 'Custom::ServiceControlPolicy':
                exec_name = "%s-%s-%s-%s" % ('AVM-CR', request_type,
                                             trim_length(self.event.get('ResourceProperties', {}).get('Operation'), 45),
                                             time.strftime("%Y-%m-%dT%H-%M-%S"))
            elif resource_type == 'Custom::HandShakeStateMachine':
                exec_name = "%s-%s-%s-%s" % ('AVM-CR', request_type,
                                             trim_length(self.event.get('ResourceProperties', {}).get('ServiceType') +
                                                         '-' + self.event.get('ResourceProperties', {}).get('SpokeRegion')
                                                         + '-' + self.event.get('ResourceProperties', {}).get('SpokeAccountId'), 45),
                                             time.strftime("%Y-%m-%dT%H-%M-%S"))
            elif resource_type == 'Custom::CheckAVMExistsForAccount':
                exec_name = "%s-%s-%s-%s" % ('AVM-CR', request_type,
                                             trim_length(self.event.get('ResourceProperties', {}).get('ProdParams', {}).get('OUName') + '-' +
                                             self.event.get('ResourceProperties', {}).get('ProdParams', {}).get('AccountName'), 45),
                                             time.strftime("%Y-%m-%dT%H-%M-%S"))
            else:
                exec_name = "%s-%s-%s-%s" % ('AVM-CR', request_type, resource_type.replace("Custom::", ""),
                                             time.strftime("%Y-%m-%dT%H-%M-%S-%s"))
            self.event.update({'StateMachineArn': state_machine_arn})
            self.logger.info("Triggering {} State Machine".format(state_machine_arn.split(":", 6)[6]))
            response = sm.trigger_state_machine(state_machine_arn, self.event, sanitize(exec_name))
            self.logger.info("State machine triggered successfully, Execution Arn: {}".format(response))
        except Exception as e:
            message = {'FILE': __file__.split('/')[-1], 'CLASS': self.__class__.__name__,
                       'METHOD': inspect.stack()[0][3], 'EXCEPTION': str(e)}
            self.logger.exception(message)
            raise
Ejemplo n.º 5
0
    def create_key_pair(self,
                        account,
                        region,
                        param_key_material=None,
                        param_key_fingerprint=None,
                        param_key_name=None):

        if param_key_name:
            self.logger.info(
                "Looking up values in SSM parameter:{}".format(param_key_name))
            existing_param = self.ssm.describe_parameters(param_key_name)

            if existing_param:
                return self.ssm.get_parameter(param_key_name)

        key_name = sanitize(
            "%s_%s_%s_%s" %
            ('lz', account, region, time.strftime("%Y-%m-%dT%H-%M-%S")))

        try:
            ec2 = self._session(region, account)
            # create EC2 key pair in member account
            self.logger.info(
                "Create key pair in the member account {} in region: {}".
                format(account, region))
            response = ec2.create_key_pair(key_name)

            # add key material and fingerprint in the SSM Parameter Store
            self.logger.info("Adding Key Material and Fingerprint to SSM PS")
            description = "Contains EC2 key pair asset created by Landing Zone Solution: " \
                          "EC2 Key Pair Custom Resource."
            # Get Landing Zone KMS Key ID
            key_id = self._get_kms_key_id()
            if param_key_fingerprint:
                self.ssm.put_parameter_use_cmk(param_key_fingerprint,
                                               response.get('KeyFingerprint'),
                                               key_id, description)
            if param_key_material:
                self.ssm.put_parameter_use_cmk(param_key_material,
                                               response.get('KeyMaterial'),
                                               key_id, description)
            if param_key_name:
                self.ssm.put_parameter(param_key_name, key_name, description)

            return key_name
        except Exception as e:
            message = {
                'FILE': __file__.split('/')[-1],
                'CLASS': self.__class__.__name__,
                'METHOD': inspect.stack()[0][3],
                'EXCEPTION': str(e)
            }
            self.logger.exception(message)
            raise
Ejemplo n.º 6
0
 def _create_service_control_policy_state_machine_input_map(
         self, policy_name, policy_content, policy_desc=''):
     input_params = {}
     policy_doc = {}
     policy_doc.update({'Name': sanitize(policy_name)})
     policy_doc.update({'Description': policy_desc})
     policy_doc.update({'Content': policy_content})
     input_params.update({'PolicyDocument': policy_doc})
     input_params.update({'AccountId': ''})
     input_params.update({'PolicyList': []})
     input_params.update({'Operation': ''})
     return self._create_state_machine_input_map(input_params)
Ejemplo n.º 7
0
 def _create_service_control_policy_state_machine_input_map(self, policy_name, policy_full_path, policy_desc='', ou_list=[]):
     input_params = {}
     policy_doc = {}
     policy_doc.update({'Name': sanitize(policy_name)})
     policy_doc.update({'Description': policy_desc})
     policy_doc.update({'PolicyURL': policy_full_path})
     input_params.update({'PolicyDocument': policy_doc})
     input_params.update({'AccountId': ''})
     input_params.update({'PolicyList': []})
     input_params.update({'Operation': ''})
     input_params.update({'OUList': ou_list})
     input_params.update({'OUNameDelimiter': self.nested_ou_delimiter})
     return self._create_state_machine_input_map(input_params)
Ejemplo n.º 8
0
 def trigger_state_machine(self, state_machine_arn, input, name):
     try:
         self.logger.info("Starting execution of state machine: {} with input: {}".format(state_machine_arn, input))
         response = self.state_machine_client.start_execution(
             stateMachineArn=state_machine_arn,
             input=json.dumps(input),
             name=sanitize(name)
         )
         self.logger.info("State machine Execution ARN: {}".format(response['executionArn']))
         return response.get('executionArn')
     except Exception as e:
         message = {'FILE': __file__.split('/')[-1], 'METHOD': inspect.stack()[0][3], 'EXCEPTION': str(e)}
         self.logger.exception(message)
         raise
Ejemplo n.º 9
0
    def _process_accounts_in_batches(self, accounts, organizations, ou_id, ou_name):
        try:
            list_of_accounts = []
            for account in accounts:
                if account.get('Status').upper() == 'SUSPENDED':
                    organizations.move_account(account.get('Id'), ou_id, self.root_id)
                    continue
                else:
                    params = self.avm_params.copy()
                    for key, value in params.items():
                        if value.lower() == 'accountemail':
                            params.update({key: account.get('Email')})
                        elif value.lower() == 'accountname':
                            params.update({key: account.get('Name')})
                        elif value.lower() == 'orgunitname':
                            params.update({key: ou_name})

                    self.logger.info(
                        "Input parameters format for Account: {} are {}".format(account.get('Name'), params))

                    list_of_accounts.append(params)

            if len(list_of_accounts) > 0:
                sm_input = self._create_launch_avm_state_machine_input_map(self.avm_portfolio_name,
                                                                           self.avm_product_name.strip(),
                                                                           list_of_accounts)
                self.logger.info("Launch AVM state machine Input: {}".format(sm_input))
                exec_name = "%s-%s-%s-%s" % (sm_input.get('RequestType'), sanitize(ou_name), "Launch-AVM",
                                             time.strftime("%Y-%m-%dT%H-%M-%S"))
                sm_exec_arn = self.state_machine.trigger_state_machine(self.sm_arn_launch_avm, sm_input, exec_name)
                self.list_sm_exec_arns.append(sm_exec_arn)

                time.sleep(int(wait_time))  # Sleeping for sometime
        except Exception as e:
            message = {'FILE': __file__.split('/')[-1], 'METHOD': inspect.stack()[0][3], 'EXCEPTION': str(e)}
            self.logger.exception(message)
            raise
Ejemplo n.º 10
0
    def _create_service_catalog_state_machine_input_map(
            self, portfolio, product):
        input_params = {}

        sc_portfolio = {}
        sc_portfolio.update({'PortfolioName': sanitize(portfolio.name, True)})
        sc_portfolio.update(
            {'PortfolioDescription': sanitize(portfolio.description, True)})
        sc_portfolio.update(
            {'PortfolioProvider': sanitize(portfolio.owner, True)})
        ssm_value = self.param_handler.update_params(
            transform_params({'principal_role': portfolio.principal_role}))
        sc_portfolio.update({'PrincipalArn': ssm_value.get('principal_role')})

        sc_product = {}
        sc_product.update({'ProductName': sanitize(product.name, True)})
        sc_product.update({'ProductDescription': product.description})
        sc_product.update({'ProductOwner': sanitize(portfolio.owner, True)})
        if product.hide_old_versions is True:
            sc_product.update({'HideOldVersions': 'Yes'})
        else:
            sc_product.update({'HideOldVersions': 'No'})
        ssm_value = self.param_handler.update_params(
            transform_params(
                {'launch_constraint_role': product.launch_constraint_role}))
        sc_product.update({'RoleArn': ssm_value.get('launch_constraint_role')})

        ec2 = EC2(self.logger, environ.get('AWS_REGION'))
        region_list = []
        for region in ec2.describe_regions():
            region_list.append(region.get('RegionName'))

        if os.path.isfile(
                os.path.join(self.manifest_folder, product.skeleton_file)):
            lambda_arn_param = get_env_var('lambda_arn_param_name')
            lambda_arn = self.ssm.get_parameter(lambda_arn_param)
            portfolio_index = self.manifest.portfolios.index(portfolio)
            product_index = self.manifest.portfolios[
                portfolio_index].products.index(product)
            product_name = self.manifest.portfolios[portfolio_index].products[
                product_index].name
            logger.info(
                "Generating the product template for {} from {}".format(
                    product_name,
                    os.path.join(self.manifest_folder, product.skeleton_file)))
            j2loader = jinja2.FileSystemLoader(self.manifest_folder)
            j2env = jinja2.Environment(loader=j2loader)
            j2template = j2env.get_template(product.skeleton_file)
            template_url = None
            if product.product_type.lower() == 'baseline':
                # j2result = j2template.render(manifest=self.manifest, portfolio_index=portfolio_index,
                #                              product_index=product_index, lambda_arn=lambda_arn, uuid=uuid.uuid4(),
                #                              regions=region_list)
                template_url = self._stage_template(product.skeleton_file +
                                                    ".template")
            elif product.product_type.lower() == 'optional':
                if len(product.template_file) > 0:
                    template_url = self._stage_template(product.template_file)
                    j2result = j2template.render(
                        manifest=self.manifest,
                        portfolio_index=portfolio_index,
                        product_index=product_index,
                        lambda_arn=lambda_arn,
                        uuid=uuid.uuid4(),
                        template_url=template_url)
                    generated_avm_template = os.path.join(
                        self.manifest_folder,
                        product.skeleton_file + ".generated.template")
                    logger.info(
                        "Writing the generated product template to {}".format(
                            generated_avm_template))
                    with open(generated_avm_template, "w") as fh:
                        fh.write(j2result)
                    template_url = self._stage_template(generated_avm_template)
                else:
                    raise Exception(
                        "Missing template_file location for portfolio:{} and product:{} in Manifest file"
                        .format(portfolio.name, product.name))

        else:
            raise Exception(
                "Missing skeleton_file for portfolio:{} and product:{} in Manifest file"
                .format(portfolio.name, product.name))

        artifact_params = {}
        artifact_params.update({'Info': {'LoadTemplateFromURL': template_url}})
        artifact_params.update({'Type': 'CLOUD_FORMATION_TEMPLATE'})
        artifact_params.update({'Description': product.description})
        sc_product.update({'ProvisioningArtifactParameters': artifact_params})

        try:
            if product.rules_file:
                rules = self._load_template_rules(product.rules_file)
                sc_product.update({'Rules': rules})
        except Exception as e:
            logger.error(e)

        input_params.update({'SCPortfolio': sc_portfolio})
        input_params.update({'SCProduct': sc_product})

        return self._create_state_machine_input_map(input_params)
Ejemplo n.º 11
0
    def create_key_pair(self,
                        account,
                        region,
                        param_key_material=None,
                        param_key_fingerprint=None,
                        param_key_name=None):

        if param_key_name:
            self.logger.info(
                "Looking up values in SSM parameter:{}".format(param_key_name))
            existing_param = self.ssm.describe_parameters(param_key_name)

            if existing_param:
                return self.ssm.get_parameter(param_key_name)

        sts = STS(self.logger)
        key_name = sanitize(
            "%s_%s_%s_%s" %
            ('lz', account, region, time.strftime("%Y-%m-%dT%H-%M-%S")))

        try:
            role_arn = "arn:aws:iam::" + str(
                account) + ":role/AWSCloudFormationStackSetExecutionRole"
            session_name = "create_key_pair_role"
            # assume role
            credentials = sts.assume_role(role_arn, session_name)
            self.logger.info("Assuming IAM role: {}".format(role_arn))

            # instantiate EC2 class
            self.logger.debug(
                "Creating EC2 Session in {} for account: {}".format(
                    region, account))
            ec2 = EC2(self.logger, region, credentials=credentials)

            if type(credentials) == dict:
                # create EC2 key pair in member account
                self.logger.info(
                    "Create key pair in the member account {} in region: {}".
                    format(account, region))
                response = ec2.create_key_pair(key_name)
                self.logger.debug(response)

                # add key material and fingerprint in the SSM Parameter Store
                self.logger.info(
                    "Adding Key Material and Fingerprint to SSM PS")
                description = "Contains EC2 key pair asset created by Landing Zone Solution: " \
                              "EC2 Key Pair Custom Resource."
                # Get Landing Zone KMS Key ID
                key_id = self._get_kms_key_id()
                if param_key_fingerprint:
                    self.ssm.put_parameter_use_cmk(
                        param_key_fingerprint, response.get('KeyFingerprint'),
                        key_id, description)
                if param_key_material:
                    self.ssm.put_parameter_use_cmk(param_key_material,
                                                   response.get('KeyMaterial'),
                                                   key_id, description)
                if param_key_name:
                    self.ssm.put_parameter(param_key_name, key_name,
                                           description)

                return key_name
            else:
                self.logger.error("Unable to obtain credentials.")
        except Exception as e:
            message = {
                'FILE': __file__.split('/')[-1],
                'CLASS': self.__class__.__name__,
                'METHOD': inspect.stack()[0][3],
                'EXCEPTION': str(e)
            }
            self.logger.exception(message)
            raise