Esempio n. 1
0
 def hub_client(self, service):
     if self.is_running_in_spoke():
         return betterboto_client.CrossAccountClientContextManager(
             service,
             config.get_puppet_role_arn(self.executor_account_id),
             f"{self.executor_account_id}-{config.get_puppet_role_name()}",
         )
     else:
         return betterboto_client.CrossAccountClientContextManager(
             service,
             config.get_puppet_role_arn(self.puppet_account_id),
             f"{self.puppet_account_id}-{config.get_puppet_role_name()}",
         )
Esempio n. 2
0
def bootstrap_spokes_in_ou(ou_path_or_id, role_name, iam_role_arns,
                           permission_boundary):
    org_iam_role_arn = config.get_org_iam_role_arn()
    puppet_account_id = config.get_puppet_account_id()
    if org_iam_role_arn is None:
        click.echo('No org role set - not expanding')
    else:
        click.echo('Expanding using role: {}'.format(org_iam_role_arn))
        with betterboto_client.CrossAccountClientContextManager(
                'organizations', org_iam_role_arn, 'org-iam-role') as client:
            tasks = []
            if ou_path_or_id.startswith('/'):
                ou_id = client.convert_path_to_ou(ou_path_or_id)
            else:
                ou_id = ou_path_or_id
            logging.info(f"ou_id is {ou_id}")
            response = client.list_children_nested(ParentId=ou_id,
                                                   ChildType='ACCOUNT')
            for spoke in response:
                tasks.append(
                    management_tasks.BootstrapSpokeAsTask(
                        puppet_account_id=puppet_account_id,
                        account_id=spoke.get('Id'),
                        iam_role_arns=iam_role_arns,
                        role_name=role_name,
                        permission_boundary=permission_boundary,
                    ))

        runner.run_tasks_for_bootstrap_spokes_in_ou(tasks)
def get_provisioning_artifact_id_for(portfolio_name, product_name,
                                     version_name, account_id, region):
    logger.info(
        "Getting provisioning artifact id for: {} {} {} in the region: {} of account: {}"
        .format(portfolio_name, product_name, version_name, region,
                account_id))
    role = "arn:aws:iam::{}:role/{}".format(
        account_id, 'servicecatalog-puppet/PuppetRole')
    with betterboto_client.CrossAccountClientContextManager(
            'servicecatalog',
            role,
            "-".join([account_id, region]),
            region_name=region) as cross_account_servicecatalog:
        product_id = None
        version_id = None
        portfolio_id = None
        args = {}
        while True:
            response = cross_account_servicecatalog.list_accepted_portfolio_shares(
            )
            assert response.get(
                'NextPageToken') is None, "Pagination not supported"
            for portfolio_detail in response.get('PortfolioDetails'):
                if portfolio_detail.get('DisplayName') == portfolio_name:
                    portfolio_id = portfolio_detail.get('Id')
                    break

            if portfolio_id is None:
                response = cross_account_servicecatalog.list_portfolios()
                for portfolio_detail in response.get('PortfolioDetails', []):
                    if portfolio_detail.get('DisplayName') == portfolio_name:
                        portfolio_id = portfolio_detail.get('Id')
                        break

            assert portfolio_id is not None, "Could not find portfolio"
            logger.info("Found portfolio: {}".format(portfolio_id))

            args['PortfolioId'] = portfolio_id
            response = cross_account_servicecatalog.search_products_as_admin(
                **args)
            for product_view_details in response.get('ProductViewDetails'):
                product_view = product_view_details.get('ProductViewSummary')
                if product_view.get('Name') == product_name:
                    logger.info('Found product: {}'.format(product_view))
                    product_id = product_view.get('ProductId')
            if response.get('NextPageToken', None) is not None:
                args['PageToken'] = response.get('NextPageToken')
            else:
                break
        assert product_id is not None, "Did not find product looking for"

        response = cross_account_servicecatalog.list_provisioning_artifacts(
            ProductId=product_id)
        assert response.get('NextPageToken') is None, "Pagination not support"
        for provisioning_artifact_detail in response.get(
                'ProvisioningArtifactDetails'):
            if provisioning_artifact_detail.get('Name') == version_name:
                version_id = provisioning_artifact_detail.get('Id')
        assert version_id is not None, "Did not find version looking for"
        return product_id, version_id
