From 1bc55d3db77ee3201306613d193ec25d93aba37a Mon Sep 17 00:00:00 2001 From: AWS Date: Mon, 6 Jan 2025 19:33:35 +0000 Subject: [PATCH] Release: 1.13.3 --- VERSION | 2 +- modules/aft-account-request-framework/vpc.tf | 8 +++--- modules/aft-code-repositories/codepipeline.tf | 28 +++++++++++-------- modules/aft-code-repositories/codestar.tf | 2 +- .../customizations_pipeline/codepipeline.tf | 14 ++++++---- .../ACCOUNT_TEMPLATE/terraform/backend.jinja | 4 ++- .../account_provisioning_framework.py | 2 +- .../aft_common/account_request_framework.py | 19 +++++++------ .../aft-lambda-layer/aft_common/aft_utils.py | 2 +- .../aft_common/codepipeline.py | 11 ++++++-- .../aft_common/customizations.py | 8 ++++-- .../aft_common/feature_options.py | 2 +- sources/aft-lambda-layer/aft_common/sqs.py | 2 +- sources/scripts/terraform_client.py | 22 ++++++++++++--- .../aft_account_request_action_trigger.py | 6 ++-- .../aft_account_request_audit_trigger.py | 5 +++- .../aft_cleanup_resources.py | 5 +++- 17 files changed, 89 insertions(+), 53 deletions(-) diff --git a/VERSION b/VERSION index 61ce01b3..01b75682 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.13.2 +1.13.3 diff --git a/modules/aft-account-request-framework/vpc.tf b/modules/aft-account-request-framework/vpc.tf index 97e59e33..47108f4b 100644 --- a/modules/aft-account-request-framework/vpc.tf +++ b/modules/aft-account-request-framework/vpc.tf @@ -202,13 +202,13 @@ resource "aws_internet_gateway" "aft-vpc-igw" { } resource "aws_eip" "aft-vpc-natgw-01" { - count = var.aft_enable_vpc ? 1 : 0 - vpc = true + count = var.aft_enable_vpc ? 1 : 0 + domain = "vpc" } resource "aws_eip" "aft-vpc-natgw-02" { - count = var.aft_enable_vpc ? 1 : 0 - vpc = true + count = var.aft_enable_vpc ? 1 : 0 + domain = "vpc" } resource "aws_nat_gateway" "aft-vpc-natgw-01" { diff --git a/modules/aft-code-repositories/codepipeline.tf b/modules/aft-code-repositories/codepipeline.tf index 538b9728..0efe8953 100644 --- a/modules/aft-code-repositories/codepipeline.tf +++ b/modules/aft-code-repositories/codepipeline.tf @@ -6,9 +6,10 @@ ############################################################## resource "aws_codepipeline" "codecommit_account_request" { - count = local.vcs.is_codecommit ? 1 : 0 - name = "ct-aft-account-request" - role_arn = aws_iam_role.account_request_codepipeline_role.arn + count = local.vcs.is_codecommit ? 1 : 0 + name = "ct-aft-account-request" + role_arn = aws_iam_role.account_request_codepipeline_role.arn + pipeline_type = "V2" artifact_store { location = var.codepipeline_s3_bucket_name @@ -111,9 +112,10 @@ resource "aws_cloudwatch_event_target" "account_request" { ############################################################## resource "aws_codepipeline" "codestar_account_request" { - count = local.vcs.is_codecommit ? 0 : 1 - name = "ct-aft-account-request" - role_arn = aws_iam_role.account_request_codepipeline_role.arn + count = local.vcs.is_codecommit ? 0 : 1 + name = "ct-aft-account-request" + role_arn = aws_iam_role.account_request_codepipeline_role.arn + pipeline_type = "V2" artifact_store { location = var.codepipeline_s3_bucket_name @@ -176,9 +178,10 @@ resource "aws_codepipeline" "codestar_account_request" { ############################################################## resource "aws_codepipeline" "codecommit_account_provisioning_customizations" { - count = local.vcs.is_codecommit ? 1 : 0 - name = "ct-aft-account-provisioning-customizations" - role_arn = aws_iam_role.account_provisioning_customizations_codepipeline_role.arn + count = local.vcs.is_codecommit ? 1 : 0 + name = "ct-aft-account-provisioning-customizations" + role_arn = aws_iam_role.account_provisioning_customizations_codepipeline_role.arn + pipeline_type = "V2" artifact_store { location = var.codepipeline_s3_bucket_name @@ -242,9 +245,10 @@ resource "aws_codepipeline" "codecommit_account_provisioning_customizations" { ############################################################## resource "aws_codepipeline" "codestar_account_provisioning_customizations" { - count = local.vcs.is_codecommit ? 0 : 1 - name = "ct-aft-account-provisioning-customizations" - role_arn = aws_iam_role.account_provisioning_customizations_codepipeline_role.arn + count = local.vcs.is_codecommit ? 0 : 1 + name = "ct-aft-account-provisioning-customizations" + role_arn = aws_iam_role.account_provisioning_customizations_codepipeline_role.arn + pipeline_type = "V2" artifact_store { location = var.codepipeline_s3_bucket_name diff --git a/modules/aft-code-repositories/codestar.tf b/modules/aft-code-repositories/codestar.tf index 683e1eb0..7857ff36 100644 --- a/modules/aft-code-repositories/codestar.tf +++ b/modules/aft-code-repositories/codestar.tf @@ -43,7 +43,7 @@ resource "aws_codestarconnections_connection" "gitlab" { resource "aws_codestarconnections_connection" "gitlabselfmanaged" { count = local.vcs.is_gitlab_selfmanaged ? 1 : 0 - name = "ct-aft-gitlab-selfmanaged-connection" + name = "ct-aft-gitlab-selfmanaged" host_arn = aws_codestarconnections_host.gitlabselfmanaged[0].arn } diff --git a/sources/aft-customizations-common/templates/customizations_pipeline/codepipeline.tf b/sources/aft-customizations-common/templates/customizations_pipeline/codepipeline.tf index a9d243cc..67ae4647 100644 --- a/sources/aft-customizations-common/templates/customizations_pipeline/codepipeline.tf +++ b/sources/aft-customizations-common/templates/customizations_pipeline/codepipeline.tf @@ -2,9 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 # resource "aws_codepipeline" "aft_codecommit_customizations_codepipeline" { - count = local.vcs.is_codecommit ? 1 : 0 - name = "${var.account_id}-customizations-pipeline" - role_arn = data.aws_iam_role.aft_codepipeline_customizations_role.arn + count = local.vcs.is_codecommit ? 1 : 0 + name = "${var.account_id}-customizations-pipeline" + role_arn = data.aws_iam_role.aft_codepipeline_customizations_role.arn + pipeline_type = "V2" artifact_store { location = data.aws_s3_bucket.aft_codepipeline_customizations_bucket.id @@ -108,9 +109,10 @@ resource "aws_codepipeline" "aft_codecommit_customizations_codepipeline" { } resource "aws_codepipeline" "aft_codestar_customizations_codepipeline" { - count = local.vcs.is_codecommit ? 0 : 1 - name = "${var.account_id}-customizations-pipeline" - role_arn = data.aws_iam_role.aft_codepipeline_customizations_role.arn + count = local.vcs.is_codecommit ? 0 : 1 + name = "${var.account_id}-customizations-pipeline" + role_arn = data.aws_iam_role.aft_codepipeline_customizations_role.arn + pipeline_type = "V2" artifact_store { location = data.aws_s3_bucket.aft_codepipeline_customizations_bucket.id diff --git a/sources/aft-customizations-repos/aft-account-customizations/ACCOUNT_TEMPLATE/terraform/backend.jinja b/sources/aft-customizations-repos/aft-account-customizations/ACCOUNT_TEMPLATE/terraform/backend.jinja index cb7154de..c8d6ee32 100644 --- a/sources/aft-customizations-repos/aft-account-customizations/ACCOUNT_TEMPLATE/terraform/backend.jinja +++ b/sources/aft-customizations-repos/aft-account-customizations/ACCOUNT_TEMPLATE/terraform/backend.jinja @@ -11,7 +11,9 @@ terraform { dynamodb_table = "{{ dynamodb_table }}" encrypt = "true" kms_key_id = "{{ kms_key_id }}" - role_arn = "{{ aft_admin_role_arn }}" + assume_role { + role_arn = "{{ aft_admin_role_arn }}" + } } } {% else -%} diff --git a/sources/aft-lambda-layer/aft_common/account_provisioning_framework.py b/sources/aft-lambda-layer/aft_common/account_provisioning_framework.py index 267ca00e..49c70c91 100644 --- a/sources/aft-lambda-layer/aft_common/account_provisioning_framework.py +++ b/sources/aft-lambda-layer/aft_common/account_provisioning_framework.py @@ -174,7 +174,7 @@ def _put_policy_on_role( def role_policy_is_attached( role_name: str, policy_arn: str, target_account_session: Session ) -> bool: - logger.info("Determining if {policy_arn} is attached to {role_name}") + logger.info(f"Determining if {policy_arn} is attached to {role_name}") resource: IAMServiceResource = target_account_session.resource("iam") role = resource.Role(role_name) policy_iterator = role.attached_policies.all() diff --git a/sources/aft-lambda-layer/aft_common/account_request_framework.py b/sources/aft-lambda-layer/aft_common/account_request_framework.py index 9c58967f..f181c1f6 100644 --- a/sources/aft-lambda-layer/aft_common/account_request_framework.py +++ b/sources/aft-lambda-layer/aft_common/account_request_framework.py @@ -153,10 +153,12 @@ def modify_ct_request_is_valid(request: Dict[str, Any]) -> bool: old_ct_parameters = request.get("old_control_tower_parameters", {}) new_ct_parameters = request["control_tower_parameters"] - for i in old_ct_parameters.keys(): - if i != "ManagedOrganizationalUnit": - if old_ct_parameters[i] != new_ct_parameters[i]: - logger.error(f"Control Tower parameter {i} cannot be modified") + for param_name in old_ct_parameters.keys(): + if param_name != "ManagedOrganizationalUnit": + if old_ct_parameters[param_name] != new_ct_parameters[param_name]: + logger.error( + f"Control Tower parameter {utils.sanitize_input_for_logging(param_name)} cannot be modified" + ) return False return True @@ -193,7 +195,8 @@ def create_new_account( provisioning_parameters.append({"Key": k, "Value": v}) logger.info( - "Creating new account leveraging parameters: " + str(provisioning_parameters) + "Creating new account leveraging parameters: " + + utils.sanitize_input_for_logging(str(provisioning_parameters)) ) provisioned_product_name = create_provisioned_product_name( account_name=request["control_tower_parameters"]["AccountName"] @@ -275,7 +278,7 @@ def update_existing_account( logger.info( "Modifying existing account leveraging parameters: " - + str(provisioning_parameters) + + utils.sanitize_input_for_logging(str(provisioning_parameters)) + " with provisioned product ID " + target_product["Id"] ) @@ -288,7 +291,7 @@ def update_existing_account( ProvisioningParameters=provisioning_parameters, UpdateToken=str(uuid.uuid1()), ) - logger.info(update_response) + logger.info(utils.sanitize_input_for_logging(update_response)) def get_account_request_record( @@ -307,7 +310,7 @@ def get_account_request_record( ) if item: logger.info("Record found") - logger.info(item) + logger.info(utils.sanitize_input_for_logging(item)) return item else: raise Exception(f"Account {request_table_id} not found in {table_name}") diff --git a/sources/aft-lambda-layer/aft_common/aft_utils.py b/sources/aft-lambda-layer/aft_common/aft_utils.py index b5060c89..df59ee78 100644 --- a/sources/aft-lambda-layer/aft_common/aft_utils.py +++ b/sources/aft-lambda-layer/aft_common/aft_utils.py @@ -162,7 +162,7 @@ def invoke_step_function( sanitized_sfn_arn = sanitize_input_for_logging(sfn_arn) logger.info("Starting SFN execution of " + sanitized_sfn_arn) response = client.start_execution(stateMachineArn=sfn_arn, input=input) - logger.debug(response) + logger.debug(sanitize_input_for_logging(response)) return response diff --git a/sources/aft-lambda-layer/aft_common/codepipeline.py b/sources/aft-lambda-layer/aft_common/codepipeline.py index 57e7c9dc..eea1c0b5 100644 --- a/sources/aft-lambda-layer/aft_common/codepipeline.py +++ b/sources/aft-lambda-layer/aft_common/codepipeline.py @@ -17,7 +17,8 @@ def get_pipeline_for_account(session: Session, account_id: str) -> str: current_account = session.client("sts").get_caller_identity()["Account"] current_region = session.region_name - logger.info("Getting pipeline name for " + account_id) + sanitized_account_id = utils.sanitize_input_for_logging(account_id) + logger.info("Getting pipeline name for " + sanitized_account_id) client = session.client("codepipeline", config=utils.get_high_retry_botoconfig()) paginator = client.get_paginator("list_pipelines") @@ -42,7 +43,9 @@ def get_pipeline_for_account(session: Session, account_id: str) -> str: if t["key"] == "managed_by" and t["value"] == "AFT": pipeline_name: str = p["name"] return pipeline_name - raise Exception("Pipelines for account id " + account_id + " was not found") + raise Exception( + "Pipelines for account id " + sanitized_account_id + " was not found" + ) def pipeline_is_running(session: Session, name: str) -> bool: @@ -142,7 +145,9 @@ def delete_customization_pipeline( ) if not pipeline_is_running(session=aft_management_session, name=pipeline_name): client.delete_pipeline(name=pipeline_name) - logger.info(f"Deleted customization pipeline for {account_id}") + logger.info( + f"Deleted customization pipeline for {utils.sanitize_input_for_logging(account_id)}" + ) else: logger.warning( f"Cannot delete running customization pipeline: {pipeline_name}, skipping" diff --git a/sources/aft-lambda-layer/aft_common/customizations.py b/sources/aft-lambda-layer/aft_common/customizations.py index e1f9c465..2359e743 100644 --- a/sources/aft-lambda-layer/aft_common/customizations.py +++ b/sources/aft-lambda-layer/aft_common/customizations.py @@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional import jsonschema -from aft_common.aft_utils import get_high_retry_botoconfig +from aft_common.aft_utils import get_high_retry_botoconfig, sanitize_input_for_logging from aft_common.constants import SSM_PARAM_AFT_DDB_META_TABLE from aft_common.organizations import OrganizationsAgent from aft_common.ssm import get_ssm_parameter_value @@ -30,7 +30,9 @@ def validate_identify_targets_request(payload: Dict[str, Any]) -> bool: ) with open(schema_path) as schema_file: schema_object = json.load(schema_file) - logger.info("Schema Loaded:" + json.dumps(schema_object)) + logger.info( + "Schema Loaded:" + sanitize_input_for_logging(json.dumps(schema_object)) + ) validated = jsonschema.validate(payload, schema_object) if validated is None: logger.info("Request Validated") @@ -53,7 +55,7 @@ def get_all_aft_account_ids(aft_management_session: Session) -> List[str]: while "LastEvaluatedKey" in response: logger.debug( "Paginated response found, continuing at {}".format( - response["LastEvaluatedKey"] + sanitize_input_for_logging(response["LastEvaluatedKey"]) ) ) response = table.scan(ExclusiveStartKey=response["LastEvaluatedKey"]) diff --git a/sources/aft-lambda-layer/aft_common/feature_options.py b/sources/aft-lambda-layer/aft_common/feature_options.py index c3e9ab23..a06d293d 100644 --- a/sources/aft-lambda-layer/aft_common/feature_options.py +++ b/sources/aft-lambda-layer/aft_common/feature_options.py @@ -161,7 +161,7 @@ def get_vpc_security_groups(resource: EC2ServiceResource, vpc: str) -> List[str] sgs = [] for s in vpc_resource.security_groups.all(): sgs.append(s.id) - logger.info("SGs: " + str(sgs)) + logger.info("SGs: " + utils.sanitize_input_for_logging(sgs)) return sgs diff --git a/sources/aft-lambda-layer/aft_common/sqs.py b/sources/aft-lambda-layer/aft_common/sqs.py index d3445f35..53204c0e 100644 --- a/sources/aft-lambda-layer/aft_common/sqs.py +++ b/sources/aft-lambda-layer/aft_common/sqs.py @@ -41,7 +41,7 @@ def receive_sqs_message(session: Session, sqs_queue: str) -> Optional[MessageTyp logger.info("There are messages pending processing") message = response["Messages"][0] logger.info("Message retrieved") - logger.info(message) + logger.info(utils.sanitize_input_for_logging(message)) return message else: logger.info("There are no messages pending processing") diff --git a/sources/scripts/terraform_client.py b/sources/scripts/terraform_client.py index 0718ceda..20c7e15a 100755 --- a/sources/scripts/terraform_client.py +++ b/sources/scripts/terraform_client.py @@ -4,6 +4,7 @@ # import os import time +from typing import Any import requests @@ -169,17 +170,18 @@ def create_destroy_run(workspace_id, api_token): def delete_workspace(workspace_id, api_token): endpoint = "{}/workspaces/{}".format(TERRAFORM_API_ENDPOINT, workspace_id) + sanitized_workspace_id = __sanitize_input_for_logging(workspace_id) headers = __build_standard_headers(api_token) response = __delete(endpoint, headers) if response is not None: errors = response["errors"] if len(errors) == 0: - print("Successfully deleted workspace {}".format(workspace_id)) + print("Successfully deleted workspace {}".format(sanitized_workspace_id)) else: - print("Error occured deleting workspace {}".format(workspace_id)) + print("Error occured deleting workspace {}".format(sanitized_workspace_id)) print(str(errors)) else: - print("Successfully deleted workspace {}".format(workspace_id)) + print("Successfully deleted workspace {}".format(sanitized_workspace_id)) def wait_to_stabilize(entity_type, entity_id, target_states, api_token): @@ -187,7 +189,11 @@ def wait_to_stabilize(entity_type, entity_id, target_states, api_token): status = get_action_status(entity_type, entity_id, api_token) if status in target_states: break - print("{} not yet ready. In status {}".format(entity_type, status)) + print( + "{} not yet ready. In status {}".format( + entity_type, __sanitize_input_for_logging(status) + ) + ) time.sleep(10) return status @@ -258,6 +264,14 @@ def __handle_errors(response): raise ClientError(status="500", message=str(errors)) +def __sanitize_input_for_logging(input: Any) -> str: + """ + Sanitize the input string by replacing newline characters, tabs with their literal string representations. + """ + input_str = str(input) + return input_str.encode("unicode_escape").decode() + + class ClientError(Exception): def __init__(self, status, message): self.status = status diff --git a/src/aft_lambda/aft_account_request_framework/aft_account_request_action_trigger.py b/src/aft_lambda/aft_account_request_framework/aft_account_request_action_trigger.py index 5434f515..361731a4 100644 --- a/src/aft_lambda/aft_account_request_framework/aft_account_request_action_trigger.py +++ b/src/aft_lambda/aft_account_request_framework/aft_account_request_action_trigger.py @@ -6,12 +6,10 @@ from typing import TYPE_CHECKING, Any, Dict from aft_common import notifications -from aft_common.account_request_framework import control_tower_param_changed from aft_common.account_request_record_handler import AccountRequestRecordHandler +from aft_common.aft_utils import sanitize_input_for_logging from aft_common.auth import AuthClient from aft_common.logger import configure_aft_logger -from aft_common.service_catalog import provisioned_product_exists -from aft_common.shared_account import shared_account_request if TYPE_CHECKING: from aws_lambda_powertools.utilities.typing import LambdaContext @@ -27,7 +25,7 @@ def lambda_handler(event: Dict[str, Any], context: LambdaContext) -> None: auth = AuthClient() try: record_handler = AccountRequestRecordHandler(auth=auth, event=event) - logger.info(record_handler.record) + logger.info(sanitize_input_for_logging(record_handler.record)) record_handler.process_request() except Exception as error: diff --git a/src/aft_lambda/aft_account_request_framework/aft_account_request_audit_trigger.py b/src/aft_lambda/aft_account_request_framework/aft_account_request_audit_trigger.py index ead7fad3..ff534d35 100644 --- a/src/aft_lambda/aft_account_request_framework/aft_account_request_audit_trigger.py +++ b/src/aft_lambda/aft_account_request_framework/aft_account_request_audit_trigger.py @@ -9,6 +9,7 @@ from aft_common import constants as utils from aft_common import notifications, ssm from aft_common.account_request_framework import put_audit_record +from aft_common.aft_utils import sanitize_input_for_logging from aft_common.logger import configure_aft_logger from boto3.session import Session @@ -52,7 +53,9 @@ def lambda_handler(event: Dict[str, Any], context: LambdaContext) -> None: event_name, ) else: - logger.info(f"Event Name: {event_name} is unsupported.") + logger.info( + f"Event Name: {sanitize_input_for_logging(event_name)} is unsupported." + ) else: raise Exception("Non DynamoDB Event Received") else: diff --git a/src/aft_lambda/aft_account_request_framework/aft_cleanup_resources.py b/src/aft_lambda/aft_account_request_framework/aft_cleanup_resources.py index fe36af71..f2f57926 100644 --- a/src/aft_lambda/aft_account_request_framework/aft_cleanup_resources.py +++ b/src/aft_lambda/aft_account_request_framework/aft_cleanup_resources.py @@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, Any, Dict from aft_common import codepipeline, ddb +from aft_common.aft_utils import sanitize_input_for_logging from aft_common.auth import AuthClient from aft_common.constants import SSM_PARAM_AFT_DDB_META_TABLE from aft_common.logger import configure_aft_logger @@ -33,7 +34,9 @@ def lambda_handler(event: Dict[str, Any], context: LambdaContext) -> None: "id" ] # the account email is stored in "id" field - logger.info(f"Beginnning resource cleanup for {account_email}") + logger.info( + f"Beginning resource cleanup for {sanitize_input_for_logging(account_email)}" + ) orgs_agent = OrganizationsAgent( ct_management_session=auth.get_ct_management_session()