Esempio n. 4
0
 def hub_regional_client(self, service, region_name=None):
     region = region_name or self.region
     if self.is_running_in_spoke():
         return betterboto_client.CrossAccountClientContextManager(
             service,
             config.get_puppet_role_arn(self.executor_account_id),
             f"{self.executor_account_id}-{config.get_puppet_role_name()}",
             region_name=region,
         )
     else:
         return betterboto_client.CrossAccountClientContextManager(
             service,
             config.get_puppet_role_arn(self.puppet_account_id),
             f"{self.puppet_account_id}-{region}-{config.get_puppet_role_name()}",
             region_name=region,
         )
    def run(self):
        home_region = config.get_home_region(self.puppet_account_id)
        with betterboto_client.CrossAccountClientContextManager(
            "lambda",
            f"arn:aws:iam::{self.puppet_account_id}:role/servicecatalog-puppet/PuppetRole",
            f"sc-{home_region}-{self.puppet_account_id}",
            region_name=home_region,
        ) as lambda_client:
            payload = dict(
                account_id=self.account_id,
                region=self.region,
                parameters=self.get_all_params(),
            )
            response = lambda_client.invoke(
                FunctionName=self.function_name,
                InvocationType=self.invocation_type,
                Payload=json.dumps(payload),
                Qualifier=self.qualifier,
            )
        success_results = dict(RequestResponse=200, Event=202, DryRun=204)

        if success_results.get(self.invocation_type) != response.get('StatusCode'):
            raise Exception(f"{self.lambda_invocation_name} failed for {self.account_id}, {self.region}")
        else:
            if response.get('FunctionError'):
                error_payload = response.get('Payload').read()
                raise Exception(error_payload)
            else:
                output = dict(**self.params_for_results_display(), payload=payload, response=response)
                self.write_output(output)
Esempio n. 6
0
    def run(self):
        logger.info(
            f"[{self.launch_name}] {self.account_id}:{self.region} :: "
            f"starting terminate try {self.try_count} of {self.retry_count}")

        role = f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole"
        with betterboto_client.CrossAccountClientContextManager(
                'servicecatalog',
                role,
                f'sc-{self.region}-{self.account_id}',
                region_name=self.region) as service_catalog:
            logger.info(
                f"[{self.launch_name}] {self.account_id}:{self.region} :: looking for previous failures"
            )
            provisioned_product_id, provisioning_artifact_id = aws.ensure_is_terminated(
                service_catalog, self.launch_name, self.product_id)
            log_output = self.to_str_params()
            log_output.update({
                "provisioned_product_id": provisioned_product_id,
            })
            f = self.output().open('w')
            f.write(json.dumps(
                log_output,
                indent=4,
                default=str,
            ))
            f.close()
            logger.info(
                f"[{self.launch_name}] {self.account_id}:{self.region} :: finished terminating"
            )
Esempio n. 7
0
    def run(self):
        logger.info(f"[{self.launch_name}] {self.account_id}:{self.region} :: "
                    f"starting dry run terminate try {self.try_count} of {self.retry_count}")

        role = f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole"
        with betterboto_client.CrossAccountClientContextManager(
                'servicecatalog', role, f'sc-{self.region}-{self.account_id}', region_name=self.region
        ) as service_catalog:
            logger.info(f"[{self.launch_name}] {self.account_id}:{self.region} :: looking for previous failures")
            r = aws.get_provisioned_product_details(self.product_id, self.launch_name, service_catalog)

            if r is None:
                self.write_result(
                    '-', '-', constants.NO_CHANGE, notes='There is nothing to terminate'
                )
            else:
                provisioned_product_name = service_catalog.describe_provisioning_artifact(
                    ProvisioningArtifactId=r.get('ProvisioningArtifactId'),
                    ProductId=self.product_id,
                ).get('ProvisioningArtifactDetail').get('Name')

                if r.get('Status') != "TERMINATED":
                    self.write_result(
                        provisioned_product_name, '-', constants.CHANGE, notes='The product would be terminated'
                    )
                else:
                    self.write_result(
                        '-', '-', constants.CHANGE, notes='The product is already terminated'
                    )
 def spoke_regional_client(self, service):
     return betterboto_client.CrossAccountClientContextManager(
         service,
         config.get_puppet_role_arn(self.account_id),
         f"{self.account_id}-{self.region}-{config.get_puppet_role_name()}",
         region_name=self.region,
     )
def apply_migration_policies(role_arn):
    click.echo("Updating state file")
    with betterboto_client.CrossAccountClientContextManager(
            "organizations",
            role_arn,
            f"organizations",
    ) as organizations:
        list_accounts_response = organizations.list_accounts_single_page()
        list_roots_response = organizations.list_roots_single_page()
        root_id = list_roots_response.get("Roots")[0].get("Id")
        org_path = SEP.join(["environment", root_id])
        all_files_in_environment_list = helper.getListOfFiles(org_path)

    # Step 1 Save Attached policies
    accounts = {
        account.get("Id"): account.get("Name")
        for account in list_accounts_response.get("Accounts")
    }
    ous = get_organizational_units(root_id)  # list all OUs in org

    org_ids_map = accounts | ous
    policy_ids_map = dict()

    # map SCP name to Ids
    for file_path in os.listdir(service_control_policies_path):
        policy = helper.read_json(
            SEP.join([service_control_policies_path,
                      file_path]))["PolicySummary"]
        policy_ids_map[helper.get_valid_filename(
            policy["Name"])] = policy["Id"]

    # TODO make this in accordance with Eamonn's AWS Organized general way of doing things
    # so the user will be able to type in the file name and the migration wil be applied
    reverse_org_ids_map = dict((v, k) for k, v in org_ids_map.items())
    for migration_policy in os.listdir(
            make_individual_migration_policies_path):
        policy = helper.read_json(
            SEP.join(
                [make_individual_migration_policies_path,
                 migration_policy])).get("Migration")

        policy_id = policy.get("Policy_Id")
        policy_name = policy.get("Policy_Name")
        target_name = policy.get("Target")
        target_id = reverse_org_ids_map[target_name]
        policy_type = policy.get("Migration_Type")

        try:
            org.attach_policy(
                PolicyId=policy_id, TargetId=target_id
            ) if policy_type == ATTACH_POLICY else org.detach_policy(
                PolicyId=policy_id, TargetId=target_id)
        except:
            print(
                f"Error when attempting to {policy_type} {policy_name} on target {target_name}."
            )
        else:
            print(
                f"Successfully performed {policy_type} {policy_name} on target {target_name}."
            )
Esempio n. 10
0
def expand(f, single_account):
    click.echo("Expanding")
    puppet_account_id = config.get_puppet_account_id()
    manifest = manifest_utils.load(f, puppet_account_id)
    org_iam_role_arn = config.get_org_iam_role_arn(puppet_account_id)
    if org_iam_role_arn is None:
        click.echo("No org role set - not expanding")
        new_manifest = manifest
    else:
        click.echo("Expanding using role: {}".format(org_iam_role_arn))
        with betterboto_client.CrossAccountClientContextManager(
            "organizations", org_iam_role_arn, "org-iam-role"
        ) as client:
            new_manifest = manifest_utils.expand_manifest(manifest, client)
    click.echo("Expanded")
    if single_account:
        click.echo(f"Filtering for single account: {single_account}")

        for account in new_manifest.get("accounts", []):
            if account.get("account_id") == single_account:
                click.echo(f"Found single account: {single_account}")
                new_manifest["accounts"] = [account]
                break

        click.echo("Filtered")

    new_name = f.name.replace(".yaml", "-expanded.yaml")
    logger.info("Writing new manifest: {}".format(new_name))
    with open(new_name, "w") as output:
        output.write(yaml.safe_dump(new_manifest, default_flow_style=False))
Esempio n. 11
0
def get_portfolio_for(portfolio_name, account_id, region):
    logger.info(f"Getting portfolio id for: {portfolio_name}")
    role = f"arn:aws:iam::{account_id}:role/servicecatalog-puppet/PuppetRole"
    with betterboto_client.CrossAccountClientContextManager(
            'servicecatalog',
            role,
            "-".join([account_id, region]),
            region_name=region) as cross_account_servicecatalog:
        portfolio = None
        while True:
            response = cross_account_servicecatalog.list_accepted_portfolio_shares(
            )
            assert response.get(
                'NextPageToken') is None, "Pagination not supported"
            for portfolio_detail in response.get('PortfolioDetails'):
                if portfolio_detail.get('DisplayName') == portfolio_name:
                    portfolio = portfolio_detail
                    break

            if portfolio is None:
                response = cross_account_servicecatalog.list_portfolios()
                for portfolio_detail in response.get('PortfolioDetails', []):
                    if portfolio_detail.get('DisplayName') == portfolio_name:
                        portfolio = portfolio_detail
                        break

            assert portfolio is not None, "Could not find portfolio"
            logger.info(f"Found portfolio: {portfolio}")
            return portfolio
 def run(self):
     with self.input().get('portfolio').open('r') as f:
         portfolio_details = json.loads(f.read())
     with betterboto_client.CrossAccountClientContextManager(
             'servicecatalog',
             f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole",
             f"{self.account_id}-{self.region}",
             region_name=self.region) as cross_account_servicecatalog:
         product_id = aws.get_product_id_for(
             cross_account_servicecatalog,
             portfolio_details.get('portfolio_id'),
             self.product,
         )
         with self.output().open('w') as f:
             f.write(
                 json.dumps(
                     {
                         'product_name':
                         self.product,
                         'product_id':
                         product_id,
                         'portfolio_name':
                         portfolio_details.get('portfolio_name'),
                         'portfolio_id':
                         portfolio_details.get('portfolio_id'),
                     },
                     indent=4,
                     default=str,
                 ))
def bootstrap_spokes_in_ou(ou_path_or_id,
                           role_name,
                           iam_role_arns,
                           permission_boundary,
                           num_workers=10):
    puppet_account_id = config.get_puppet_account_id()
    org_iam_role_arn = config.get_org_iam_role_arn(puppet_account_id)
    if org_iam_role_arn is None:
        click.echo("No org role set - not expanding")
    else:
        click.echo("Expanding using role: {}".format(org_iam_role_arn))
        with betterboto_client.CrossAccountClientContextManager(
                "organizations", org_iam_role_arn, "org-iam-role") as client:
            tasks = []
            if ou_path_or_id.startswith("/"):
                ou_id = client.convert_path_to_ou(ou_path_or_id)
            else:
                ou_id = ou_path_or_id
            logging.info(f"ou_id is {ou_id}")
            response = client.list_children_nested(ParentId=ou_id,
                                                   ChildType="ACCOUNT")
            for spoke in response:
                tasks.append(
                    management_tasks.BootstrapSpokeAsTask(
                        puppet_account_id=puppet_account_id,
                        account_id=spoke.get("Id"),
                        iam_role_arns=iam_role_arns,
                        role_name=role_name,
                        permission_boundary=permission_boundary,
                    ))

        runner.run_tasks_for_bootstrap_spokes_in_ou(tasks, num_workers)
    def run(self):
        all_params = {}
        for param_name, param_details in self.parameters.items():
            if param_details.get('ssm'):
                with self.input().get('ssm_params').get(
                        param_name).open() as f:
                    all_params[param_name] = json.loads(f.read()).get('Value')
            if param_details.get('default'):
                all_params[param_name] = param_details.get('default')
        logger.info(
            f"[{self.uid}] :: finished collecting all_params: {all_params}")

        environmentVariablesOverride = [{
            'name': param_name,
            'value': param_details,
            'type': 'PLAINTEXT'
        } for param_name, param_details in all_params.items()]

        role = f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole"
        with betterboto_client.CrossAccountClientContextManager(
                'codebuild',
                role,
                f'sc-{self.region}-{self.account_id}',
                region_name=self.region) as codebuild:
            build = codebuild.start_build_and_wait_for_completion(
                projectName=self.project_name,
                environmentVariablesOverride=environmentVariablesOverride,
            )
            if build.get('buildStatus') != 'SUCCEEDED':
                raise Exception(
                    f"{self.uid}: Build failed: {build.get('buildStatus')}")
        self.write_output(self.param_kwargs)
 def run(self):
     logger.info(
         f"[{self.portfolio}] {self.account_id}:{self.region} :: starting creating portfolio"
     )
     role = f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole"
     with betterboto_client.CrossAccountClientContextManager(
             'servicecatalog',
             role,
             f'sc-{self.account_id}-{self.region}',
             region_name=self.region) as spoke_service_catalog:
         spoke_portfolio = aws.ensure_portfolio(
             spoke_service_catalog,
             self.portfolio,
             self.provider_name,
             self.description,
         )
     with self.output().open('w') as f:
         f.write(json.dumps(
             spoke_portfolio,
             indent=4,
             default=str,
         ))
     logger.info(
         f"[{self.portfolio}] {self.account_id}:{self.region} :: finished creating portfolio"
     )
def get_required_params(region_name, portfolio, product, version, account_id):
    logging.info(
        f"get_required_params for {region_name} {portfolio} {product} {version} {account_id}"
    )
    with betterboto_client.CrossAccountClientContextManager(
            'servicecatalog',
            f"arn:aws:iam::{account_id}:role/servicecatalog-puppet/PuppetRole",
            f"{account_id}-{region_name}",
            region_name=region_name) as service_catalog:
        portfolio_id = aws.get_portfolio_id_for(service_catalog, portfolio)
        product_id = aws.get_product_id_for(service_catalog, portfolio_id,
                                            product)
        version_id = aws.get_version_id_for(service_catalog, product_id,
                                            version)

        required_parameters = {}

        response = service_catalog.describe_provisioning_parameters(
            ProductId=product_id,
            ProvisioningArtifactId=version_id,
            PathId=aws.get_path_for_product(service_catalog, product_id,
                                            portfolio),
        )
        for provisioning_artifact_parameters in response.get(
                'ProvisioningArtifactParameters', []):
            parameter_key = provisioning_artifact_parameters.get(
                'ParameterKey')
            required_parameters[parameter_key] = True

    return required_parameters
 def hub_regional_client(self, service, region_name=None):
     region = region_name or self.region
     return betterboto_client.CrossAccountClientContextManager(
         service,
         config.get_puppet_role_arn(self.puppet_account_id),
         f"{self.puppet_account_id}-{region}-{config.get_puppet_role_name()}",
         region_name=region,
     )
Esempio n. 18
0
def get_provisioning_artifact_id_for(portfolio_name, product_name,
                                     version_name, account_id, region):
    logger.info(
        "Getting provisioning artifact id for: {} {} {} in the region: {} of account: {}"
        .format(portfolio_name, product_name, version_name, region,
                account_id))
    role = "arn:aws:iam::{}:role/{}".format(
        account_id, "servicecatalog-puppet/PuppetRole")
    with betterboto_client.CrossAccountClientContextManager(
            "servicecatalog",
            role,
            "-".join([account_id, region]),
            region_name=region) as cross_account_servicecatalog:
        product_id = None
        version_id = None
        portfolio_id = None

        response = cross_account_servicecatalog.list_accepted_portfolio_shares(
        )
        assert response.get(
            "NextPageToken") is None, "Pagination not supported"
        for portfolio_detail in response.get("PortfolioDetails"):
            if portfolio_detail.get("DisplayName") == portfolio_name:
                portfolio_id = portfolio_detail.get("Id")
                break

        if portfolio_id is None:
            response = cross_account_servicecatalog.list_portfolios_single_page(
            )
            for portfolio_detail in response.get("PortfolioDetails", []):
                if portfolio_detail.get("DisplayName") == portfolio_name:
                    portfolio_id = portfolio_detail.get("Id")
                    break

        assert portfolio_id is not None, "Could not find portfolio"
        logger.info(
            f"Found portfolio: {portfolio_id}, looking for product: {product_name}"
        )

        response = cross_account_servicecatalog.search_products_as_admin_single_page(
            PortfolioId=portfolio_id)
        for product_view_details in response.get("ProductViewDetails"):
            product_view = product_view_details.get("ProductViewSummary")
            logging.info(f"looking at {product_view.get('Name')}")
            if product_view.get("Name") == product_name:
                logger.info("Found product: {}".format(product_view))
                product_id = product_view.get("ProductId")

        assert product_id is not None, "Did not find product looking for"

        response = cross_account_servicecatalog.list_provisioning_artifacts_single_page(
            ProductId=product_id)
        for provisioning_artifact_detail in response.get(
                "ProvisioningArtifactDetails"):
            if provisioning_artifact_detail.get("Name") == version_name:
                version_id = provisioning_artifact_detail.get("Id")
        assert version_id is not None, "Did not find version looking for"
        return product_id, version_id
Esempio n. 19
0
def make_migrations(role_arn) -> None:
    os.makedirs(SEP.join(["environment", "migrations"]), exist_ok=True)
    with betterboto_client.CrossAccountClientContextManager(
            "organizations",
            role_arn,
            f"organizations",
    ) as organizations:
        make_migrations_for_organizational_units(organizations)
        make_migrations_for_accounts(organizations)
def on_task_processing_time(task, duration):
    print_stats()
    record_event("processing_time", task, {"duration": duration})

    task_params = dict(**task.param_kwargs)
    task_params.update(task.params_for_results_display())

    with betterboto_client.CrossAccountClientContextManager(
            "cloudwatch",
            config.get_puppet_role_arn(config.get_puppet_account_id()),
            "cloudwatch-puppethub",
    ) as cloudwatch:

        dimensions = [dict(
            Name="task_type",
            Value=task.__class__.__name__,
        )]
        for note_worthy in [
                "launch_name",
                "region",
                "account_id",
                "puppet_account_id",
                "sharing_mode",
                "portfolio",
                "product",
                "version",
                "execution",
        ]:
            if task_params.get(note_worthy):
                dimensions.append(
                    dict(Name=note_worthy, Value=task_params.get(note_worthy)))

        cloudwatch.put_metric_data(
            Namespace=
            f"ServiceCatalogTools/Puppet/v1/ProcessingTime/{task.__class__.__name__}",
            MetricData=[
                dict(
                    MetricName=task.__class__.__name__,
                    Dimensions=dimensions,
                    Value=duration,
                    Unit="Seconds",
                ),
            ],
        )
        cloudwatch.put_metric_data(
            Namespace=f"ServiceCatalogTools/Puppet/v1/ProcessingTime/Tasks",
            MetricData=[
                dict(
                    MetricName="Tasks",
                    Dimensions=[
                        dict(Name="TaskType", Value=task.__class__.__name__)
                    ],
                    Value=duration,
                    Unit="Seconds",
                ),
            ],
        )
Esempio n. 21
0
def get_home_region(puppet_account_id):
    if get_local_config("home_region"):
        return get_local_config("home_region")
    with betterboto_client.CrossAccountClientContextManager(
            "ssm",
            f"arn:aws:iam::{puppet_account_id}:role/servicecatalog-puppet/PuppetRole",
            f"{puppet_account_id}-PuppetRole",
    ) as ssm:
        response = ssm.get_parameter(Name=constants.HOME_REGION_PARAM_NAME)
        return response.get("Parameter").get("Value")
Esempio n. 22
0
 def run(self):
     with betterboto_client.CrossAccountClientContextManager(
             "cloudformation",
             config.get_puppet_role_arn(self.account_id),
             f"{self.account_id}-{self.region}-{config.get_puppet_role_name()}",
             region_name=self.region,
     ) as cloudformation:
         self.info(f"About to delete the stack: {self.stack_name}")
         cloudformation.ensure_deleted(StackName=self.stack_name)
     self.write_output(self.params_for_results_display())
Esempio n. 23
0
 def hub_client(self, service):
     kwargs = dict()
     if os.environ.get(f"CUSTOM_ENDPOINT_{service}"):
         kwargs["endpoint_url"] = os.environ.get(
             f"CUSTOM_ENDPOINT_{service}")
     if self.is_running_in_spoke():
         return betterboto_client.CrossAccountClientContextManager(
             service,
             config.get_puppet_role_arn(self.executor_account_id),
             f"{self.executor_account_id}-{config.get_puppet_role_name()}",
             **kwargs,
         )
     else:
         return betterboto_client.CrossAccountClientContextManager(
             service,
             config.get_puppet_role_arn(self.puppet_account_id),
             f"{self.puppet_account_id}-{config.get_puppet_role_name()}",
             **kwargs,
         )
Esempio n. 24
0
def get_home_region(puppet_account_id):
    if get_local_config("home_region"):
        return get_local_config("home_region")
    with betterboto_client.CrossAccountClientContextManager(
            "ssm",
            get_puppet_role_arn(puppet_account_id),
            f"{puppet_account_id}-{get_puppet_role_name()}",
    ) as ssm:
        response = ssm.get_parameter(Name=constants.HOME_REGION_PARAM_NAME)
        return response.get("Parameter").get("Value")
 def run(self):
     with betterboto_client.CrossAccountClientContextManager(
             "cloudformation",
             f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole",
             f"{self.account_id}-{self.region}-PuppetRole",
             region_name=self.region,
     ) as cloudformation:
         self.info(f"About to delete the stack: {self.stack_name}")
         cloudformation.ensure_deleted(StackName=self.stack_name)
     self.write_output(self.params_for_results_display())
Esempio n. 26
0
 def spoke_client(self, service):
     kwargs = dict()
     if os.environ.get(f"CUSTOM_ENDPOINT_{service}"):
         kwargs["endpoint_url"] = os.environ.get(
             f"CUSTOM_ENDPOINT_{service}")
     return betterboto_client.CrossAccountClientContextManager(
         service,
         config.get_puppet_role_arn(self.account_id),
         f"{self.account_id}-{config.get_puppet_role_name()}",
         **kwargs,
     )
def handler(event, context):
    request_type = event["RequestType"]
    try:
        logger.info(request_type)

        assumable_role_in_root_account_arn = os.environ.get(
            "ASSUMABLE_ROLE_IN_ROOT_ACCOUNT_ARN"
        )
        with betterboto_client.CrossAccountClientContextManager(
                "organizations", assumable_role_in_root_account_arn, "assumable_org_role"
        ) as organizations:
            if request_type in ["Create", "Update"]:
                target_ou = event.get("ResourceProperties").get("TargetOU")
                account_id = event.get("ResourceProperties").get("AccountId")

                result = organizations.list_parents_single_page(ChildId=account_id)
                if len(result.get("Parents", [])) != 1:
                    raise Exception(
                        f"There were unexpected parents for the account_id {account_id}: {json.dumps(result)}"
                    )
                current_ou = result.get("Parents")[0].get('Id')
                if str(target_ou) != "None" and current_ou != target_ou:
                    logger.info("Moving account to new OU")
                    response = organizations.list_roots()
                    if len(response.get("Roots")) != 1:
                        raise Exception("nRoots: {}".format(len(response.get("Roots"))))
                    if str(target_ou).startswith("/"):
                        target = organizations.convert_path_to_ou(target_ou)
                    else:
                        target = target_ou
                    organizations.move_account(
                        AccountId=account_id,
                        SourceParentId=current_ou,
                        DestinationParentId=target,
                    )

                    send_response(
                        event,
                        context,
                        "SUCCESS",
                        {
                            "Message": f"Moved to {target}",
                            "account_id": account_id,
                        },
                    )

            elif request_type == "Delete":
                send_response(event, context, "SUCCESS", {"Message": "Deleted"})
            else:
                send_response(event, context, "FAILED", {"Message": "Unexpected"})
    except Exception as ex:
        logger.error(ex)
        send_response(event, context, "FAILED", {"Message": "Exception"})
Esempio n. 28
0
 def run(self):
     self.info("Starting")
     with betterboto_client.CrossAccountClientContextManager(
             'cloudformation',
             f"arn:aws:iam::{self.account_id}:role/servicecatalog-puppet/PuppetRole",
             f"{self.account_id}-{self.region}-PuppetRole",
             region_name=self.region,
     ) as cloudformation:
         self.info(f"About to delete the stack: {self.stack_name}")
         cloudformation.ensure_deleted(StackName=self.stack_name)
     self.write_output({})
     self.info("Finished")
Esempio n. 29
0
def make_migrations(role_arn: str, root_id: str) -> None:
    with betterboto_client.CrossAccountClientContextManager(
            "organizations",
            role_arn,
            f"organizations",
    ) as orgs_client:
        progress = bar.IncrementalBar("Making migrations", max=2)
        progress.next()
        make_migrations_for_organizational_units(orgs_client, root_id)
        progress.next()
        make_migrations_for_accounts(orgs_client, root_id)
        progress.finish()
def import_organization_policies(role_arn, root_id) -> None:
    with betterboto_client.CrossAccountClientContextManager(
        "organizations", role_arn, f"organizations"
    ) as organizations:
        progress = bar.IncrementalBar("Importing SCPs", max=4)
        progress.next()
        remove_any_existing_policy_records(root_id)
        progress.next()
        save_all_policies_from_org(root_id, organizations)
        progress.next()
        save_targets_for_policy(root_id, organizations)
        progress.next()
        progress.finish()