diff --git a/.gitignore b/.gitignore index 151454e7..a295c653 100644 --- a/.gitignore +++ b/.gitignore @@ -508,3 +508,13 @@ $RECYCLE.BIN/ **/sra_staging_manual_upload/* **/dist-*/* poetry.lock + +# Ignore packages generated by TF +**/aws_sra_examples/terraform/**/lambda/ +**.terraform +*.tfstate +*.tfstate.* +*.tfvars* +**./terraform +*.hcl + diff --git a/aws_sra_examples/docs/artifacts/terraform-control-tower-process.png b/aws_sra_examples/docs/artifacts/terraform-control-tower-process.png new file mode 100644 index 00000000..dbbf8a58 Binary files /dev/null and b/aws_sra_examples/docs/artifacts/terraform-control-tower-process.png differ diff --git a/aws_sra_examples/docs/artifacts/terraform-process.png b/aws_sra_examples/docs/artifacts/terraform-process.png new file mode 100644 index 00000000..aae1c0e0 Binary files /dev/null and b/aws_sra_examples/docs/artifacts/terraform-process.png differ diff --git a/aws_sra_examples/docs/artifacts/where-to-start-process.pptx b/aws_sra_examples/docs/artifacts/where-to-start-process.pptx index 01534d0a..eb0354e8 100644 Binary files a/aws_sra_examples/docs/artifacts/where-to-start-process.pptx and b/aws_sra_examples/docs/artifacts/where-to-start-process.pptx differ diff --git a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/documentation/sra-cloudtrail-org-terraform.png b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/documentation/sra-cloudtrail-org-terraform.png new file mode 100644 index 00000000..4967cd4f Binary files /dev/null and b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/documentation/sra-cloudtrail-org-terraform.png differ diff --git a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/documentation/sra-cloudtrail-org.pptx b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/documentation/sra-cloudtrail-org.pptx index e4d38f5b..590b2744 100644 Binary files a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/documentation/sra-cloudtrail-org.pptx and b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/documentation/sra-cloudtrail-org.pptx differ diff --git a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/lambda/src/app.py b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/lambda/src/app.py index d8ab1c85..59271b40 100644 --- a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/lambda/src/app.py +++ b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/lambda/src/app.py @@ -358,3 +358,21 @@ def lambda_handler(event: CloudFormationCustomResourceEvent, context: Context) - except Exception: LOGGER.exception(UNEXPECTED) raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None + + +def terraform_handler(event: CloudFormationCustomResourceEvent, context: Context) -> None: + """Lambda Handler. + + Args: + event: event data + context: runtime information + + Raises: + ValueError: Unexpected error executing Lambda function + + """ + try: + process_event(event, context) + except Exception: + LOGGER.exception(UNEXPECTED) + raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None diff --git a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-bucket.yaml b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-bucket.yaml index 5a788d88..86b802d0 100644 --- a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-bucket.yaml +++ b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-bucket.yaml @@ -227,7 +227,7 @@ Resources: Properties: Name: sra/cloudtrail_org_s3_bucket Description: Organization CloudTrail S3 Bucket - SecretString: !Sub '{"OrganizationCloudTrailS3Bucket":"${rOrgTrailBucket}"}' # checkov:skip=CKV_SECRET_6 + SecretString: !Sub '{"OrganizationCloudTrailS3Bucket":"${rOrgTrailBucket}"}' # checkov:skip=CKV_SECRET_6 KmsKeyId: !Ref pSRASecretsKeyAliasArn Tags: - Key: sra-solution diff --git a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-kms.yaml b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-kms.yaml index 142389b5..70e39996 100644 --- a/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-kms.yaml +++ b/aws_sra_examples/solutions/cloudtrail/cloudtrail_org/templates/sra-cloudtrail-org-kms.yaml @@ -160,7 +160,7 @@ Resources: Properties: Name: sra/cloudtrail_org_key_arn Description: Organization CloudTrail KMS Key ARN - SecretString: !Sub '{"OrganizationCloudTrailKeyArn":"${rOrganizationCloudTrailKey.Arn}"}' # checkov:skip=CKV_SECRET_6 + SecretString: !Sub '{"OrganizationCloudTrailKeyArn":"${rOrganizationCloudTrailKey.Arn}"}' # checkov:skip=CKV_SECRET_6 KmsKeyId: !Ref pSRASecretsKeyAliasArn Tags: - Key: sra-solution diff --git a/aws_sra_examples/solutions/common/common_prerequisites/documentation/common-prerequisites.pptx b/aws_sra_examples/solutions/common/common_prerequisites/documentation/common-prerequisites.pptx index c4eab14d..d17e309e 100644 Binary files a/aws_sra_examples/solutions/common/common_prerequisites/documentation/common-prerequisites.pptx and b/aws_sra_examples/solutions/common/common_prerequisites/documentation/common-prerequisites.pptx differ diff --git a/aws_sra_examples/solutions/common/common_prerequisites/documentation/terraform-common-prerequisites.png b/aws_sra_examples/solutions/common/common_prerequisites/documentation/terraform-common-prerequisites.png new file mode 100644 index 00000000..0a74501c Binary files /dev/null and b/aws_sra_examples/solutions/common/common_prerequisites/documentation/terraform-common-prerequisites.png differ diff --git a/aws_sra_examples/solutions/common/common_prerequisites/lambda/src/app.py b/aws_sra_examples/solutions/common/common_prerequisites/lambda/src/app.py index 2cb967ba..bc3faa76 100644 --- a/aws_sra_examples/solutions/common/common_prerequisites/lambda/src/app.py +++ b/aws_sra_examples/solutions/common/common_prerequisites/lambda/src/app.py @@ -494,3 +494,25 @@ def lambda_handler(event: CloudFormationCustomResourceEvent, context: Context) - except Exception: LOGGER.exception(UNEXPECTED) raise ValueError(f"See the details in CloudWatch Log Stream: '{context.log_group_name}'") from None + + +def terraform_handler(event: dict, context: Context) -> dict: + """Lambda Handler. + + Args: + event: event data + context: runtime information + + Raises: + ValueError: Unexpected error executing Lambda function + + Returns: + dict: status code + """ + try: + create_update_event(event, context) + response = {"event": event, "statusCode": 200} + return response + except Exception as error_msg: + LOGGER.exception(UNEXPECTED) + raise ValueError(f"See the details in CloudWatch Log Stream: '{context.log_group_name}' Error Message: {error_msg}") from None diff --git a/aws_sra_examples/solutions/common/common_register_delegated_administrator/documentation/sra-common-register-delegated-administrator-terraform.png b/aws_sra_examples/solutions/common/common_register_delegated_administrator/documentation/sra-common-register-delegated-administrator-terraform.png new file mode 100644 index 00000000..44179051 Binary files /dev/null and b/aws_sra_examples/solutions/common/common_register_delegated_administrator/documentation/sra-common-register-delegated-administrator-terraform.png differ diff --git a/aws_sra_examples/solutions/common/common_register_delegated_administrator/documentation/sra-common-register-delegated-administrator.pptx b/aws_sra_examples/solutions/common/common_register_delegated_administrator/documentation/sra-common-register-delegated-administrator.pptx index 65c0a541..3846d14a 100644 Binary files a/aws_sra_examples/solutions/common/common_register_delegated_administrator/documentation/sra-common-register-delegated-administrator.pptx and b/aws_sra_examples/solutions/common/common_register_delegated_administrator/documentation/sra-common-register-delegated-administrator.pptx differ diff --git a/aws_sra_examples/solutions/common/common_register_delegated_administrator/lambda/src/app.py b/aws_sra_examples/solutions/common/common_register_delegated_administrator/lambda/src/app.py index 38ff9516..f7cc4659 100644 --- a/aws_sra_examples/solutions/common/common_register_delegated_administrator/lambda/src/app.py +++ b/aws_sra_examples/solutions/common/common_register_delegated_administrator/lambda/src/app.py @@ -263,3 +263,28 @@ def lambda_handler( except Exception: LOGGER.exception(UNEXPECTED) raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None + + +def terraform_handler(event: dict, context: Context) -> None: + """Lambda Handler. + + Args: + event: event data + context: runtime information + + Raises: + ValueError: Unexpected error executing Lambda function + """ + LOGGER.info("....Lambda Handler Started....") + event_info = {"Event": event} + LOGGER.info(event_info) + try: + request_type = event["RequestType"] + + if request_type == "Create": + create(event, context) + elif request_type == "Delete": + delete(event, context) + except Exception: + LOGGER.exception(UNEXPECTED) + raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-kms-key.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-kms-key.yaml index d34d3f96..2b4806d7 100644 --- a/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-kms-key.yaml +++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-kms-key.yaml @@ -142,7 +142,7 @@ Resources: Properties: Name: sra/config_org_delivery_key_arn Description: Config Delivery KMS Key ARN - SecretString: !Sub '{"ConfigDeliveryKeyArn":"${rConfigDeliveryKey.Arn}"}' # checkov:skip=CKV_SECRET_6 + SecretString: !Sub '{"ConfigDeliveryKeyArn":"${rConfigDeliveryKey.Arn}"}' # checkov:skip=CKV_SECRET_6 KmsKeyId: !Ref pSRASecretsKeyAliasArn Tags: - Key: sra-solution diff --git a/aws_sra_examples/solutions/guardduty/guardduty_org/documentation/guardduty-org-terraform.png b/aws_sra_examples/solutions/guardduty/guardduty_org/documentation/guardduty-org-terraform.png new file mode 100644 index 00000000..9a9f4a14 Binary files /dev/null and b/aws_sra_examples/solutions/guardduty/guardduty_org/documentation/guardduty-org-terraform.png differ diff --git a/aws_sra_examples/solutions/guardduty/guardduty_org/documentation/guardduty-org.pptx b/aws_sra_examples/solutions/guardduty/guardduty_org/documentation/guardduty-org.pptx index c6b96116..508a6ae3 100644 Binary files a/aws_sra_examples/solutions/guardduty/guardduty_org/documentation/guardduty-org.pptx and b/aws_sra_examples/solutions/guardduty/guardduty_org/documentation/guardduty-org.pptx differ diff --git a/aws_sra_examples/solutions/guardduty/guardduty_org/lambda/src/app.py b/aws_sra_examples/solutions/guardduty/guardduty_org/lambda/src/app.py index 9c5f7750..9c8bee17 100644 --- a/aws_sra_examples/solutions/guardduty/guardduty_org/lambda/src/app.py +++ b/aws_sra_examples/solutions/guardduty/guardduty_org/lambda/src/app.py @@ -302,3 +302,30 @@ def lambda_handler(event: Dict[str, Any], context: Context) -> None: except Exception: LOGGER.exception(UNEXPECTED) raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None + + +def terraform_handler(event: Dict[str, Any], context: Context) -> None: + """Lambda Handler. + + Args: + event: event data + context: runtime information + + Raises: + ValueError: Unexpected error executing Lambda function + """ + LOGGER.info("....Lambda Handler Started....") + event_info = {"Event": event} + LOGGER.info(event_info) + try: + if "Records" not in event and "RequestType" not in event and ("source" not in event and event["source"] != "aws.controltower"): + raise ValueError( + f"The event did not include Records or RequestType. Review CloudWatch logs '{context.log_group_name}' for details." + ) from None + elif "Records" in event and event["Records"][0]["EventSource"] == "aws:sns": + process_sns_records(event["Records"]) + elif "RequestType" in event: + process_cloudformation_event(event, context) + except Exception: + LOGGER.exception(UNEXPECTED) + raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None diff --git a/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-delivery-kms-key.yaml b/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-delivery-kms-key.yaml index a22367b2..eaf62beb 100644 --- a/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-delivery-kms-key.yaml +++ b/aws_sra_examples/solutions/guardduty/guardduty_org/templates/sra-guardduty-org-delivery-kms-key.yaml @@ -142,7 +142,7 @@ Resources: Properties: Name: sra/guardduty_org_delivery_key_arn Description: GuardDuty Delivery KMS Key ARN - SecretString: !Sub '{"GuardDutyDeliveryKeyArn":"${rGuardDutyDeliveryKey.Arn}"}' # checkov:skip=CKV_SECRET_6 + SecretString: !Sub '{"GuardDutyDeliveryKeyArn":"${rGuardDutyDeliveryKey.Arn}"}' # checkov:skip=CKV_SECRET_6 KmsKeyId: !Ref pSRASecretsKeyAliasArn Tags: - Key: sra-solution diff --git a/aws_sra_examples/solutions/iam/iam_access_analyzer/documentation/iam-access-analyzer-terraform.png b/aws_sra_examples/solutions/iam/iam_access_analyzer/documentation/iam-access-analyzer-terraform.png new file mode 100644 index 00000000..f0e77e7e Binary files /dev/null and b/aws_sra_examples/solutions/iam/iam_access_analyzer/documentation/iam-access-analyzer-terraform.png differ diff --git a/aws_sra_examples/solutions/iam/iam_access_analyzer/documentation/iam-access-analyzer.pptx b/aws_sra_examples/solutions/iam/iam_access_analyzer/documentation/iam-access-analyzer.pptx index 47807efb..cb610ba7 100644 Binary files a/aws_sra_examples/solutions/iam/iam_access_analyzer/documentation/iam-access-analyzer.pptx and b/aws_sra_examples/solutions/iam/iam_access_analyzer/documentation/iam-access-analyzer.pptx differ diff --git a/aws_sra_examples/solutions/iam/iam_password_policy/documentation/iam-password-policy-terraform.png b/aws_sra_examples/solutions/iam/iam_password_policy/documentation/iam-password-policy-terraform.png new file mode 100644 index 00000000..81f86555 Binary files /dev/null and b/aws_sra_examples/solutions/iam/iam_password_policy/documentation/iam-password-policy-terraform.png differ diff --git a/aws_sra_examples/solutions/iam/iam_password_policy/documentation/iam-password-policy.pptx b/aws_sra_examples/solutions/iam/iam_password_policy/documentation/iam-password-policy.pptx index ffeaa25d..a1a92694 100644 Binary files a/aws_sra_examples/solutions/iam/iam_password_policy/documentation/iam-password-policy.pptx and b/aws_sra_examples/solutions/iam/iam_password_policy/documentation/iam-password-policy.pptx differ diff --git a/aws_sra_examples/solutions/iam/iam_password_policy/lambda/src/app.py b/aws_sra_examples/solutions/iam/iam_password_policy/lambda/src/app.py index 9c1ca976..0fb8f471 100644 --- a/aws_sra_examples/solutions/iam/iam_password_policy/lambda/src/app.py +++ b/aws_sra_examples/solutions/iam/iam_password_policy/lambda/src/app.py @@ -153,7 +153,10 @@ def lambda_handler(event: CloudFormationCustomResourceEvent, context: Context) - """ try: - helper(event, context) + if event.get("ResourceType") == "Terraform": + process_cloudformation_event(event, context) + else: + helper(event, context) except Exception: LOGGER.exception(UNEXPECTED) raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None diff --git a/aws_sra_examples/solutions/inspector/inspector_org/documentation/inspector-org-terraform.png b/aws_sra_examples/solutions/inspector/inspector_org/documentation/inspector-org-terraform.png new file mode 100644 index 00000000..ac718975 Binary files /dev/null and b/aws_sra_examples/solutions/inspector/inspector_org/documentation/inspector-org-terraform.png differ diff --git a/aws_sra_examples/solutions/inspector/inspector_org/documentation/inspector-org.pptx b/aws_sra_examples/solutions/inspector/inspector_org/documentation/inspector-org.pptx index 8a89a387..1f3663d5 100644 Binary files a/aws_sra_examples/solutions/inspector/inspector_org/documentation/inspector-org.pptx and b/aws_sra_examples/solutions/inspector/inspector_org/documentation/inspector-org.pptx differ diff --git a/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/app.py b/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/app.py index 30fa87c9..d12107af 100644 --- a/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/app.py +++ b/aws_sra_examples/solutions/inspector/inspector_org/lambda/src/app.py @@ -88,8 +88,14 @@ def process_event(event: dict) -> None: excluded_accounts: list = [params["DELEGATED_ADMIN_ACCOUNT_ID"]] accounts = common.get_active_organization_accounts(excluded_accounts) regions = common.get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"] == "true") - - process_add_update_event(params, regions, accounts) + if event.get("ResourceType") == "Terraform" and event.get("tf", {}).get("action") == "delete": + LOGGER.info("...Disable Inspector from Terraform") + disabled_inspector_service(params, regions) + elif event.get("RequestType") == "Delete": + LOGGER.info("...Disable Inspector via process_event") + disabled_inspector_service(params, regions) + else: + process_add_update_event(params, regions, accounts) def parameter_pattern_validator(parameter_name: str, parameter_value: Optional[str], pattern: str, is_optional: bool = False) -> dict: @@ -314,10 +320,14 @@ def disabled_inspector_service(params: dict, regions: list) -> None: params: Configuration Parameters regions: list of regions """ + scan_components = params["SCAN_COMPONENTS"].split(",") LOGGER.info("Remove inspector") - LOGGER.info(f"disabled_inspector_service: ALL_INSPECTOR_SCAN_COMPONENTS as ({ALL_INSPECTOR_SCAN_COMPONENTS})") + LOGGER.info(f"disabled_inspector_service: scan_components as ({scan_components})") inspector.disable_inspector_in_associated_member_accounts( - params["DELEGATED_ADMIN_ACCOUNT_ID"], params["CONFIGURATION_ROLE_NAME"], regions, ALL_INSPECTOR_SCAN_COMPONENTS + params["DELEGATED_ADMIN_ACCOUNT_ID"], + params["CONFIGURATION_ROLE_NAME"], + regions, + scan_components, ) inspector.disable_auto_scanning_in_org(params["DELEGATED_ADMIN_ACCOUNT_ID"], params["CONFIGURATION_ROLE_NAME"], regions) @@ -329,7 +339,8 @@ def disabled_inspector_service(params: dict, regions: list) -> None: params["CONFIGURATION_ROLE_NAME"], params["MANAGEMENT_ACCOUNT_ID"], params["DELEGATED_ADMIN_ACCOUNT_ID"], - ALL_INSPECTOR_SCAN_COMPONENTS, + # ALL_INSPECTOR_SCAN_COMPONENTS, + scan_components, ) deregister_delegated_administrator(params["DELEGATED_ADMIN_ACCOUNT_ID"], SERVICE_NAME) @@ -540,8 +551,12 @@ def orchestrator(event: Dict[str, Any], context: Any) -> None: context: runtime information """ if event.get("RequestType"): - LOGGER.info("...calling helper...") - helper(event, context) + if event.get("ResourceType") and event["ResourceType"] == "Terraform": + LOGGER.info("...calling process_event from Terraform...") + process_event(event) + else: + LOGGER.info("...calling helper...") + helper(event, context) elif event.get("Records") and event["Records"][0]["EventSource"] == "aws:sns": LOGGER.info("...aws:sns record...") process_event_sns(event) diff --git a/aws_sra_examples/solutions/macie/macie_org/documentation/macie-org-terraform.png b/aws_sra_examples/solutions/macie/macie_org/documentation/macie-org-terraform.png new file mode 100644 index 00000000..fbfb3805 Binary files /dev/null and b/aws_sra_examples/solutions/macie/macie_org/documentation/macie-org-terraform.png differ diff --git a/aws_sra_examples/solutions/macie/macie_org/documentation/macie-org.pptx b/aws_sra_examples/solutions/macie/macie_org/documentation/macie-org.pptx index 7d390606..c0b6b172 100644 Binary files a/aws_sra_examples/solutions/macie/macie_org/documentation/macie-org.pptx and b/aws_sra_examples/solutions/macie/macie_org/documentation/macie-org.pptx differ diff --git a/aws_sra_examples/solutions/macie/macie_org/lambda/src/app.py b/aws_sra_examples/solutions/macie/macie_org/lambda/src/app.py index aa08f3ac..c51d432e 100644 --- a/aws_sra_examples/solutions/macie/macie_org/lambda/src/app.py +++ b/aws_sra_examples/solutions/macie/macie_org/lambda/src/app.py @@ -220,3 +220,30 @@ def lambda_handler(event: Dict[str, Any], context: Context) -> None: except Exception: LOGGER.exception(UNEXPECTED) raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None + + +def terraform_handler(event: Dict[str, Any], context: Context) -> None: + """Lambda Handler. + + Args: + event: event data + context: runtime information + + Raises: + ValueError: Unexpected error executing Lambda function + """ + LOGGER.info("....Terraform Lambda Handler Started....") + event_info = {"Event": event} + LOGGER.info(event_info) + try: + if "Records" not in event and "RequestType" not in event and ("source" not in event and event["source"] != "aws.controltower"): + raise ValueError( + f"The event did not include Records, RequestType, or source. Review CloudWatch logs '{context.log_group_name}' for details." + ) from None + elif "Records" in event and event["Records"][0]["EventSource"] == "aws:sns": + process_sns_records(event["Records"]) + elif "RequestType" in event: + process_cloudformation_event(event, context) + except Exception: + LOGGER.exception(UNEXPECTED) + raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None diff --git a/aws_sra_examples/solutions/macie/macie_org/templates/sra-macie-org-delivery-kms-key.yaml b/aws_sra_examples/solutions/macie/macie_org/templates/sra-macie-org-delivery-kms-key.yaml index 3fc79e6f..2a810a16 100644 --- a/aws_sra_examples/solutions/macie/macie_org/templates/sra-macie-org-delivery-kms-key.yaml +++ b/aws_sra_examples/solutions/macie/macie_org/templates/sra-macie-org-delivery-kms-key.yaml @@ -148,7 +148,7 @@ Resources: Properties: Name: sra/macie_org_delivery_key_arn Description: Macie Delivery KMS Key ARN - SecretString: !Sub '{"MacieOrgDeliveryKeyArn":"${rMacieOrgDeliveryKey.Arn}"}' # checkov:skip=CKV_SECRET_6 + SecretString: !Sub '{"MacieOrgDeliveryKeyArn":"${rMacieOrgDeliveryKey.Arn}"}' # checkov:skip=CKV_SECRET_6 KmsKeyId: !Ref pSRASecretsKeyAliasArn Tags: - Key: sra-solution diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org-terraform.png b/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org-terraform.png new file mode 100644 index 00000000..5e047023 Binary files /dev/null and b/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org-terraform.png differ diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.pptx b/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.pptx index c567c2de..c5309db1 100644 Binary files a/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.pptx and b/aws_sra_examples/solutions/securityhub/securityhub_org/documentation/securityhub-org.pptx differ diff --git a/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/app.py b/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/app.py index 07d21520..6e175a3d 100644 --- a/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/app.py +++ b/aws_sra_examples/solutions/securityhub/securityhub_org/lambda/src/app.py @@ -436,3 +436,34 @@ def lambda_handler(event: Dict[str, Any], context: Any) -> None: except Exception: LOGGER.exception(UNEXPECTED) raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None + + +def terraform_handler(event: Dict[str, Any], context: Context) -> None: + """Lambda Handler. + + Args: + event: event data + context: runtime information + + Raises: + ValueError: Unexpected error executing Lambda function + """ + LOGGER.info("....Lambda Handler Started....") + event_info = {"Event": event} + LOGGER.info(event_info) + try: + if "Records" not in event and "RequestType" not in event and ("source" not in event and event["source"] != "aws.controltower"): + raise ValueError( + f"The event did not include Records or RequestType. Review CloudWatch logs '{context.log_group_name}' for details." + ) from None + elif event.get("source") == "aws.controltower": + process_event_lifecycle(event) + elif event.get("source") == "aws.organizations": + process_event_organizations(event) + elif event.get("Records") and event["Records"][0]["EventSource"] == "aws:sns": + process_event_sns(event) + else: + process_event(event) + except Exception: + LOGGER.exception(UNEXPECTED) + raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs '{context.log_group_name}' for details.") from None diff --git a/aws_sra_examples/terraform/README.md b/aws_sra_examples/terraform/README.md new file mode 100644 index 00000000..06e11eb2 --- /dev/null +++ b/aws_sra_examples/terraform/README.md @@ -0,0 +1,151 @@ +# SRA Terraform Edition + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + +## Table of Contents + +- [Introduction](#introduction) +- [Prerequisites](#prerequisites) +- [Getting Started Using AWS SRA with Terraform and AWS Control Tower](#getting-started-using-aws-sra-with-terraform-and-aws-control-tower) +- [Getting Started Using AWS SRA with Terraform and AWS Organizations](#getting-started-using-aws-sra-with-terraform-and-aws-organizations) +- [Implementation Instructions](#implementation-instructions) + - [Installing the AWS SRA Common Pre-Requisite Solution](#installing-the-aws-sra-common-pre-requisite-solution) + - [Installing the AWS SRA Solutions](#installing-the-aws-sra-solutions) + - [Updating and removing the AWS SRA Solutions](#updating-and-removing-the-aws-sra-solutions) +- [Available solutions](#available-solutions) + +## Introduction + +The AWS Security Reference Architecture (SRA) code library, a comprehensive public code repository, offers a suite of example code designed to help organizations implement robust security controls within their AWS environments. Recognizing the increasing complexity and evolving security requirements of cloud infrastructures, AWS has expanded the accessibility and usability of the SRA by enabling deployment through Terraform. This integration marks a significant advancement, providing developers and cloud engineers with a more flexible and efficient method to enforce security best practices and configurations directly into their AWS cloud environments. + +The SRA Terraform edition was driven by valuable customer feedback, highlighting a strong demand for more versatile and automation-friendly options to apply AWS’s security guidance. Customers expressed a need for tools that could seamlessly integrate into their existing Infrastructure as Code (IaC) workflows, allowing for a more streamlined and scalable approach to cloud security. By building the code to deploy SRA via Terraform, AWS responds to this need, empowering users to deploy the Security Reference Architecture with ease and precision tailored to their specific needs. This development not only enhances security posture management but also aligns with the dynamic and automated nature of cloud computing, ensuring that AWS users have the necessary resources to protect their environments effectively. + +## Prerequisites + +- Terraform version >= 1.0 +- Clone the SRA code library github repository + +## Getting Started Using AWS SRA with Terraform and AWS Control Tower + +![How to get started with the terraform process in AWS Control Tower diagram](../docs/artifacts/terraform-control-tower-process.png) + +1. Setup the environment to configure [AWS Control Tower](https://docs.aws.amazon.com/controltower/latest/userguide/getting-started-with-control-tower.html) within a new or existing AWS account. Existing AWS Control Tower environments can also be + used but may require existing service configurations to be removed. + - NOTE: The `aws_sra_examples/terraform/common/variables.tf` file, by default, should be setup already with the proper values for a control tower environment. So, it should not need to be modified for this deployment. +2. Deploy the common prerequisites using Terraform (command line) + - See [Installaing the AWS Common Pre-Requisite Solution](#installaing-the-aws-common-pre-requisite-solution) below. +3. Deploy solutions using Terraform (command line) + - See [Installing the AWS SRA Solutions](#installing-the-aws-sra-solutions) below. + + +## Getting Started Using AWS SRA with Terraform and AWS Organizations + +![How to get started with the terraform process in AWS Organizations diagram](../docs/artifacts/terraform-process.png) + +1. Setup the environment to configure [AWS Organizations](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_getting-started.html) within a new or existing AWS account. Existing AWS Organizations environments can also be used but may + require existing service configurations to be removed. + - The `Security Tooling` and `Log Archive` accounts must be created or already be part of the existing AWS Organizations environment (though they may be named differently in your environment). + - It is recommended that the OU structure is setup in alignment with the [AWS SRA design guidance](https://docs.aws.amazon.com/prescriptive-guidance/latest/security-reference-architecture/architecture.html) +2. Deploy the common prerequisites using Terraform (command line) + - Edit the `aws_sra_examples/terraform/common/variables.tf` or pass in the variables in the command-line. + - The `control_tower` variable must be `"false"` + - The `governed_regions` variable must be set for the environments regions + - The `security_account_id` variable must be set to the security tooling account Id + - The `log_archive_account_id` variable must be set to the log archive account Id + - See [Installaing the AWS Common Pre-Requisite Solution](#installaing-the-aws-common-pre-requisite-solution) below. +3. Deploy solutions using Terraform (command line) + - See [Installing the AWS SRA Solutions](#installing-the-aws-sra-solutions) below. + +## Implementation Instructions + +### Installing the AWS SRA Common Pre-Requisite Solution + +This will install the common pre-requisites solution including lambda and SSM parameter resources into your environment for usage by other AWS SRA solutions in its code library. + +1. From the location where the SRA code library was cloned to, change to the `./aws_sra_examples/terraform/common` folder +```bash +cd aws_sra_examples/terraform/common +``` +2. Run terraform init +```bash +terraform init +``` +3. Run terraform plan (this is optional to review before applying) +```bash +terraform plan +``` +4. Run terraform apply +```bash +terraform apply +``` + +After the apply operation is complete, Terraform will have created two files in your `./aws_sra_examples/terraform/solutions` folder: `backend.tfvars` and `config.tfvars` + +### Installing the AWS SRA Solutions + +1. From the location where the SRA code library was cloned to, change to the ./aws_sra_examples/terraform/common folder +```bash +cd aws_sra_examples/terraform/solutions +``` +2. Edit the `aws_sra_examples/terraform/solutions/config.tfvars` file, choose which AWS SRA Solutions to deploy and their settings. This can be done during initial setup or as an update later but nothing will be done unless at least one solution is set to be deployed. + +#### Deployment To All Accounts and Governed Regions + +Inside the `aws_sra_examples/terraform/solutions` directory is a python script, `terraform_stack.py`, that handles the deployment of all resources and configurations to all accounts and all specified governed regions. + +1. Run terraform init using `terraform_stack.py` script +```bash +python3 terraform_stack.py init +``` +2. Run terraform plan using `terraform_stack.py` script (this is optional to review before applying) +```bash +python3 terraform_stack.py plan +``` +3. Run terraform apply using `terraform_stack.py` script +```bash +python3 terraform_stack.py apply +``` + +### Updating and removing the AWS SRA Solutions + +#### Solution Update Instructions + +1. Edit the `aws_sra_examples/terraform/solutions/config.tfvars` file and change the variable for the updated setting. (e.g. update the AWS SRA security hub solution that was previously deployed to enable the NIST standard by changing the `enable_nist_standard variable` setting to `true`) +2. Run terraform apply using `terraform_stack.py` script from inside the `aws_sra_examples/terraform/solutions` directory +```bash +python3 terraform_stack.py apply +``` + +#### Solution Delete Instructions + +1. Edit the `aws_sra_examples/terraform/solutions/config.tfvars` file and change the disable variable for the solutions being removed. (e.g. update the AWS SRA guardduty solution that was previously deployed to disable itself by changing the `disable_guard_duty` setting to `true`) + +2. Run terraform apply using `terraform_stack.py` script from inside the `aws_sra_examples/terraform/solutions` directory +```bash +python3 terraform_stack.py apply +``` +3. Edit the `aws_sra_examples/terraform/solutions/config.tfvars` file and change the deployment (enable) variable for the solutions being removed. (e.g. update the `config.tfvars` file by setting the `enable_gd` setting to `false`) +4. Run terraform apply using `terraform_stack.py` script from inside the `aws_sra_examples/terraform/solutions` directory +```bash +python3 terraform_stack.py apply +``` + +## Available solutions +This is a list of the currently available AWS SRA solutions in the terraform edition. +| Solution | +| ------------------------------------------------------------------------------------------ | +| [CloudTrail](./solutions/cloudtrail_org/README.md) | +| [IAM Access Analyzer](./solutions/iam_access_analyzer/README.md) | +| [IAM Password Policy](./solutions/iam_password_policy/README.md) | +| [Inspector](./solutions/inspector/README.md) | +| [Macie](./solutions/macie/README.md) | +| [GuardDuty](./solutions/guard_duty/README.md) | +| [Security Hub](./solutions/security_hub/recorder_start_event/data.tf) | +| [Register Delegated Administrator](./solutions/register_delegated_administrator/README.md) | diff --git a/aws_sra_examples/terraform/common/README.md b/aws_sra_examples/terraform/common/README.md new file mode 100644 index 00000000..a3fe491f --- /dev/null +++ b/aws_sra_examples/terraform/common/README.md @@ -0,0 +1,176 @@ +# AWS SRA Common Pre-Requisites Solution with Terraform + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + + +## Introduction + +This will install the common pre-requisites solution including lambda and SSM parameter resources into your environment for usage by other AWS SRA solutions in its code library. + +This must be installed, in the management account, prior to installing and of the other AWS SRA solutions. + +Information on the resources deployed as well as terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA common pre-requisite solution](./../../terraform#installing-the-aws-sra-common-pre-requisite-solution) section of the documentation for more information and installation instructions. + +## Table of Contents +- [Introduction](#introduction) +- [Deployed Resource Details](#deployed-resource-details) +- [Requirements](#requirements) +- [Providers](#providers) +- [Modules](#modules) +- [Resources](#resources) +- [Inputs](#inputs) +- [Outputs](#outputs) + +## Deployed Resource Details + +![Architecture](./../../solutions/common/common_prerequisites/documentation/terraform-common-prerequisites.png) + +Note: Many links in this documentation navigate back to the CloudFormation edition of the AWS SRA code library as reference. Be sure to navigate back to the Terraform edition of the AWS SRA code library documentation for the Terraform-specific information. + +### 1.0 Organization Management Account + +#### 1.1 Hashicorp Terraform + +- Resources are deployed via Hashicorp Terraform within the management account. + +#### 1.2 Org ID AWS Lambda IAM Role + +- See [1.2 Org ID AWS Lambda IAM Role](./../../solutions/common/common_prerequisites#12-org-id-aws-lambda-iam-role) + +#### 1.3 Org ID AWS Lambda Function + +- See [1.3 Org ID AWS Lambda Function](./../../solutions/common/common_prerequisites#13-org-id-aws-lambda-function) + +#### 1.4 AWS Lambda CloudWatch Log Group + +- See [1.4 AWS Lambda CloudWatch Log Group](./../../solutions/common/common_prerequisites#14-aws-lambda-cloudwatch-log-group) + +#### 1.5 AWS SSM Parameter Store + +- See [1.5 AWS SSM Parameter Store](./../../solutions/common/common_prerequisites#15-aws-ssm-parameter-store) + +#### 1.6 Terraform State S3 Bucket + +- The S3 Bucket is used to store the Terraform state information. + +#### 1.7 Parameter AWS Lambda IAM Role + +- See [1.7 Parameter AWS Lambda IAM Role](./../../solutions/common/common_prerequisites#17-parameter-aws-lambda-iam-role) + +#### 1.8 Parameter AWS Lambda Function + +- See [1.8 Parameter AWS Lambda Function](./../../solutions/common/common_prerequisites#18-parameter-aws-lambda-function) + +#### 1.9 AWS Lambda CloudWatch Log Group + +- See [1.9 AWS Lambda CloudWatch Log Group](./../../solutions/common/common_prerequisites#19-aws-lambda-cloudwatch-log-group) + +#### 1.10 AWS CloudFormation + +- CloudFormation is used to create a stackset to deploy the [1.11 SRA Execution Role](#111-sra-execution-role) to all accounts in the organization. + +#### 1.11 SRA Execution Role + +- See [1.11 SRA Execution Role](./../../solutions/common/common_prerequisites#111-sra-execution-role) + +#### 1.12 AWS SSM Parameter Store + +- See [1.5 AWS SSM Parameter Store](#15-aws-ssm-parameter-store) + +### 2.0 All Existing and Future Organization Member Accounts + +#### 2.1 AWS CloudFormation + +- See [1.10 AWS CloudFormation](#110-aws-cloudformation) + +#### 2.2 AWS SSM Parameter Store + +- See [1.5 AWS SSM Parameter Store](#15-aws-ssm-parameter-store) + +#### 2.4 SRA Execution Role + +- See [1.11 SRA Execution Role](#111-sra-execution-role) + +### 3.0 Audit (Security Tooling) Account + +#### 3.1 AWS CloudFormation + +- See [1.10 AWS CloudFormation](#110-aws-cloudformation) + +#### 3.2 SRA Secrets KMS Key + +- See [3.2 SRA Secrets KMS Key](./../../solutions/common/common_prerequisites#32-sra-secrets-kms-key) + +#### 3.3 SRA Execution Role + +- See [1.11 SRA Execution Role](#111-sra-execution-role) + + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 5.1.0 | +| [local](#provider\_local) | n/a | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [dynamo\_tf\_lock](#module\_dynamo\_tf\_lock) | ./dynamodb | n/a | +| [mangement\_account\_parameters](#module\_mangement\_account\_parameters) | ./ssm_parameters | n/a | +| [s3\_state\_bucket](#module\_s3\_state\_bucket) | ./s3 | n/a | +| [sra\_execution\_role](#module\_sra\_execution\_role) | ./sra_execution_role | n/a | +| [sra\_secrets\_kms](#module\_sra\_secrets\_kms) | ./secrets_kms | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_cloudformation_stack_set.sra_execution_role_stackset](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudformation_stack_set) | resource | +| [aws_cloudformation_stack_set_instance.sra_execution_role_stackset_instance](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudformation_stack_set_instance) | resource | +| [local_file.backend_file_creation](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [local_file.config_file_creation](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_ssm_parameter.audit_account_id](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.customer_control_tower_regions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.customer_control_tower_regions_without_home_region](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.enabled_regions](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.enabled_regions_without_home_region](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.home_region](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.log_archive_account_id](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.management_account_id](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.organization_id](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | +| [aws_ssm_parameter.root_organizational_unit_id](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aws\_partition](#input\_aws\_partition) | AWS Partition (e.g., aws or aws-cn) | `string` | `"aws"` | no | +| [control\_tower](#input\_control\_tower) | AWS Control Tower landing zone deployed/in-use | `string` | `"true"` | no | +| [execution\_role\_name](#input\_execution\_role\_name) | Name of the SRA execution role | `string` | `"sra-execution"` | no | +| [governed\_regions](#input\_governed\_regions) | AWS regions (comma separated) if not using AWS Control Tower (leave set to ct-regions for AWS Control Tower environments) | `string` | `"ct-regions"` | no | +| [log\_archive\_account\_id](#input\_log\_archive\_account\_id) | Log Archive Account ID | `string` | `"222222222222"` | no | +| [security\_account\_id](#input\_security\_account\_id) | Security Tooling Account ID | `string` | `"111111111111"` | no | +| [solution\_name](#input\_solution\_name) | Name of the SRA solution | `string` | `"sra-create-deployment-roles"` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/data.tf b/aws_sra_examples/terraform/common/data.tf new file mode 100644 index 00000000..497e8600 --- /dev/null +++ b/aws_sra_examples/terraform/common/data.tf @@ -0,0 +1,56 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_caller_identity" "current" {} + +data "aws_ssm_parameter" "customer_control_tower_regions" { + depends_on = [module.mangement_account_parameters] + name = "/sra/regions/customer-control-tower-regions" +} + +data "aws_ssm_parameter" "customer_control_tower_regions_without_home_region" { + depends_on = [module.mangement_account_parameters] + name = "/sra/regions/customer-control-tower-regions-without-home-region" +} + +data "aws_ssm_parameter" "enabled_regions" { + depends_on = [module.mangement_account_parameters] + name = "/sra/regions/enabled-regions" +} + +data "aws_ssm_parameter" "enabled_regions_without_home_region" { + depends_on = [module.mangement_account_parameters] + name = "/sra/regions/enabled-regions-without-home-region" +} + +data "aws_ssm_parameter" "home_region" { + depends_on = [module.mangement_account_parameters] + name = "/sra/control-tower/home-region" +} + +data "aws_ssm_parameter" "audit_account_id" { + depends_on = [module.mangement_account_parameters] + name = "/sra/control-tower/audit-account-id" +} + +data "aws_ssm_parameter" "log_archive_account_id" { + depends_on = [module.mangement_account_parameters] + name = "/sra/control-tower/log-archive-account-id" +} + +data "aws_ssm_parameter" "management_account_id" { + depends_on = [module.mangement_account_parameters] + name = "/sra/control-tower/management-account-id" +} + +data "aws_ssm_parameter" "organization_id" { + depends_on = [module.mangement_account_parameters] + name = "/sra/control-tower/organization-id" +} + +data "aws_ssm_parameter" "root_organizational_unit_id" { + depends_on = [module.mangement_account_parameters] + name = "/sra/control-tower/root-organizational-unit-id" +} diff --git a/aws_sra_examples/terraform/common/dynamodb/README-TF.MD b/aws_sra_examples/terraform/common/dynamodb/README-TF.MD new file mode 100644 index 00000000..8d939944 --- /dev/null +++ b/aws_sra_examples/terraform/common/dynamodb/README-TF.MD @@ -0,0 +1,34 @@ + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_dynamodb_table.terraform_locks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/dynamodb_table) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [dynamodb\_name](#input\_dynamodb\_name) | DynamoDB Table Name for state locking | `string` | `"sra-tfstate-lock"` | no | +| [sra\_solution\_name](#input\_sra\_solution\_name) | SRA Solution Name | `string` | `"sra-tfstate-s3"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [dynamo\_db\_table\_name](#output\_dynamo\_db\_table\_name) | n/a | + \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/dynamodb/main.tf b/aws_sra_examples/terraform/common/dynamodb/main.tf new file mode 100644 index 00000000..2b13f467 --- /dev/null +++ b/aws_sra_examples/terraform/common/dynamodb/main.tf @@ -0,0 +1,16 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_dynamodb_table" "terraform_locks" { + #checkov:skip=CKV_AWS_28: Ensure DynamoDB point in time recovery (backup) is enabled + #checkov:skip=CKV_AWS_119: Ensure DynamoDB Tables are encrypted using a KMS Customer Managed CMK + name = var.dynamodb_name + billing_mode = "PAY_PER_REQUEST" + hash_key = "LockID" + attribute { + name = "LockID" + type = "S" + } +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/dynamodb/output.tf b/aws_sra_examples/terraform/common/dynamodb/output.tf new file mode 100644 index 00000000..a86de848 --- /dev/null +++ b/aws_sra_examples/terraform/common/dynamodb/output.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +output dynamo_db_table_name { + value = aws_dynamodb_table.terraform_locks.name +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/dynamodb/variables.tf b/aws_sra_examples/terraform/common/dynamodb/variables.tf new file mode 100644 index 00000000..b9a21bf4 --- /dev/null +++ b/aws_sra_examples/terraform/common/dynamodb/variables.tf @@ -0,0 +1,16 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "dynamodb_name" { + description = "DynamoDB Table Name for state locking" + type = string + default = "sra-tfstate-lock" +} + +variable "sra_solution_name" { + description = "SRA Solution Name" + type = string + default = "sra-tfstate-s3" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/main.tf b/aws_sra_examples/terraform/common/main.tf new file mode 100644 index 00000000..f6988e0f --- /dev/null +++ b/aws_sra_examples/terraform/common/main.tf @@ -0,0 +1,192 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + + +######################################################################## +# Deploy Pre-requisites for Management Account +######################################################################## + +module "mangement_account_parameters" { + source = "./ssm_parameters" + + control_tower = var.control_tower + governed_regions = var.governed_regions + security_account_id = var.security_account_id + log_archive_account_id = var.log_archive_account_id +} + +module "sra_execution_role" { + depends_on = [module.mangement_account_parameters] + source = "./sra_execution_role" + + management_account_id = data.aws_ssm_parameter.management_account_id.value +} + +module "sra_secrets_kms" { + depends_on = [module.mangement_account_parameters] + + source = "./secrets_kms" + + management_account_id = data.aws_ssm_parameter.management_account_id.value + organization_id = data.aws_ssm_parameter.organization_id.value +} + +resource "aws_cloudformation_stack_set" "sra_execution_role_stackset" { + name = "sra-stackset-execution-role" + description = "SRA execution role stackset" + template_body = file("${path.root}/sra_execution_role/execution-role.yaml") + parameters = { + pSRAExecutionRoleName = var.execution_role_name, + pSRASolutionName = var.solution_name, + pManagementAccountId = data.aws_ssm_parameter.management_account_id.value + } + + auto_deployment { + enabled = true + retain_stacks_on_account_removal = false + } + call_as = "SELF" + capabilities = ["CAPABILITY_NAMED_IAM"] + managed_execution { + active = true + } + operation_preferences { + failure_tolerance_percentage = 100 + max_concurrent_percentage = 100 + region_concurrency_type = "PARALLEL" + } + permission_model = "SERVICE_MANAGED" +} + +module "s3_state_bucket" { + source = "./s3" + + kms_key_id = module.sra_secrets_kms.kms_key_arn +} + +module "dynamo_tf_lock" { + source = "./dynamodb" +} + +resource "aws_cloudformation_stack_set_instance" "sra_execution_role_stackset_instance" { + deployment_targets { + organizational_unit_ids = [data.aws_ssm_parameter.root_organizational_unit_id.value] + } + region = data.aws_ssm_parameter.home_region.value + stack_set_name = aws_cloudformation_stack_set.sra_execution_role_stackset.name +} + +######################################################################## +# Create tfvar config file +######################################################################## +resource "local_file" "backend_file_creation" { + depends_on = [module.mangement_account_parameters] + content = <<-EOT + ######################################################################## + # Main Configuration + ######################################################################## + bucket = "${module.s3_state_bucket.bucket_name}" + key = "state/sra_state.tfstate" + region = "${data.aws_ssm_parameter.home_region.value}" + encrypt = true + dynamodb_table = "${module.dynamo_tf_lock.dynamo_db_table_name}" + EOT + filename = "${path.root}/../solutions/backend.tfvars" +} + +resource "local_file" "config_file_creation" { + depends_on = [module.mangement_account_parameters] + content = <<-EOT + ######################################################################## + # Main Configuration + ######################################################################## + audit_account_id = "${data.aws_ssm_parameter.audit_account_id.value}" + home_region = "${data.aws_ssm_parameter.home_region.value}" + log_archive_account_id = "${data.aws_ssm_parameter.log_archive_account_id.value}" + management_account_id = "${data.aws_ssm_parameter.management_account_id.value}" + organization_id = "${data.aws_ssm_parameter.organization_id.value}" + root_organizational_unit_id = "${data.aws_ssm_parameter.root_organizational_unit_id.value}" + customer_control_tower_regions = "${data.aws_ssm_parameter.customer_control_tower_regions.value}" + customer_control_tower_regions_without_home_region = "${data.aws_ssm_parameter.customer_control_tower_regions_without_home_region.value}" + enabled_regions = "" + enabled_regions_without_home_region = "" + + ######################################################################## + # Services to enable/disable + ######################################################################## + enable_gd = false + enable_sh = false + enable_access_analyzer = false + enable_macie = false + enable_cloudtrail_org = false + enable_iam_password_policy = false + enable_inspector = false + + ######################################################################## + # Guard Duty Settings + ######################################################################## + disable_guard_duty = false + enable_s3_logs = true + enable_kubernetes_audit_logs = true + enable_malware_protection = true + enable_rds_login_events = true + enable_eks_runtime_monitoring = true + enable_eks_addon_management = true + enable_lambda_network_logs = true + guardduty_control_tower_regions_only = true + finding_publishing_frequency = "FIFTEEN_MINUTES" + + ######################################################################## + # Security Hub Settings + ######################################################################## + disable_security_hub = false + cis_standard_version = "1.4.0" + compliance_frequency = "7" + securityhub_control_tower_regions_only = true + enable_cis_standard = false + enable_pci_standard = false + enable_nist_standard = false + enable_security_best_practices_standard = true + pci_standard_version = "3.2.1" + nist_standard_version = "5.0.0" + security_best_practices_standard_version = "1.0.0" + + ######################################################################## + # Inspector Settings + ######################################################################## + disable_inspector = false # set true BEFORE destroy + ecr_rescan_duration = "LIFETIME" + scan_components = "EC2,ECR,LAMBDA,LAMBDA_CODE" + inspector_control_tower_regions_only = true + + ######################################################################## + # IAM Password Policy + ######################################################################## + iam_password_policy_allow_users_to_change_password = true + iam_password_policy_hard_expiry = false + iam_password_policy_max_password_age = 90 + iam_password_policy_minimum_password_length = 14 + iam_password_policy_password_reuse_prevention = 24 + iam_password_policy_require_lowercase_characters = true + iam_password_policy_require_numbers = true + iam_password_policy_require_symbols = true + iam_password_policy_require_uppercase_characters = true + + ######################################################################## + # Macie Settings + ######################################################################## + disable_macie = false + macie_finding_publishing_frequency = "FIFTEEN_MINUTES" + + ######################################################################## + # CloudTrail Settings + ######################################################################## + enable_data_events_only = true + enable_lambda_data_events = true + enable_s3_data_events = true + disable_cloudtrail = false + EOT + filename = "${path.root}/../solutions/config.tfvars" +} diff --git a/aws_sra_examples/terraform/common/outputs.tf b/aws_sra_examples/terraform/common/outputs.tf new file mode 100644 index 00000000..de158683 --- /dev/null +++ b/aws_sra_examples/terraform/common/outputs.tf @@ -0,0 +1,9 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +# Results from lambda function +# output "lambda_result_entry" { +# value = module.mangement_account_parameters.lambda_result_entry +# } \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/providers.tf b/aws_sra_examples/terraform/common/providers.tf new file mode 100644 index 00000000..f44b58d6 --- /dev/null +++ b/aws_sra_examples/terraform/common/providers.tf @@ -0,0 +1,21 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +terraform { + required_providers { + aws = ">= 5.1.0" + } +} + +provider "aws" { + alias = "target" + region = var.account_region + + default_tags { + tags = { + Owner = "Security" + } + } +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/s3/README-TF.MD b/aws_sra_examples/terraform/common/s3/README-TF.MD new file mode 100644 index 00000000..18ab60dd --- /dev/null +++ b/aws_sra_examples/terraform/common/s3/README-TF.MD @@ -0,0 +1,42 @@ + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_s3_bucket.sra_state_bucket](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket_ownership_controls.sra_state_bucket_ownership_control](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_ownership_controls) | resource | +| [aws_s3_bucket_public_access_block.sra_state_bucket_public_access_block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | +| [aws_s3_bucket_server_side_encryption_configuration.sra_state_bucket_see](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource | +| [aws_s3_bucket_versioning.sra_state_bucket_versioning](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [kms\_key\_id](#input\_kms\_key\_id) | KMS Key ID | `string` | n/a | yes | +| [sra\_solution\_name](#input\_sra\_solution\_name) | SRA Solution Name | `string` | `"sra-tfstate-s3"` | no | +| [sra\_state\_bucket\_prefix](#input\_sra\_state\_bucket\_prefix) | SRA State Bucket Prefix | `string` | `"sra-tfstate-files"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [bucket\_name](#output\_bucket\_name) | n/a | + \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/s3/data.tf b/aws_sra_examples/terraform/common/s3/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/common/s3/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/s3/main.tf b/aws_sra_examples/terraform/common/s3/main.tf new file mode 100644 index 00000000..4576a575 --- /dev/null +++ b/aws_sra_examples/terraform/common/s3/main.tf @@ -0,0 +1,53 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_s3_bucket" "sra_state_bucket" { + #checkov:skip=CKV2_AWS_61: Ensure that an S3 bucket has a lifecycle configuration + #checkov:skip=CKV_AWS_18: Ensure the S3 bucket has access logging enabled + #checkov:skip=CKV2_AWS_62: Ensure S3 buckets should have event notifications enabled + #checkov:skip=CKV_AWS_144: Ensure that S3 bucket has cross-region replication enabled + + bucket = "${var.sra_state_bucket_prefix}-${data.aws_region.current.name}-${data.aws_caller_identity.current.account_id}" + force_destroy = true + + tags = { + "sra-solution" = var.sra_solution_name + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "sra_state_bucket_see" { + bucket = aws_s3_bucket.sra_state_bucket.id + + rule { + apply_server_side_encryption_by_default { + kms_master_key_id = var.kms_key_id + sse_algorithm = "aws:kms" + } + } +} + +resource "aws_s3_bucket_versioning" "sra_state_bucket_versioning" { + bucket = aws_s3_bucket.sra_state_bucket.id + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_ownership_controls" "sra_state_bucket_ownership_control" { + #checkov:skip=CKV2_AWS_65: Ensure access control lists for S3 buckets are disabled + bucket = aws_s3_bucket.sra_state_bucket.id + rule { + object_ownership = "BucketOwnerPreferred" + } +} + +resource "aws_s3_bucket_public_access_block" "sra_state_bucket_public_access_block" { + bucket = aws_s3_bucket.sra_state_bucket.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/s3/output.tf b/aws_sra_examples/terraform/common/s3/output.tf new file mode 100644 index 00000000..40a2d2ab --- /dev/null +++ b/aws_sra_examples/terraform/common/s3/output.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +output bucket_name { + value = aws_s3_bucket.sra_state_bucket.id +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/s3/variables.tf b/aws_sra_examples/terraform/common/s3/variables.tf new file mode 100644 index 00000000..db8d7a98 --- /dev/null +++ b/aws_sra_examples/terraform/common/s3/variables.tf @@ -0,0 +1,21 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "sra_state_bucket_prefix" { + description = "SRA State Bucket Prefix" + type = string + default = "sra-tfstate-files" +} + +variable kms_key_id { + description = "KMS Key ID" + type = string +} + +variable "sra_solution_name" { + description = "SRA Solution Name" + type = string + default = "sra-tfstate-s3" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/secrets_kms/README-TF.MD b/aws_sra_examples/terraform/common/secrets_kms/README-TF.MD new file mode 100644 index 00000000..38101cc3 --- /dev/null +++ b/aws_sra_examples/terraform/common/secrets_kms/README-TF.MD @@ -0,0 +1,41 @@ + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_kms_alias.sra_secrets_key_alias](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource | +| [aws_kms_key.sra_secrets_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.sra_secrets_key_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [management\_account\_id](#input\_management\_account\_id) | Organization Management Account ID | `string` | n/a | yes | +| [organization\_id](#input\_organization\_id) | AWS Organizations ID | `string` | n/a | yes | +| [sra\_secrets\_key\_alias](#input\_sra\_secrets\_key\_alias) | The SRA secrets KMS key alias. | `string` | `"sra-secrets-key"` | no | +| [sra\_secrets\_prefix](#input\_sra\_secrets\_prefix) | Prefix used for SRA secrets | `string` | `"sra"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [kms\_key\_arn](#output\_kms\_key\_arn) | n/a | + \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/secrets_kms/data.tf b/aws_sra_examples/terraform/common/secrets_kms/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/common/secrets_kms/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/secrets_kms/main.tf b/aws_sra_examples/terraform/common/secrets_kms/main.tf new file mode 100644 index 00000000..99be1b51 --- /dev/null +++ b/aws_sra_examples/terraform/common/secrets_kms/main.tf @@ -0,0 +1,107 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_kms_key" "sra_secrets_key" { + description = "SRA Secrets Key" + enable_key_rotation = true + policy = data.aws_iam_policy_document.sra_secrets_key_policy.json +} + +data "aws_iam_policy_document" "sra_secrets_key_policy" { + #checkov:skip=CKV_AWS_109: Ensure IAM policies does not allow permissions management without constraints + #checkov:skip=CKV_AWS_111: Ensure IAM policies does not allow write access without constraints + #checkov:skip=CKV_AWS_356: Ensure no IAM policies documents allow "*" as a statement's resource for restrictable actions + + statement { + sid = "Enable IAM User Permissions" + effect = "Allow" + actions = ["kms:*"] + resources = ["*"] + principals { + type = "AWS" + identifiers = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root"] + } + } + + statement { + sid = "Allow access through AWS Secrets Manager for all principals in the account that are authorized to use AWS Secrets Manager" + effect = "Allow" + actions = [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*", + "kms:CreateGrant", + "kms:DescribeKey", + ] + resources = ["*"] + principals { + type = "AWS" + identifiers = ["*"] + } + condition { + test = "StringEquals" + variable = "kms:ViaService" + values = ["secretsmanager.${data.aws_region.current.name}.amazonaws.com"] + } + condition { + test = "StringEquals" + variable = "aws:PrincipalOrgId" + values = [var.organization_id] + } + condition { + test = "StringLike" + variable = "kms:EncryptionContext:SecretARN" + values = ["arn:aws:secretsmanager:${data.aws_region.current.name}:*:secret:${var.sra_secrets_prefix}/*"] + } + condition { + test = "StringLike" + variable = "aws:PrincipalArn" + values = ["arn:${data.aws_partition.current.partition}:iam::*:role/AWSControlTowerExecution"] + } + } + + statement { + sid = "Allow direct access to key metadata" + effect = "Allow" + actions = [ + "kms:Decrypt", + "kms:Describe*", + "kms:Get*", + "kms:List*", + ] + resources = ["*"] + principals { + type = "AWS" + identifiers = ["arn:${data.aws_partition.current.partition}:iam::${var.management_account_id}:root"] + } + } + + statement { + sid = "Allow alias creation during setup" + effect = "Allow" + actions = ["kms:CreateAlias"] + resources = ["*"] + principals { + type = "AWS" + identifiers = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root"] + } + condition { + test = "StringEquals" + variable = "kms:CallerAccount" + values = ["${data.aws_caller_identity.current.account_id}"] + } + condition { + test = "StringEquals" + variable = "kms:ViaService" + values = ["cloudformation.${data.aws_region.current.name}.amazonaws.com"] + } + } +} + +resource "aws_kms_alias" "sra_secrets_key_alias" { + name = "alias/${var.sra_secrets_key_alias}" + target_key_id = aws_kms_key.sra_secrets_key.key_id +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/secrets_kms/output.tf b/aws_sra_examples/terraform/common/secrets_kms/output.tf new file mode 100644 index 00000000..20e0fc8f --- /dev/null +++ b/aws_sra_examples/terraform/common/secrets_kms/output.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +output kms_key_arn { + value = aws_kms_key.sra_secrets_key.arn +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/secrets_kms/variables.tf b/aws_sra_examples/terraform/common/secrets_kms/variables.tf new file mode 100644 index 00000000..7432b46b --- /dev/null +++ b/aws_sra_examples/terraform/common/secrets_kms/variables.tf @@ -0,0 +1,26 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "management_account_id" { + description = "Organization Management Account ID" + type = string +} + +variable "organization_id" { + description = "AWS Organizations ID" + type = string +} + +variable "sra_secrets_key_alias" { + description = "The SRA secrets KMS key alias." + type = string + default = "sra-secrets-key" +} + +variable "sra_secrets_prefix" { + description = "Prefix used for SRA secrets" + type = string + default = "sra" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/sra_execution_role/README-TF.MD b/aws_sra_examples/terraform/common/sra_execution_role/README-TF.MD new file mode 100644 index 00000000..381589cd --- /dev/null +++ b/aws_sra_examples/terraform/common/sra_execution_role/README-TF.MD @@ -0,0 +1,38 @@ + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 5.1.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_iam_role.sra_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [aws\_partition](#input\_aws\_partition) | AWS Partition (e.g., aws or aws-cn) | `string` | `"aws"` | no | +| [execution\_role\_name](#input\_execution\_role\_name) | Name of the SRA execution role | `string` | `"sra-execution"` | no | +| [management\_account\_id](#input\_management\_account\_id) | AWS Account ID of the Management account (12 digits) | `string` | `"333333333333"` | no | +| [solution\_name](#input\_solution\_name) | Name of the SRA solution | `string` | `"sra-create-deployment-roles"` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/sra_execution_role/data.tf b/aws_sra_examples/terraform/common/sra_execution_role/data.tf new file mode 100644 index 00000000..0ca3901b --- /dev/null +++ b/aws_sra_examples/terraform/common/sra_execution_role/data.tf @@ -0,0 +1,7 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/sra_execution_role/execution-role.yaml b/aws_sra_examples/terraform/common/sra_execution_role/execution-role.yaml new file mode 100644 index 00000000..a1468e2b --- /dev/null +++ b/aws_sra_examples/terraform/common/sra_execution_role/execution-role.yaml @@ -0,0 +1,69 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: SRA Terraform Edition Execution IAM Role Creation template (sra-1u3sd7f8f). +Metadata: + SRA: + Version: 1.0 + AWS::CloudFormation::Interface: + ParameterGroups: + - Label: + default: General Properties + Parameters: + - pSRASolutionName + - pManagementAccountId + - Label: + default: Role Attributes + Parameters: + - pSRAExecutionRoleName + ParameterLabels: + pSRAExecutionRoleName: + default: SRA Execution Role Name + pSRASolutionName: + default: SRA Solution Name + pManagementAccountId: + default: Management Account Id + +Parameters: + pSRAExecutionRoleName: + AllowedValues: [sra-execution] + Default: sra-execution + Description: SRA execution role name + Type: String + pSRASolutionName: + AllowedValues: [sra-create-deployment-roles] + Default: sra-create-deployment-roles + Description: The SRA solution name. The default value is the folder name of the solution + Type: String + pManagementAccountId: + AllowedPattern: '^\d{12}$' + Default: 333333333333 + ConstraintDescription: Must be 12 digits. + Description: AWS Account ID of the Management account. + Type: String + +Resources: + rSRAExecutionRole: + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Type: AWS::IAM::Role + Metadata: + cfn_nag: + rules_to_suppress: + - id: W28 + reason: Specific role name provided + - id: W43 + reason: Administrator policy is required for the role + Properties: + RoleName: !Ref pSRAExecutionRoleName + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Action: sts:AssumeRole + Effect: Allow + Principal: + AWS: + - !Sub arn:${AWS::Partition}:iam::${pManagementAccountId}:root + ManagedPolicyArns: + - !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/terraform/common/sra_execution_role/main.tf b/aws_sra_examples/terraform/common/sra_execution_role/main.tf new file mode 100644 index 00000000..57bcc72e --- /dev/null +++ b/aws_sra_examples/terraform/common/sra_execution_role/main.tf @@ -0,0 +1,28 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_iam_role" "sra_execution_role" { + #checkov:skip=CKV_AWS_274: Disallow IAM roles, users, and groups from using the AWS AdministratorAccess policy + name = var.execution_role_name + + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [{ + Action = "sts:AssumeRole", + Effect = "Allow", + Principal = { + AWS = "arn:${var.aws_partition}:iam::${var.management_account_id}:root" + } + }] + }) + + managed_policy_arns = [ + "arn:${var.aws_partition}:iam::aws:policy/AdministratorAccess" + ] + + tags = { + "sra-solution" = var.solution_name + } +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/sra_execution_role/providers.tf b/aws_sra_examples/terraform/common/sra_execution_role/providers.tf new file mode 100644 index 00000000..ca74bfe1 --- /dev/null +++ b/aws_sra_examples/terraform/common/sra_execution_role/providers.tf @@ -0,0 +1,14 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.1.0" + } + } +} + diff --git a/aws_sra_examples/terraform/common/sra_execution_role/variables.tf b/aws_sra_examples/terraform/common/sra_execution_role/variables.tf new file mode 100644 index 00000000..cd57da3b --- /dev/null +++ b/aws_sra_examples/terraform/common/sra_execution_role/variables.tf @@ -0,0 +1,31 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "management_account_id" { + default = "333333333333" + description = "AWS Account ID of the Management account (12 digits)" + validation { + condition = length(var.management_account_id) == 12 && can(regex("^\\d{12}$", var.management_account_id)) + error_message = "Must be 12 digits." + } + type = string +} + +variable "aws_partition" { + description = "AWS Partition (e.g., aws or aws-cn)" + default = "aws" +} + +variable "execution_role_name" { + default = "sra-execution" + description = "Name of the SRA execution role" + type = string +} + +variable "solution_name" { + default = "sra-create-deployment-roles" + description = "Name of the SRA solution" + type = string +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/ssm_parameters/README-TF.MD b/aws_sra_examples/terraform/common/ssm_parameters/README-TF.MD new file mode 100644 index 00000000..229c82d5 --- /dev/null +++ b/aws_sra_examples/terraform/common/ssm_parameters/README-TF.MD @@ -0,0 +1,59 @@ + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| [archive](#provider\_archive) | n/a | +| [aws](#provider\_aws) | n/a | +| [null](#provider\_null) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_cloudwatch_log_group.management_account_parameters](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_iam_role.management_account_parameters_lambda_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy.cloudwatch_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.management_account_parameters_lambda_ssm_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_lambda_function.management_account_parameters](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | +| [aws_lambda_invocation.lambda_invoke](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_invocation) | resource | +| [null_resource.package_lambda](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | +| [archive_file.hash_check](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source | +| [archive_file.zipped_lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.cloudwatch_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.management_account_parameters_lambda_ssm_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [control\_tower](#input\_control\_tower) | AWS Control Tower landing zone deployed/in-use | `string` | `"true"` | no | +| [create\_lambda\_log\_group](#input\_create\_lambda\_log\_group) | Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS Key for encryption. | `string` | `"false"` | no | +| [governed\_regions](#input\_governed\_regions) | AWS regions (comma separated) if not using AWS Control Tower (leave set to ct-regions for AWS Control Tower environments) | `string` | `"ct-regions"` | no | +| [lambda\_log\_group\_kms\_key](#input\_lambda\_log\_group\_kms\_key) | (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side encryption keys. | `string` | `""` | no | +| [lambda\_log\_group\_retention](#input\_lambda\_log\_group\_retention) | Specifies the number of days you want to retain log events. | `string` | `"14"` | no | +| [lambda\_log\_level](#input\_lambda\_log\_level) | Lambda Function Logging Level. | `string` | `"INFO"` | no | +| [log\_archive\_account\_id](#input\_log\_archive\_account\_id) | Log Archive Account ID | `number` | `222222222222` | no | +| [management\_account\_parameters\_lambda\_function\_name](#input\_management\_account\_parameters\_lambda\_function\_name) | Lambda function name for creating Control Tower account SSM parameters. | `string` | `"sra-management-account-parameters"` | no | +| [management\_account\_parameters\_lambda\_role\_name](#input\_management\_account\_parameters\_lambda\_role\_name) | Lambda execution role for creating Control Tower account SSM parameters. | `string` | `"sra-management-account-parameters-lambda"` | no | +| [security\_account\_id](#input\_security\_account\_id) | Security Tooling Account ID | `number` | `111111111111` | no | +| [sra\_solution\_name](#input\_sra\_solution\_name) | The SRA solution name. The default value is the folder name of the solution. | `string` | `"sra-common-prerequisites"` | no | +| [sra\_solution\_tag\_key](#input\_sra\_solution\_tag\_key) | The SRA solution tag key applied to all resources created by the solution that support tagging. The value is the pSRASolutionName. | `string` | `"sra-solution"` | no | +| [sra\_staging\_s3\_bucket\_name](#input\_sra\_staging\_s3\_bucket\_name) | (Optional) SRA Staging S3 bucket name for the artifacts relevant to the solution. (e.g., lambda zips, CloudFormation templates). If empty, the SRA Staging S3 bucket name will be resolved from the SSM Parameter '/sra/staging-s3-bucket-name'. | `string` | `""` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/ssm_parameters/data.tf b/aws_sra_examples/terraform/common/ssm_parameters/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/common/ssm_parameters/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/ssm_parameters/invoke.tf b/aws_sra_examples/terraform/common/ssm_parameters/invoke.tf new file mode 100644 index 00000000..66ad5376 --- /dev/null +++ b/aws_sra_examples/terraform/common/ssm_parameters/invoke.tf @@ -0,0 +1,24 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_lambda_invocation" "lambda_invoke" { + function_name = aws_lambda_function.management_account_parameters.function_name + + input = jsonencode({ + "ResourceType" : "Custom::LambdaCustomResource", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.management_account_parameters.arn}", + "TAG_KEY" : "sra-solution", + "TAG_VALUE" : "sra-common-prerequisites", + "CONTROL_TOWER" : "${var.control_tower}", + "OTHER_REGIONS" : "${var.governed_regions}", + "OTHER_SECURITY_ACCT" : "${var.security_account_id}", + "OTHER_LOG_ARCHIVE_ACCT" : "${var.log_archive_account_id}", + "Action" : "Created", + } + }) + + lifecycle_scope = "CREATE_ONLY" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/common/ssm_parameters/main.tf b/aws_sra_examples/terraform/common/ssm_parameters/main.tf new file mode 100644 index 00000000..0c88e54a --- /dev/null +++ b/aws_sra_examples/terraform/common/ssm_parameters/main.tf @@ -0,0 +1,218 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +locals { + #TODO: Figure out? + graviton_regions = [ + "ap-northeast-1", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ] + account_id = data.aws_caller_identity.current.account_id + region = data.aws_region.current.name + src_path = "${path.root}/../../solutions/common/common_prerequisites/lambda/src/" +} + + +data "archive_file" "hash_check" { + type = "zip" + source_dir = local.src_path + output_path = "${path.module}/lambda/lambda_function.zip" + excludes = ["lambda_function.zip, data.zip"] +} + +resource "null_resource" "package_lambda" { + triggers = { + src_hash = "${data.archive_file.hash_check.output_sha}" + } + + provisioner "local-exec" { + command = < + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + + +## Introduction + +This will install the other AWS SRA solutions including their lambdas and other resources into the AWS environment to help protect it. + +The common pre-requisites solution must be installed, in the management account, prior to installing and of these AWS SRA solutions. + +Information on the Terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA solutions](./aws_sra_examples/terraform##installing-the-aws-sra-solutions) section of the documentation for more information and installation instructions. + + + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 5.1.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [access\_analyzer](#module\_access\_analyzer) | ./iam_access_analyzer | n/a | +| [cloudtrail](#module\_cloudtrail) | ./cloudtrail_org | n/a | +| [guard\_duty](#module\_guard\_duty) | ./guard_duty | n/a | +| [iam\_password\_policy](#module\_iam\_password\_policy) | ./iam_password_policy | n/a | +| [inspector](#module\_inspector) | ./inspector | n/a | +| [macie](#module\_macie) | ./macie | n/a | +| [register\_delegated\_admin](#module\_register\_delegated\_admin) | ./register_delegated_administrator | n/a | +| [security\_hub](#module\_security\_hub) | ./security_hub | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [account\_id](#input\_account\_id) | Account ID used for assuming role | `string` | n/a | yes | +| [account\_region](#input\_account\_region) | Account Region used for assuming role | `string` | n/a | yes | +| [audit\_account\_id](#input\_audit\_account\_id) | The name for the audit account ID. | `string` | n/a | yes | +| [cis\_standard\_version](#input\_cis\_standard\_version) | CIS Standard Version | `string` | n/a | yes | +| [compliance\_frequency](#input\_compliance\_frequency) | Frequency to Check for Organizational Compliance (in days between 1 and 30, default is 7) | `number` | n/a | yes | +| [customer\_control\_tower\_regions](#input\_customer\_control\_tower\_regions) | The name for customer control tower regions. | `string` | n/a | yes | +| [customer\_control\_tower\_regions\_without\_home\_region](#input\_customer\_control\_tower\_regions\_without\_home\_region) | The name for customer control tower regions without home region. | `string` | n/a | yes | +| [disable\_guard\_duty](#input\_disable\_guard\_duty) | Update to 'true' to disable GuardDuty in all accounts and regions before deleting the TF. | `string` | `"false"` | no | +| [disable\_macie](#input\_disable\_macie) | Update to 'true' to disable Macie in all accounts and regions before deleting the TF. | `string` | n/a | yes | +| [disable\_security\_hub](#input\_disable\_security\_hub) | Update to 'true' to disable Security Hub in all accounts and regions before deleting the stack | `bool` | n/a | yes | +| [ecr\_rescan\_duration](#input\_ecr\_rescan\_duration) | ECR Rescan Duration | `string` | `"LIFETIME"` | no | +| [enable\_access\_analyzer](#input\_enable\_access\_analyzer) | Enable or disable IAM Access Analyzer module | `bool` | `true` | no | +| [enable\_cis\_standard](#input\_enable\_cis\_standard) | Indicates whether to enable the CIS AWS Foundations Benchmark Standard | `bool` | n/a | yes | +| [enable\_cloudtrail\_org](#input\_enable\_cloudtrail\_org) | Enable or disable CloudTrail Organization module | `bool` | `true` | no | +| [enable\_data\_events\_only](#input\_enable\_data\_events\_only) | Only Enable Cloud Trail Data Events | `string` | n/a | yes | +| [enable\_eks\_addon\_management](#input\_enable\_eks\_addon\_management) | Auto enable EKS Add-on Management | `string` | n/a | yes | +| [enable\_eks\_runtime\_monitoring](#input\_enable\_eks\_runtime\_monitoring) | Auto enable EKS Runtime Monitoring | `string` | n/a | yes | +| [enable\_gd](#input\_enable\_gd) | Enable or disable Guard Duty module | `bool` | `true` | no | +| [enable\_iam\_password\_policy](#input\_enable\_iam\_password\_policy) | Enable or disable IAM Password Policy Module | `bool` | `true` | no | +| [enable\_inspector](#input\_enable\_inspector) | Enable or disable Inspector module | `bool` | `true` | no | +| [enable\_kubernetes\_audit\_logs](#input\_enable\_kubernetes\_audit\_logs) | Auto enable Kubernetes Audit Logs | `string` | n/a | yes | +| [enable\_lambda\_data\_events](#input\_enable\_lambda\_data\_events) | Enable Cloud Trail Data Events for all Lambda functions | `string` | n/a | yes | +| [enable\_lambda\_network\_logs](#input\_enable\_lambda\_network\_logs) | Auto enable Lambda Network Logs | `string` | n/a | yes | +| [enable\_macie](#input\_enable\_macie) | Enable or disable Macie module | `bool` | `true` | no | +| [enable\_malware\_protection](#input\_enable\_malware\_protection) | Auto enable Malware Protection | `string` | n/a | yes | +| [enable\_member\_account\_parameters](#input\_enable\_member\_account\_parameters) | Enable or disable Members Account Paramters module | `bool` | `true` | no | +| [enable\_nist\_standard](#input\_enable\_nist\_standard) | Indicates whether to enable the National Institute of Standards and Technology (NIST) SP 800-53 Rev. 5 | `bool` | n/a | yes | +| [enable\_pci\_standard](#input\_enable\_pci\_standard) | Indicates whether to enable the Payment Card Industry Data Security Standard (PCI DSS) | `bool` | n/a | yes | +| [enable\_rds\_login\_events](#input\_enable\_rds\_login\_events) | Auto enable RDS Login Events | `string` | n/a | yes | +| [enable\_s3\_data\_events](#input\_enable\_s3\_data\_events) | Enable Cloud Trail S3 Data Events for all buckets | `string` | n/a | yes | +| [enable\_s3\_logs](#input\_enable\_s3\_logs) | Auto enable S3 logs | `string` | n/a | yes | +| [enable\_security\_best\_practices\_standard](#input\_enable\_security\_best\_practices\_standard) | Indicates whether to enable the AWS Foundational Security Best Practices Standard | `bool` | n/a | yes | +| [enable\_sh](#input\_enable\_sh) | Enable or disable Security Hub module | `bool` | `true` | no | +| [enabled\_regions](#input\_enabled\_regions) | The name for enabled regions. | `string` | n/a | yes | +| [enabled\_regions\_without\_home\_region](#input\_enabled\_regions\_without\_home\_region) | The name for enabled regions without home region. | `string` | n/a | yes | +| [finding\_publishing\_frequency](#input\_finding\_publishing\_frequency) | Finding publishing frequency | `string` | `"FIFTEEN_MINUTES"` | no | +| [guardduty\_control\_tower\_regions\_only](#input\_guardduty\_control\_tower\_regions\_only) | Only enable in the Control Tower governed regions | `string` | `"true"` | no | +| [home\_region](#input\_home\_region) | The name for the home region. | `string` | n/a | yes | +| [iam\_password\_policy\_allow\_users\_to\_change\_password](#input\_iam\_password\_policy\_allow\_users\_to\_change\_password) | You can permit all IAM users in your account to use the IAM console to change their own passwords. | `string` | n/a | yes | +| [iam\_password\_policy\_hard\_expiry](#input\_iam\_password\_policy\_hard\_expiry) | You can prevent IAM users from choosing a new password after their current password has expired. | `string` | n/a | yes | +| [iam\_password\_policy\_max\_password\_age](#input\_iam\_password\_policy\_max\_password\_age) | You can set IAM user passwords to be valid for only the specified number of days. | `string` | n/a | yes | +| [iam\_password\_policy\_minimum\_password\_length](#input\_iam\_password\_policy\_minimum\_password\_length) | You can specify the minimum number of characters allowed in an IAM user password. | `string` | n/a | yes | +| [iam\_password\_policy\_password\_reuse\_prevention](#input\_iam\_password\_policy\_password\_reuse\_prevention) | You can prevent IAM users from reusing a specified number of previous passwords. | `string` | n/a | yes | +| [iam\_password\_policy\_require\_lowercase\_characters](#input\_iam\_password\_policy\_require\_lowercase\_characters) | You can require that IAM user passwords contain at least one lowercase character from the ISO basic Latin alphabet (a to z). | `string` | n/a | yes | +| [iam\_password\_policy\_require\_numbers](#input\_iam\_password\_policy\_require\_numbers) | You can require that IAM user passwords contain at least one numeric character (0 to 9). | `string` | n/a | yes | +| [iam\_password\_policy\_require\_symbols](#input\_iam\_password\_policy\_require\_symbols) | You can require that IAM user passwords contain at least one of the following nonalphanumeric characters: ! @ # $ % ^ & * ( ) \_ + - = [ ] {} \| ' | `string` | n/a | yes | +| [iam\_password\_policy\_require\_uppercase\_characters](#input\_iam\_password\_policy\_require\_uppercase\_characters) | You can require that IAM user passwords contain at least one uppercase character from the ISO basic Latin alphabet (A to Z). | `string` | n/a | yes | +| [inspector\_control\_tower\_regions\_only](#input\_inspector\_control\_tower\_regions\_only) | Only enable in the Control Tower governed regions | `string` | `"true"` | no | +| [log\_archive\_account\_id](#input\_log\_archive\_account\_id) | The name for the log archive account ID. | `string` | n/a | yes | +| [macie\_finding\_publishing\_frequency](#input\_macie\_finding\_publishing\_frequency) | Macie finding publishing frequency | `string` | n/a | yes | +| [management\_account\_id](#input\_management\_account\_id) | The name for the management account ID. | `string` | n/a | yes | +| [nist\_standard\_version](#input\_nist\_standard\_version) | NIST Standard Version | `string` | n/a | yes | +| [organization\_id](#input\_organization\_id) | The SSM parameter name for the organization ID. | `string` | n/a | yes | +| [pci\_standard\_version](#input\_pci\_standard\_version) | PCI Standard Version | `string` | n/a | yes | +| [root\_organizational\_unit\_id](#input\_root\_organizational\_unit\_id) | The name for the root organizational unit ID. | `string` | n/a | yes | +| [scan\_components](#input\_scan\_components) | Components to scan (e.g., 'ec2,ecs') | `string` | `"ec2"` | no | +| [security\_best\_practices\_standard\_version](#input\_security\_best\_practices\_standard\_version) | SBP Standard Version | `string` | n/a | yes | +| [securityhub\_control\_tower\_regions\_only](#input\_securityhub\_control\_tower\_regions\_only) | Only enable in the Control Tower governed regions | `bool` | n/a | yes | +| [sra\_alarm\_email](#input\_sra\_alarm\_email) | (Optional) Email address for receiving DLQ alarms | `string` | `""` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/README.md b/aws_sra_examples/terraform/solutions/cloudtrail_org/README.md new file mode 100644 index 00000000..6f2a093a --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/README.md @@ -0,0 +1,159 @@ +# AWS SRA cloudtrail Organization Solution with Terraform + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + + +## Table of Contents + +- [Introduction](#introduction) +- [Deployed Resource Details](#deployed-resource-details) +- [Implementation Instructions](#implementation-instructions) +- [Requirements](#requirements) +- [Providers](#providers) +- [Modules](#modules) +- [Resources](#resources) +- [Inputs](#inputs) +- [Outputs](#outputs) + +--- + +## Introduction + +This Terraform module deploys the CloudTrail Organization AWS SRA solution. + +The common pre-requisite solution must be installed, in the management account, prior to installing this solution. + +Information on the resources deployed as well as terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for more information and installation instructions. + +*For the CloudFormation version of this AWS SRA solution as well as more information please navigate to the [AWS SRA CloudTrail solution documentation](./../../../solutions/cloudtrail/cloudtrail_org/README.md) page.* + +--- + +## Deployed Resource Details + +![Architecture](./../../../solutions/cloudtrail/cloudtrail_org/documentation/sra-cloudtrail-org-terraform.png) + +### 1.0 Organization Management Account + +#### 1.1 AWS Lambda Function + +- See [1.2 AWS Lambda Function](./../../../solutions/cloudtrail/cloudtrail_org/README.md#12-aws-lambda-function) + +#### 1.2 Lambda Layer + +- See [1.3 Lambda Layer](./../../../solutions/cloudtrail/cloudtrail_org/README.md#13-lambda-layer) + +#### 1.3 Lambda Execution IAM Role + +- See [1.4 Lambda Execution IAM Role](./../../../solutions/cloudtrail/cloudtrail_org/README.md#14-lambda-execution-iam-role) + +#### 1.4 Lambda CloudWatch Log Group + +- See [1.5 Lambda CloudWatch Log Group](./../../../solutions/cloudtrail/cloudtrail_org/README.md#15-lambda-cloudwatch-log-group) + +#### 1.5 Organization CloudTrail + +- See [1.6 Organization CloudTrail](./../../../solutions/cloudtrail/cloudtrail_org/README.md#16-organization-cloudtrail) + +#### 1.6 Organization CloudTrail CloudWatch Log Group Role + +- See [1.7 Organization CloudTrail CloudWatch Log Group Role](./../../../solutions/cloudtrail/cloudtrail_org/README.md#17-organization-cloudtrail-cloudwatch-log-group-role) + +#### 1.7 Organization CloudTrail CloudWatch Log Group + +- See [1.8 Organization CloudTrail CloudWatch Log Group](./../../../solutions/cloudtrail/cloudtrail_org/README.md#18-organization-cloudtrail-cloudwatch-log-group) + +--- + +### 2.0 Audit Account + +#### 2.1 Organization CloudTrail KMS Key + +- See [2.2 Organization CloudTrail KMS Key](./../../../solutions/cloudtrail/cloudtrail_org/README.md#22-organization-cloudtrail-kms-key) + +#### 2.2 CloudTrail KMS Key Secret + +- See [2.3 CloudTrail KMS Key Secret](./../../../solutions/cloudtrail/cloudtrail_org/README.md#23-cloudtrail-kms-key-secret) + +#### 2.3 CloudTrail (Delegated admin) + +- See [2.4 CloudTrail (Delegated admin)](#24-cloudtrail-delegated-admin) + +--- + +### 3.0 Security Log Archive Account + +#### 3.1 Organization CloudTrail S3 Bucket + +- See [3.2 Organization CloudTrail S3 Bucket](./../../../solutions/cloudtrail/cloudtrail_org/README.md#32-organization-cloudtrail-s3-bucket) + +#### 3.2 CloudTrail S3 Bucket Secret + +- See [3.3 CloudTrail S3 Bucket Secret](./../../../solutions/cloudtrail/cloudtrail_org/README.md#33-cloudtrail-s3-bucket-secret) + +--- + +## Implementation Instructions + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for installation instructions. + + +--- + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws.main](#provider\_aws.main) | >= 5.1.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [cloudtrail\_org](#module\_cloudtrail\_org) | ./org | n/a | +| [kms](#module\_kms) | ./kms | n/a | +| [s3\_bucket](#module\_s3\_bucket) | ./s3 | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [audit\_account\_id](#input\_audit\_account\_id) | AWS Account ID of the Control Tower Audit account. | `string` | n/a | yes | +| [enable\_data\_events\_only](#input\_enable\_data\_events\_only) | Only Enable Cloud Trail Data Events | `string` | n/a | yes | +| [enable\_lambda\_data\_events](#input\_enable\_lambda\_data\_events) | Enable Cloud Trail Data Events for all Lambda functions | `string` | n/a | yes | +| [enable\_s3\_data\_events](#input\_enable\_s3\_data\_events) | Enable Cloud Trail S3 Data Events for all buckets | `string` | n/a | yes | +| [home\_region](#input\_home\_region) | Name of the Control Tower home region | `string` | n/a | yes | +| [log\_archive\_account\_id](#input\_log\_archive\_account\_id) | AWS Account ID of the Control Tower Log Archive account. | `string` | n/a | yes | +| [macie\_org\_configuration\_role\_name](#input\_macie\_org\_configuration\_role\_name) | Configuration IAM Role Name | `string` | `"sra-macie-org-configuration"` | no | +| [macie\_org\_lambda\_role\_name](#input\_macie\_org\_lambda\_role\_name) | Lambda Role Name | `string` | `"sra-macie-org-lambda"` | no | +| [management\_account\_id](#input\_management\_account\_id) | Organization Management Account ID | `string` | n/a | yes | +| [organization\_id](#input\_organization\_id) | AWS Organization ID | `string` | n/a | yes | +| [secrets\_key\_alias\_arn](#input\_secrets\_key\_alias\_arn) | (Optional) SRA Secrets Manager KMS Key Alias ARN | `string` | `""` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/data.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/data.tf new file mode 100644 index 00000000..b9bcf777 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/data.tf @@ -0,0 +1,14 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" { + provider = aws.main +} +data "aws_caller_identity" "current" { + provider = aws.main +} +data "aws_region" "current" { + provider = aws.main +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/data.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/main.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/main.tf new file mode 100644 index 00000000..9d304571 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/main.tf @@ -0,0 +1,144 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +resource "aws_kms_key" "organization_cloudtrail_key" { + #checkov:skip=CKV_AWS_149: Ensure that Secrets Manager secret is encrypted using KMS CMK + description = "Organization CloudTrail Key" + enable_key_rotation = true + + policy = jsonencode({ + Version = "2012-10-17", + Id = var.org_cloudtrail_key_alias, + Statement = [ + { + Sid = "EnableIAMUserPermissions", + Effect = "Allow", + Principal = { AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" }, + Action = "kms:*", + Resource = "*", + }, + { + Sid = "AllowCloudTrailToEncryptLogs", + Effect = "Allow", + Principal = { Service = "cloudtrail.amazonaws.com" }, + Action = "kms:GenerateDataKey*", + Resource = "*", + Condition = { + StringLike = { + "kms:EncryptionContext:aws:cloudtrail:arn" = "arn:${data.aws_partition.current.partition}:cloudtrail:*:${var.management_account_id}:trail/*", + }, + }, + }, + { + Sid = "AllowCloudTrailToDecryptLogFiles", + Effect = "Allow", + Principal = { AWS = ["arn:${data.aws_partition.current.partition}:iam::${var.management_account_id}:root"] }, + Action = "kms:Decrypt", + Resource = "*", + Condition = { + "Null" : { + "kms:EncryptionContext:aws:cloudtrail:arn" : "false" + } + } + }, + { + Sid = "AllowCloudTrailToDescribeKey", + Effect = "Allow", + Principal = { Service = "cloudtrail.amazonaws.com" }, + Action = "kms:DescribeKey", + Resource = "*", + }, + { + Sid = "AllowAliasCreationDuringSetup", + Effect = "Allow", + Principal = { AWS = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root"] }, + Action = "kms:CreateAlias", + Resource = "*", + Condition = { + StringEquals = { + "kms:CallerAccount" = "${data.aws_caller_identity.current.account_id}", + "kms:ViaService" = "cloudformation.${data.aws_region.current.name}.amazonaws.com", + } + } + }, + { + Sid = "AllowLogArchiveAndPrimaryAccountAccess", + Effect = "Allow", + Principal = { AWS = ["arn:${data.aws_partition.current.partition}:iam::${var.log_archive_account_id}:root", "arn:${data.aws_partition.current.partition}:iam::${var.management_account_id}:root"] }, + Action = "kms:Decrypt", + Resource = "*", + Condition = { + "Null" : { + "kms:EncryptionContext:aws:cloudtrail:arn" : "false" + } + } + }, + { + Sid = "AllowAccountAccess", + Effect = "Allow", + Principal = { AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" }, + Action = ["kms:DescribeKey", "kms:Decrypt"], + Resource = "*", + }, + ], + }) + + tags = { + "sra-solution" = var.sra_solution_name + } +} + +resource "aws_kms_alias" "organization_cloudtrail_key_alias" { + name = "alias/${var.org_cloudtrail_key_alias}" + target_key_id = aws_kms_key.organization_cloudtrail_key.key_id +} + +resource "aws_secretsmanager_secret" "organization_cloudtrail_key_secret" { + #checkov:skip=CKV_AWS_149: Ensure that Secrets Manager secret is encrypted using KMS CMK + #checkov:skip=CKV2_AWS_57: Ensure Secrets Manager secrets should have automatic rotation enabled + count = var.secrets_key_alias_arn != "" ? 1 : 0 + + name = "sra/cloudtrail-org-key-arn" + description = "Organization CloudTrail KMS Key ARN" + + kms_key_id = var.secrets_key_alias_arn + + tags = { + "sra-solution" = var.sra_solution_name + } +} + +resource "aws_secretsmanager_secret_version" "macie_delivery_key_secret_version" { + count = var.secrets_key_alias_arn != "" ? 1 : 0 + secret_id = aws_secretsmanager_secret.organization_cloudtrail_key_secret[0].id + + secret_string = jsonencode({ + OrganizationCloudTrailKeyArn = aws_kms_key.organization_cloudtrail_key.arn, + }) +} + +resource "aws_secretsmanager_secret_policy" "organization_cloudtrail_key_secret_policy" { + count = var.secrets_key_alias_arn != "" ? 1 : 0 + + secret_arn = aws_secretsmanager_secret.organization_cloudtrail_key_secret[0].id + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Action = "secretsmanager:GetSecretValue", + Effect = "Allow", + Principal = { AWS = ["arn:${data.aws_partition.current.partition}:iam::${var.management_account_id}:root"] }, + Resource = "*", + Condition = { + StringEquals = { + "secretsmanager:VersionStage" = "AWSCURRENT", + }, + }, + }, + ], + }) + + block_public_policy = true +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/output.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/output.tf new file mode 100644 index 00000000..c208246a --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/output.tf @@ -0,0 +1,4 @@ +output "cloudtrail_kms_key_arn" { + description = "ARN of the KMS Key used for Cloudtrail delivery encryption" + value = aws_kms_key.organization_cloudtrail_key.arn +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/providers.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/providers.tf new file mode 100644 index 00000000..226f1ca4 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/providers.tf @@ -0,0 +1,13 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.1.0" + } + } +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/variables.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/variables.tf new file mode 100644 index 00000000..fdb9f76c --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/kms/variables.tf @@ -0,0 +1,30 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +variable "management_account_id" { + description = "Management Account ID" + type = string +} + +variable "log_archive_account_id" { + description = "Log Archive Account ID" + type = string +} + +variable "org_cloudtrail_key_alias" { + description = "SRA Organization CloudTrail KMS Key Alias" + type = string + default = "sra-cloudtrail-org-key" +} + +variable "secrets_key_alias_arn" { + description = "(Optional) SRA Secrets Manager KMS Key Alias ARN" + type = string +} + +variable "sra_solution_name" { + description = "The SRA solution name." + type = string + default = "sra-cloudtrail-org" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/main.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/main.tf new file mode 100644 index 00000000..8cdaf9f0 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/main.tf @@ -0,0 +1,56 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +locals { + is_audit_account = data.aws_caller_identity.current.account_id == var.audit_account_id + is_log_account = data.aws_caller_identity.current.account_id == var.log_archive_account_id + is_home_region = data.aws_region.current.name == var.home_region +} + +module "kms" { + count = local.is_audit_account && local.is_home_region ? 1 : 0 + + providers = { + aws = aws.main + } + + source = "./kms" + + management_account_id = var.management_account_id + log_archive_account_id = var.log_archive_account_id + secrets_key_alias_arn = var.secrets_key_alias_arn +} + +module "s3_bucket" { + count = local.is_audit_account && local.is_home_region ? 1 : 0 + + providers = { + aws = aws.log_archive + } + + source = "./s3" + + management_account_id = var.management_account_id + sra_secrets_key_alias_arn = var.secrets_key_alias_arn + organization_id = var.organization_id + organization_cloudtrail_kms_key_id = module.kms[0].cloudtrail_kms_key_arn +} + +module "cloudtrail_org" { + count = local.is_audit_account && local.is_home_region ? 1 : 0 + + providers = { + aws = aws.management + } + + source = "./org" + + delegated_admin_account_id = var.audit_account_id + organization_cloudtrail_kms_key_id = module.kms[0].cloudtrail_kms_key_arn + cloudtrail_s3_bucket_name = module.s3_bucket[0].cloudtrail_org_bucket_name + enable_data_events_only = var.enable_data_events_only + enable_lambda_data_events = var.enable_lambda_data_events + enable_s3_data_events = var.enable_s3_data_events + disable_cloudtrail = var.disable_cloudtrail +} diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/org/data.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/org/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/org/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/org/invoke.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/org/invoke.tf new file mode 100644 index 00000000..dda60350 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/org/invoke.tf @@ -0,0 +1,57 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +locals { + cloudwatch_log_group_arn = var.create_cloudtrail_log_group == "true" ? aws_cloudwatch_log_group.cloudtrail_log_group[0].arn : "" + cloudwatch_log_group_role_arn = var.create_cloudtrail_log_group == "true" ? aws_iam_role.cloudtrail_log_group_role[0].arn : "" +} + +resource "aws_lambda_invocation" "lambda_invoke" { + count = var.disable_cloudtrail ? 0 : 1 + function_name = aws_lambda_function.cloudtrail_org_lambda_function.function_name + + input = jsonencode({ + "RequestType" : "Create", + "ResourceType" : "Custom::LambdaCustomResource", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.cloudtrail_org_lambda_function.arn}", + "AWS_PARTITION" : "${data.aws_partition.current.partition}", + "CLOUDTRAIL_NAME" : "${var.cloudtrail_name}", + "CLOUDWATCH_LOG_GROUP_ARN" : "${local.cloudwatch_log_group_arn}:*", + "CLOUDWATCH_LOG_GROUP_ROLE_ARN" : "${local.cloudwatch_log_group_role_arn}", + "ENABLE_DATA_EVENTS_ONLY" : "${var.enable_data_events_only}", + "ENABLE_LAMBDA_DATA_EVENTS" : "${var.enable_lambda_data_events}", + "ENABLE_S3_DATA_EVENTS" : "${var.enable_s3_data_events}", + "KMS_KEY_ID" : "${var.organization_cloudtrail_kms_key_id}", + "S3_BUCKET_NAME" : "${var.cloudtrail_s3_bucket_name}", + "SRA_SOLUTION_NAME" : "${var.sra_solution_name}", + "DELEGATED_ADMIN_ACCOUNT_ID" : "${var.delegated_admin_account_id}", + } + }) +} + +resource "aws_lambda_invocation" "lambda_disable_invoke" { + count = var.disable_cloudtrail ? 1 : 0 + function_name = aws_lambda_function.cloudtrail_org_lambda_function.function_name + + input = jsonencode({ + "RequestType" : "Delete", + "ResourceType" : "Custom::LambdaCustomResource", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.cloudtrail_org_lambda_function.arn}", + "AWS_PARTITION" : "${data.aws_partition.current.partition}", + "CLOUDTRAIL_NAME" : "${var.cloudtrail_name}", + "CLOUDWATCH_LOG_GROUP_ARN" : "${local.cloudwatch_log_group_arn}:*", + "CLOUDWATCH_LOG_GROUP_ROLE_ARN" : "${local.cloudwatch_log_group_role_arn}", + "ENABLE_DATA_EVENTS_ONLY" : "${var.enable_data_events_only}", + "ENABLE_LAMBDA_DATA_EVENTS" : "${var.enable_lambda_data_events}", + "ENABLE_S3_DATA_EVENTS" : "${var.enable_s3_data_events}", + "KMS_KEY_ID" : "${var.organization_cloudtrail_kms_key_id}", + "S3_BUCKET_NAME" : "${var.cloudtrail_s3_bucket_name}", + "SRA_SOLUTION_NAME" : "${var.sra_solution_name}", + "DELEGATED_ADMIN_ACCOUNT_ID" : "${var.delegated_admin_account_id}", + } + }) +} diff --git a/aws_sra_examples/terraform/solutions/cloudtrail_org/org/main.tf b/aws_sra_examples/terraform/solutions/cloudtrail_org/org/main.tf new file mode 100644 index 00000000..50e76c05 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/cloudtrail_org/org/main.tf @@ -0,0 +1,313 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +locals { + src_path = "${path.root}/../../solutions/cloudtrail/cloudtrail_org/lambda/src/" +} + +resource "aws_iam_role" "cloudtrail_log_group_role" { + count = var.create_cloudtrail_log_group == "true" ? 1 : 0 + + name = "${var.cloudtrail_name}-cloudwatch-logs" + + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [{ + Effect = "Allow", + Principal = { + Service = "cloudtrail.amazonaws.com" + }, + Action = "sts:AssumeRole" + }] + }) + + tags = { + "sra-solution" = var.sra_solution_name + } +} + +resource "aws_iam_role_policy" "cloudtrail_cloudwatch_logs_policy" { + count = var.create_cloudtrail_log_group == "true" ? 1 : 0 + + name = "sra-cloudtrail-cloudwatch-logs" + role = aws_iam_role.cloudtrail_log_group_role[0].id + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Sid = "CreateLogStreamAndEvents", + Effect = "Allow", + Action = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + Resource = "arn:${data.aws_partition.current.partition}:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:${aws_cloudwatch_log_group.cloudtrail_log_group[0].name}:log-stream:*" + } + ] + }) +} + +resource "aws_cloudwatch_log_group" "cloudtrail_log_group" { + #checkov:skip=CKV_AWS_158: Ensure that CloudWatch Log Group is encrypted by KMS + count = var.create_cloudtrail_log_group == "true" ? 1 : 0 + + name = "sra/${var.cloudtrail_name}" + kms_key_id = var.cloudtrail_log_group_kms_key != "" ? var.cloudtrail_log_group_kms_key : null + retention_in_days = var.cloudtrail_log_group_retention +} + +resource "aws_cloudwatch_log_group" "lambda_log_group" { + #checkov:skip=CKV_AWS_158: Ensure that CloudWatch Log Group is encrypted by KMS + count = var.create_lambda_log_group == "true" ? 1 : 0 + + name = "/aws/lambda/${var.cloudtrail_lambda_function_name}" + kms_key_id = var.lambda_log_group_kms_key != "" ? var.lambda_log_group_kms_key : null + retention_in_days = var.lambda_log_group_retention +} + +resource "aws_iam_role" "cloudtrail_lambda_role" { + name = var.cloudtrail_lambda_role_name + + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [{ + Effect = "Allow", + Principal = { + Service = "lambda.amazonaws.com" + }, + Action = "sts:AssumeRole" + }] + }) + + tags = { + "sra-solution" = var.sra_solution_name + } +} +######################################################################## +# Lambda Policies +######################################################################## +resource "aws_iam_role_policy" "cloudtrail_log_group_policy" { + name = "sra-cloudtrail-org-policy-logs" + role = aws_iam_role.cloudtrail_lambda_role.id + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Sid = "CloudWatchLogs", + Effect = "Allow", + Action = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ], + Resource = "arn:${data.aws_partition.current.partition}:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/${var.cloudtrail_lambda_function_name}:log-stream:*" + } + ] + }) +} + +resource "aws_iam_role_policy" "cloudtrail_policy" { + #checkov:skip=CKV_AWS_290: Ensure IAM policies does not allow write access without constraints + + name = "sra-cloudtrail-org-policy-cloudtrail" + role = aws_iam_role.cloudtrail_lambda_role.id + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Sid = "AllowCloudTrail", + Effect = "Allow", + Action = [ + "cloudtrail:AddTags", + "cloudtrail:CreateTrail", + "cloudtrail:DeleteTrail", + "cloudtrail:GetEventSelectors", + "cloudtrail:PutEventSelectors", + "cloudtrail:RemoveTags", + "cloudtrail:StartLogging", + "cloudtrail:StopLogging", + "cloudtrail:UpdateTrail", + ], + Resource = "arn:${data.aws_partition.current.partition}:cloudtrail:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:trail/*" + }, + { + Sid = "AllowCloudTrailDelegatedAdministrator", + Effect = "Allow", + Action = [ + "cloudtrail:RegisterOrganizationDelegatedAdmin", + "cloudtrail:DeregisterOrganizationDelegatedAdmin", + ], + Resource = "*" + }, + { + Sid = "RegisterDeregisterDelegatedAdministrator", + Effect = "Allow", + Action = [ + "organizations:DeregisterDelegatedAdministrator", + "organizations:RegisterDelegatedAdministrator", + ], + Condition = { + StringLikeIfExists = { + "organizations:ServicePrincipal" : "cloudtrail.amazonaws.com" + } + }, + Resource = "*" + } + ] + }) +} + +resource "aws_iam_role_policy" "cloudtrail_org_policy" { + name = "cloudtrail-org-policy-organization" + role = aws_iam_role.cloudtrail_lambda_role.id + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Sid = "AllowOrganizationsAccess", + Effect = "Allow", + Action = [ + "organizations:DescribeOrganization", + "organizations:ListAWSServiceAccessForOrganization", + "organizations:ListAccounts", + "organizations:ListDelegatedAdministrators", + ], + Resource = "*" + }, + { + Sid = "AWSServiceAccess", + Effect = "Allow", + Action = [ + "organizations:DisableAWSServiceAccess", + "organizations:EnableAWSServiceAccess", + ], + Condition = { + StringLikeIfExists = { + "organizations:ServicePrincipal" : "cloudtrail.amazonaws.com" + } + }, + Resource = "*" + } + ] + }) +} + +resource "aws_iam_role_policy" "cloudtrail_iam_policy" { + name = "sra-cloudtrail-org-policy-iam" + role = aws_iam_role.cloudtrail_lambda_role.id + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Sid = "AllowReadIamActions", + Effect = "Allow", + Action = "iam:GetRole", + Resource = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/*" + }, + { + Sid = "AllowCreateDeleteServiceLinkedRole", + Effect = "Allow", + Action = [ + "iam:CreateServiceLinkedRole", + "iam:DeleteServiceLinkedRole", + ], + Resource = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/cloudtrail.amazonaws.com/AWSServiceRoleForCloudTrail*" + } + ] + }) +} + +resource "aws_iam_role_policy" "cloudtrail_cloudwatch_logs_policy2" { + count = var.create_cloudtrail_log_group == "true" ? 1 : 0 + + name = "cloudtrail-org-policy-organization2" + role = aws_iam_role.cloudtrail_lambda_role.id + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Sid = "AllowPassRoleForCWLogGroupRole", + Effect = "Allow", + Action = "iam:PassRole", + Resource = aws_iam_role.cloudtrail_log_group_role[0].arn, + Condition = { + StringEqualsIfExists = { + "iam:PassedToService" : "cloudtrail.amazonaws.com" + } + } + }, + ] + }) +} + +######################################################################## +# Lambda Functions +######################################################################## +data "archive_file" "hash_check" { + type = "zip" + source_dir = local.src_path + output_path = "${path.module}/lambda/lambda_function.zip" + excludes = ["lambda_function.zip, data.zip"] +} + +resource "null_resource" "package_lambda" { + triggers = { + src_hash = "${data.archive_file.hash_check.output_sha}" + } + + provisioner "local-exec" { + command = < + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + + +## Table of Contents + +- [Introduction](#introduction) +- [Deployed Resource Details](#deployed-resource-details) +- [Implementation Instructions](#implementation-instructions) +- [Requirements](#requirements) +- [Providers](#providers) +- [Modules](#modules) +- [Resources](#resources) +- [Inputs](#inputs) +- [Outputs](#outputs) + +--- + +## Introduction + +This Terraform module deploys GuardDuty Organization AWS SRA solution. + +The common pre-requisite solution must be installed, in the management account, prior to installing this solution. + +Information on the resources deployed as well as terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for more information and installation instructions. + +*For the CloudFormation version of this AWS SRA solution as well as more information please navigate to the [AWS SRA GuardDuty solution documentation](./../../../solutions/guardduty/guardduty_org/README.md) page.* + +--- + +## Deployed Resource Details + +![Architecture](./../../../solutions/guardduty/guardduty_org/documentation/guardduty-org-terraform.png) + +### 1.0 Organization Management Account + +#### 1.1 AWS Lambda Function + +- See [1.2 AWS Lambda Function](./../../../solutions/guardduty/guardduty_org/README.md#12-aws-lambda-function) + +#### 1.2 Lambda Execution IAM Role + +- See [1.3 Lambda Execution IAM Role](./../../../solutions/guardduty/guardduty_org/README.md#13-lambda-execution-iam-role) + +#### 1.3 Lambda CloudWatch Log Group + +- See [1.4 Lambda CloudWatch Log Group](./../../../solutions/guardduty/guardduty_org/README.md#14-lambda-cloudwatch-log-group) + +#### 1.4 Configuration SNS Topic + +- See [1.5 Configuration SNS Topic](./../../../solutions/guardduty/guardduty_org/README.md#15-configuration-sns-topic) + +#### 1.5 Dead Letter Queue (DLQ) + +- See [1.6 Dead Letter Queue (DLQ)](./../../../solutions/guardduty/guardduty_org/README.md#16-dead-letter-queue-dlq) + +#### 1.6 Alarm SNS Topic + +- See [1.7 Alarm SNS Topic](./../../../solutions/guardduty/guardduty_org/README.md#17-alarm-sns-topic) + +#### 1.7 GuardDuty + +- See [1.8 GuardDuty](./../../../solutions/guardduty/guardduty_org/README.md#18-guardduty) + +#### 1.8 Lambda Layer + +- See [1.9 Lambda Layer](./../../../solutions/guardduty/guardduty_org/README.md#19-lambda-layer) + +--- + +### 2.0 Log Archive Account + +#### 2.1 GuardDuty Delivery S3 Bucket + +- See [2.2 GuardDuty Delivery S3 Bucket](./../../../solutions/guardduty/guardduty_org/README.md#22-guardduty-delivery-s3-bucket) + +#### 2.2 GuardDuty + +- See [2.3 GuardDuty](./../../../solutions/guardduty/guardduty_org/README.md#23-guardduty) + +--- + +### 3.0 Audit (Security Tooling) Account + +#### 3.1 GuardDuty Delivery KMS Key + +- See [3.2 GuardDuty Delivery KMS Key](./../../../solutions/guardduty/guardduty_org/README.md#32-guardduty-delivery-kms-key) + +#### 3.2 Configuration IAM Role + +- See [3.3 Configuration IAM Role](./../../../solutions/guardduty/guardduty_org/README.md#33-configuration-iam-role) + +#### 3.3 GuardDuty + +- See [3.4 GuardDuty](./../../../solutions/guardduty/guardduty_org/README.md#34-guardduty) + +--- + +### 4.0 All Existing and Future Organization Member Accounts + +#### 4.1 GuardDuty + +- See [4.1 GuardDuty](./../../../solutions/guardduty/guardduty_org/README.md#41-guardduty) + +#### 4.2 Delete Detector Role + +- See [4.2 Delete Detector Role](./../../../solutions/guardduty/guardduty_org/README.md#42-delete-detector-role) + +--- + +## Implementation Instructions + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for installation instructions. + + +--- + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws.main](#provider\_aws.main) | >= 5.1.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [guardduty\_configuration](#module\_guardduty\_configuration) | ./gd_configuration | n/a | +| [guardduty\_configuration\_role](#module\_guardduty\_configuration\_role) | ./configuration_role | n/a | +| [guardduty\_delete\_role](#module\_guardduty\_delete\_role) | ./delete_detector | n/a | +| [guardduty\_delivery\_key](#module\_guardduty\_delivery\_key) | ./kms_key | n/a | +| [guardduty\_s3\_bucket](#module\_guardduty\_s3\_bucket) | ./s3 | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [account\_id](#input\_account\_id) | Current Account ID | `string` | n/a | yes | +| [audit\_account\_id](#input\_audit\_account\_id) | AWS Account ID of the Control Tower Audit account. | `string` | n/a | yes | +| [disable\_guard\_duty](#input\_disable\_guard\_duty) | Update to 'true' to disable GuardDuty in all accounts and regions before deleting the TF. | `string` | n/a | yes | +| [enable\_eks\_addon\_management](#input\_enable\_eks\_addon\_management) | Auto enable EKS Add-on Management | `string` | n/a | yes | +| [enable\_eks\_runtime\_monitoring](#input\_enable\_eks\_runtime\_monitoring) | Auto enable EKS Runtime Monitoring | `string` | n/a | yes | +| [enable\_kubernetes\_audit\_logs](#input\_enable\_kubernetes\_audit\_logs) | Auto enable Kubernetes Audit Logs | `string` | n/a | yes | +| [enable\_lambda\_network\_logs](#input\_enable\_lambda\_network\_logs) | Auto enable Lambda Network Logs | `string` | n/a | yes | +| [enable\_malware\_protection](#input\_enable\_malware\_protection) | Auto enable Malware Protection | `string` | n/a | yes | +| [enable\_rds\_login\_events](#input\_enable\_rds\_login\_events) | Auto enable RDS Login Events | `string` | n/a | yes | +| [enable\_s3\_logs](#input\_enable\_s3\_logs) | Auto enable S3 logs | `string` | n/a | yes | +| [finding\_publishing\_frequency](#input\_finding\_publishing\_frequency) | Finding publishing frequency | `string` | n/a | yes | +| [guardduty\_control\_tower\_regions\_only](#input\_guardduty\_control\_tower\_regions\_only) | Only enable in the Control Tower governed regions | `string` | n/a | yes | +| [home\_region](#input\_home\_region) | Name of the Control Tower home region | `string` | n/a | yes | +| [log\_archive\_account\_id](#input\_log\_archive\_account\_id) | AWS Account ID of the Control Tower Log Archive account. | `string` | n/a | yes | +| [management\_account\_id](#input\_management\_account\_id) | Organization Management Account ID | `string` | n/a | yes | +| [organization\_id](#input\_organization\_id) | AWS Organization ID | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [guard\_duty\_results](#output\_guard\_duty\_results) | n/a | + +--- + diff --git a/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/data.tf b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/main.tf b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/main.tf new file mode 100644 index 00000000..8de7f1ef --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/main.tf @@ -0,0 +1,167 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_iam_role" "configuration_role" { + name = var.guardduty_org_configuration_role_name + assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json + + tags = { + "sra-solution" = var.sra_solution_name + } +} + +resource "aws_iam_policy" "organizations_policy" { + name = "sra-guardduty-org-policy-organizations" + policy = data.aws_iam_policy_document.organizations_policy.json + description = "Policy for organizations" +} + +resource "aws_iam_policy" "guardduty_policy" { + name = "sra-guardduty-org-policy-guardduty" + policy = data.aws_iam_policy_document.guardduty_policy.json + description = "Policy for GuardDuty" +} + +resource "aws_iam_policy" "iam_policy" { + name = "sra-guardduty-org-policy-iam" + policy = data.aws_iam_policy_document.iam_policy.json + description = "Policy for IAM" +} + +data "aws_iam_policy_document" "assume_role_policy" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + + principals { + type = "AWS" + identifiers = ["arn:${data.aws_partition.current.partition}:iam::${var.management_account_id}:root"] + } + + condition { + test = "StringEquals" + variable = "aws:PrincipalArn" + values = ["arn:${data.aws_partition.current.partition}:iam::${var.management_account_id}:role/${var.guardduty_org_lambda_role_name}"] + } + } +} + +data "aws_iam_policy_document" "organizations_policy" { + statement { + sid = "OrganizationsListAccounts" + effect = "Allow" + actions = ["organizations:ListAccounts"] + resources = ["*"] + } +} + +data "aws_iam_policy_document" "guardduty_policy" { + statement { + sid = "GuardDutyNoResource" + effect = "Allow" + actions = ["guardduty:ListDetectors"] + resources = ["*"] + } + + statement { + sid = "GuardDutyWithResource" + effect = "Allow" + actions = [ + "guardduty:CreateMembers", + "guardduty:CreatePublishingDestination", + "guardduty:DeleteDetector", + "guardduty:DeleteMembers", + "guardduty:DisassociateMembers", + "guardduty:ListMembers", + "guardduty:ListPublishingDestinations", + "guardduty:UpdateDetector", + "guardduty:UpdateMemberDetectors", + "guardduty:UpdateOrganizationConfiguration", + "guardduty:UpdatePublishingDestination", + ] + resources = [ + "arn:${data.aws_partition.current.partition}:guardduty:*:${data.aws_caller_identity.current.account_id}:/detector/*", + "arn:${data.aws_partition.current.partition}:guardduty:*:${data.aws_caller_identity.current.account_id}:detector/*", + ] + } +} + +data "aws_iam_policy_document" "iam_policy" { + #checkov:skip=CKV_AWS_111: Ensure IAM policies does not allow write access without constraints + #checkov:skip=CKV_AWS_356: Ensure no IAM policies documents allow "*" as a statement's resource for restrictable actions + statement { + sid = "AllowReadIamActions" + effect = "Allow" + actions = ["iam:GetRole"] + resources = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/*"] + } + + statement { + sid = "AllowCreateDeleteServiceLinkedRole" + effect = "Allow" + actions = [ + "iam:CreateServiceLinkedRole", + "iam:DeleteServiceLinkedRole", + ] + condition { + test = "StringLike" + variable = "iam:AWSServiceName" + values = ["guardduty.amazonaws.com", "malware-protection.guardduty.amazonaws.com"] + } + resources = [ + "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty", + "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role//malware-protection.guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDutyMalwareProtection" + ] + } + + statement { + sid = "AllowEnableMalwareProtection" + effect = "Allow" + actions = [ + "organizations:EnableAWSServiceAccess", + "organizations:RegisterDelegatedAdministrator", + "organizations:ListDelegatedAdministrators", + "organizations:ListAWSServiceAccessForOrganization", + "organizations:DescribeOrganizationalUnit", + "organizations:DescribeAccount", + "organizations:DescribeOrganization" + ] + resources = ["*"] + } + + statement { + sid = "AllowGetRoleMalwareProtection" + effect = "Allow" + actions = [ + "iam:GetRole", + ] + resources = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role//malware-protection.guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDutyMalwareProtection"] + } + + statement { + sid = "AllowPolicyActions" + effect = "Allow" + actions = [ + "iam:DeleteRolePolicy", + "iam:PutRolePolicy", + ] + resources = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty"] + } +} + +resource "aws_iam_role_policy_attachment" "organizations_attachment" { + policy_arn = aws_iam_policy.organizations_policy.arn + role = aws_iam_role.configuration_role.name +} + +resource "aws_iam_role_policy_attachment" "guardduty_attachment" { + policy_arn = aws_iam_policy.guardduty_policy.arn + role = aws_iam_role.configuration_role.name +} + +resource "aws_iam_role_policy_attachment" "iam_attachment" { + policy_arn = aws_iam_policy.iam_policy.arn + role = aws_iam_role.configuration_role.name +} diff --git a/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/output.tf b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/output.tf new file mode 100644 index 00000000..f36b1f60 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/output.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +output "guardduty_org_configuration_role_name" { + value = aws_iam_role.configuration_role.name +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/providers.tf b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/providers.tf new file mode 100644 index 00000000..226f1ca4 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/providers.tf @@ -0,0 +1,13 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.1.0" + } + } +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/variables.tf b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/variables.tf new file mode 100644 index 00000000..e68f2b55 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/configuration_role/variables.tf @@ -0,0 +1,27 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "guardduty_org_configuration_role_name" { + description = "GuardDuty Configuration IAM Role Name" + type = string + default = "sra-guardduty-org-configuration" +} + +variable "management_account_id" { + description = "Organization Management Account ID" + type = string +} + +variable "guardduty_org_lambda_role_name" { + description = "Lambda Role Name" + type = string + default = "sra-guardduty-org-lambda" +} + +variable "sra_solution_name" { + description = "The SRA solution name. The default value is the folder name of the solution" + type = string + default = "sra-guardduty-org" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/data.tf b/aws_sra_examples/terraform/solutions/guard_duty/data.tf new file mode 100644 index 00000000..b9bcf777 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/data.tf @@ -0,0 +1,14 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" { + provider = aws.main +} +data "aws_caller_identity" "current" { + provider = aws.main +} +data "aws_region" "current" { + provider = aws.main +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/data.tf b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/main.tf b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/main.tf new file mode 100644 index 00000000..71115ea6 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/main.tf @@ -0,0 +1,57 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_iam_policy_document" "delete_detector_policy" { + statement { + sid = "GuardDutyNoResource" + effect = "Allow" + actions = ["guardduty:ListDetectors"] + resources = ["*"] + } + + statement { + sid = "GuardDutyWithResource" + effect = "Allow" + actions = ["guardduty:DeleteDetector"] + resources = ["arn:${data.aws_partition.current.partition}:guardduty:*:${data.aws_caller_identity.current.account_id}:detector/*"] + } +} + +resource "aws_iam_policy" "delete_detector_policy" { + name = "sra-guardduty-org-policy-guardduty-delete" + policy = data.aws_iam_policy_document.delete_detector_policy.json + description = "Policy for deleting GuardDuty detectors in the organization" +} + +data "aws_iam_policy_document" "assume_role_policy" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "AWS" + identifiers = ["arn:${data.aws_partition.current.partition}:iam::${var.management_account_id}:root"] + } + condition { + test = "StringEquals" + variable = "aws:PrincipalArn" + values = ["arn:${data.aws_partition.current.partition}:iam::${var.management_account_id}:role/${var.guardduty_org_lambda_role_name}"] + } + } +} + +resource "aws_iam_role" "delete_detector_role" { + name = var.delete_detector_role_name + + assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json + + tags = { + "sra-solution" = var.sra_solution_name + } +} + +resource "aws_iam_role_policy_attachment" "delete_detector_policy_attachment" { + policy_arn = aws_iam_policy.delete_detector_policy.arn + role = aws_iam_role.delete_detector_role.name +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/output.tf b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/output.tf new file mode 100644 index 00000000..75bf9dea --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/output.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +output "delete_detector_role_name" { + value = aws_iam_role.delete_detector_role.name +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/providers.tf b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/providers.tf new file mode 100644 index 00000000..226f1ca4 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/providers.tf @@ -0,0 +1,13 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.1.0" + } + } +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/variables.tf b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/variables.tf new file mode 100644 index 00000000..fb91ddfc --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/delete_detector/variables.tf @@ -0,0 +1,27 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "delete_detector_role_name" { + description = "Delete Detector IAM Role Name" + type = string + default = "sra-guardduty-delete-detector" +} + +variable "guardduty_org_lambda_role_name" { + description = "Lambda Role Name" + type = string + default = "sra-guardduty-org-lambda" +} + +variable "management_account_id" { + description = "Organization Management Account ID" + type = string +} + +variable "sra_solution_name" { + description = "The SRA solution name" + type = string + default = "sra-guardduty-org" +} diff --git a/aws_sra_examples/terraform/solutions/guard_duty/gd_configuration/data.tf b/aws_sra_examples/terraform/solutions/guard_duty/gd_configuration/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/gd_configuration/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/guard_duty/gd_configuration/invoke.tf b/aws_sra_examples/terraform/solutions/guard_duty/gd_configuration/invoke.tf new file mode 100644 index 00000000..b10152f2 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/gd_configuration/invoke.tf @@ -0,0 +1,34 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_lambda_invocation" "lambda_invoke" { + function_name = aws_lambda_function.guardduty_lambda_function.function_name + + input = jsonencode({ + "RequestType" : "Update", + "ResourceType" : "Custom::LambdaCustomResource", + "ResourceProperties" : { + "RequestType" : "Update", + "ServiceToken" : "${aws_lambda_function.guardduty_lambda_function.arn}", + "DELEGATED_ADMIN_ACCOUNT_ID" : "${var.audit_account_id}", + "SNS_TOPIC_ARN" : "${aws_sns_topic.guardduty_topic.arn}", + "KMS_KEY_ARN" : "${var.guardduty_org_delivery_kms_key_arn}", + "CONTROL_TOWER_REGIONS_ONLY" : "${var.guardduty_control_tower_regions_only}", + "DELETE_DETECTOR_ROLE_NAME" : "${var.delete_detector_role_name}", + "CONFIGURATION_ROLE_NAME" : "${var.guardduty_org_configuration_role_name}", + "DISABLE_GUARD_DUTY" : "${var.disable_guard_duty}", + "FINDING_PUBLISHING_FREQUENCY" : "${var.finding_publishing_frequency}", + "AUTO_ENABLE_S3_LOGS" : "${var.auto_enable_s3_logs}", + "PUBLISHING_DESTINATION_BUCKET_ARN" : "${var.publishing_destination_bucket_arn}", + "ENABLED_REGIONS" : "${var.enabled_regions}", + "ENABLE_EKS_AUDIT_LOGS" : "${var.enable_kubernetes_audit_logs}", + "AUTO_ENABLE_MALWARE_PROTECTION" : "${var.enable_malware_protection}", + "ENABLE_RDS_LOGIN_EVENTS" : "${var.enable_rds_login_events}", + "ENABLE_EKS_RUNTIME_MONITORING" : "${var.enable_eks_runtime_monitoring}", + "ENABLE_EKS_ADDON_MANAGEMENT" : "${var.enable_eks_addon_management}", + "ENABLE_LAMBDA_NETWORK_LOGS" : "${var.enable_lambda_network_logs}", + } + }) +} diff --git a/aws_sra_examples/terraform/solutions/guard_duty/gd_configuration/main.tf b/aws_sra_examples/terraform/solutions/guard_duty/gd_configuration/main.tf new file mode 100644 index 00000000..ec55c2f0 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/guard_duty/gd_configuration/main.tf @@ -0,0 +1,468 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +locals { + #TODO: Figure out? + graviton_regions = [ + "ap-northeast-1", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ] + account_id = data.aws_caller_identity.current.account_id + region = data.aws_region.current.name + create_dlq_alarm = var.sra_alarm_email != "" ? true : false + src_path = "${path.root}/../../solutions/guardduty/guardduty_org/lambda/src/" +} + +######################################################################## +# Lambda Policies Documents +######################################################################## + +data "aws_iam_policy_document" "assume_role" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "guardduty_lambda_role" { + name = var.guardduty_lambda_role_name + description = "Role for '${var.guardduty_lambda_role_name}' Lambda function" + + assume_role_policy = data.aws_iam_policy_document.assume_role.json + + tags = { + "sra-solution" = var.sra_solution_name + } +} + +data "aws_iam_policy_document" "sra_guardduty_org_policy_cloudformation" { + statement { + sid = "CloudFormation" + effect = "Allow" + actions = ["cloudformation:ListStackInstances"] + resources = ["arn:${data.aws_partition.current.partition}:cloudformation:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:stackset/AWSControlTowerBP-*"] + } +} + +data "aws_iam_policy_document" "sra_guardduty_org_policy_ssm_access" { + statement { + sid = "SSMAccess" + effect = "Allow" + actions = [ + "ssm:GetParameter", + "ssm:GetParameters", + ] + resources = ["arn:${data.aws_partition.current.partition}:ssm:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:parameter/sra*"] + } +} + +data "aws_iam_policy_document" "sra_guardduty_org_policy_guardduty" { + statement { + sid = "GuardDutyNoResource" + effect = "Allow" + actions = [ + "guardduty:DisableOrganizationAdminAccount", + "guardduty:EnableOrganizationAdminAccount", + "guardduty:ListDetectors", + "guardduty:ListOrganizationAdminAccounts", + ] + resources = ["*"] + } + + statement { + sid = "GuardDutyWithResource" + effect = "Allow" + actions = [ + "guardduty:DeleteDetector", + "guardduty:ListMembers", + ] + resources = [ + "arn:${data.aws_partition.current.partition}:guardduty:*:${data.aws_caller_identity.current.account_id}:detector/*", + "arn:${data.aws_partition.current.partition}:guardduty:*:${data.aws_caller_identity.current.account_id}:/detector/*", + ] + } +} + +data "aws_iam_policy_document" "sra_guardduty_org_policy_iam" { + statement { + sid = "AllowReadIamActions" + effect = "Allow" + actions = ["iam:GetRole"] + resources = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/*"] + } + + statement { + sid = "AllowCreateServiceLinkedRole" + effect = "Allow" + actions = ["iam:CreateServiceLinkedRole"] + condition { + test = "StringLike" + variable = "iam:AWSServiceName" + values = ["guardduty.amazonaws.com"] + } + resources = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty"] + } + + statement { + sid = "AllowPolicyActions" + effect = "Allow" + actions = ["iam:PutRolePolicy"] + resources = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty"] + } + + statement { + sid = "AssumeRole" + effect = "Allow" + actions = ["sts:AssumeRole"] + condition { + test = "StringEquals" + variable = "aws:PrincipalOrgId" + values = [var.organization_id] + } + resources = [ + "arn:${data.aws_partition.current.partition}:iam::*:role/${var.delete_detector_role_name}", + "arn:${data.aws_partition.current.partition}:iam::*:role/${var.guardduty_org_configuration_role_name}", + ] + } +} + +data "aws_iam_policy_document" "sra_guardduty_org_policy_logs" { + statement { + sid = "CreateLogGroupAndEvents" + effect = "Allow" + actions = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"] + resources = ["arn:${data.aws_partition.current.partition}:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/${var.guardduty_lambda_function_name}:log-stream:*"] + } +} + +data "aws_iam_policy_document" "sra_guardduty_org_policy_organizations" { + #checkov:skip=CKV_AWS_111: Ensure IAM policies does not allow write access without constraints + statement { + sid = "OrganizationsReadAccess" + effect = "Allow" + actions = [ + "organizations:DescribeOrganization", + "organizations:ListAWSServiceAccessForOrganization", + "organizations:ListAccounts", + "organizations:ListDelegatedAdministrators", + ] + resources = ["*"] + } + + statement { + sid = "RegisterDeregisterDelegatedAdministrator" + effect = "Allow" + actions = [ + "organizations:DeregisterDelegatedAdministrator", + "organizations:DisableAWSServiceAccess", + "organizations:EnableAWSServiceAccess", + "organizations:RegisterDelegatedAdministrator", + ] + condition { + test = "StringLikeIfExists" + variable = "organizations:ServicePrincipal" + values = ["guardduty.amazonaws.com", "malware-protection.guardduty.amazonaws.com"] + } + resources = ["*"] + } +} + +data "aws_iam_policy_document" "sra_guardduty_org_policy_sns" { + statement { + sid = "SNSPublish" + effect = "Allow" + actions = ["sns:Publish"] + resources = [aws_sns_topic.guardduty_topic.arn] + } +} + +data "aws_iam_policy_document" "sra_guardduty_org_policy_sqs" { + statement { + sid = "SQSSendMessage" + effect = "Allow" + actions = ["sqs:SendMessage"] + resources = [aws_sqs_queue.guardduty_dlq.arn] + } +} + +######################################################################## +# Lambda Policies +######################################################################## + +resource "aws_iam_policy" "sra_guardduty_org_policy_logs" { + name = "sra-guardduty-org-policy-logs" + policy = data.aws_iam_policy_document.sra_guardduty_org_policy_logs.json +} + +resource "aws_iam_policy" "sra_guardduty_org_policy_organizations" { + name = "sra-guardduty-org-policy-organizations" + policy = data.aws_iam_policy_document.sra_guardduty_org_policy_organizations.json +} + +resource "aws_iam_policy" "sra_guardduty_org_policy_sns" { + name = "sra-guardduty-org-policy-sns" + policy = data.aws_iam_policy_document.sra_guardduty_org_policy_sns.json +} + +resource "aws_iam_policy" "sra_guardduty_org_policy_sqs" { + name = "sra-guardduty-org-policy-sqs" + policy = data.aws_iam_policy_document.sra_guardduty_org_policy_sqs.json +} + +resource "aws_iam_policy" "sra_guardduty_org_policy_iam" { + name = "sra-guardduty-org-policy-iam" + policy = data.aws_iam_policy_document.sra_guardduty_org_policy_iam.json +} + +resource "aws_iam_policy" "sra_guardduty_org_policy_cloudformation" { + name = "sra-guardduty-org-policy-cloudformation" + policy = data.aws_iam_policy_document.sra_guardduty_org_policy_cloudformation.json +} + +resource "aws_iam_policy" "sra_guardduty_org_policy_ssm_access" { + name = "ssm-access" + policy = data.aws_iam_policy_document.sra_guardduty_org_policy_ssm_access.json +} + +resource "aws_iam_policy" "sra_guardduty_org_policy_guardduty" { + name = "sra-guardduty-org-policy-guardduty" + policy = data.aws_iam_policy_document.sra_guardduty_org_policy_guardduty.json +} + +######################################################################## +# Lambda Attachment +######################################################################## + +resource "aws_iam_policy_attachment" "sra_guardduty_org_policy_attachment_logs" { + name = "sra-guardduty-org-policy-attachment-logs" + roles = [aws_iam_role.guardduty_lambda_role.name] + policy_arn = aws_iam_policy.sra_guardduty_org_policy_logs.arn +} + +resource "aws_iam_policy_attachment" "sra_guardduty_org_policy_attachment_organizations" { + name = "sra-guardduty-org-policy-attachment-organizations" + roles = [aws_iam_role.guardduty_lambda_role.name] + policy_arn = aws_iam_policy.sra_guardduty_org_policy_organizations.arn +} + +resource "aws_iam_policy_attachment" "sra_guardduty_org_policy_attachment_sns" { + name = "sra-guardduty-org-policy-attachment-sns" + roles = [aws_iam_role.guardduty_lambda_role.name] + policy_arn = aws_iam_policy.sra_guardduty_org_policy_sns.arn +} + +resource "aws_iam_policy_attachment" "sra_guardduty_org_policy_attachment_sqs" { + name = "sra-guardduty-org-policy-attachment-sqs" + roles = [aws_iam_role.guardduty_lambda_role.name] + policy_arn = aws_iam_policy.sra_guardduty_org_policy_sqs.arn +} + +resource "aws_iam_policy_attachment" "sra_guardduty_org_policy_attachment_iam" { + name = "sra-guardduty-org-policy-attachment-iam" + roles = [aws_iam_role.guardduty_lambda_role.name] + policy_arn = aws_iam_policy.sra_guardduty_org_policy_iam.arn +} + +resource "aws_iam_policy_attachment" "sra_guardduty_org_policy_attachment_cloudformation" { + name = "sra-guardduty-org-policy-attachment-cloudformation" + roles = [aws_iam_role.guardduty_lambda_role.name] + policy_arn = aws_iam_policy.sra_guardduty_org_policy_cloudformation.arn +} + +resource "aws_iam_policy_attachment" "sra_guardduty_org_policy_attachment_ssm_access" { + name = "sra-guardduty-org-policy-attachment-ssm-access" + roles = [aws_iam_role.guardduty_lambda_role.name] + policy_arn = aws_iam_policy.sra_guardduty_org_policy_ssm_access.arn +} + +resource "aws_iam_policy_attachment" "sra_guardduty_org_policy_attachment_guardduty" { + name = "sra-guardduty-org-policy-attachment-guardduty" + roles = [aws_iam_role.guardduty_lambda_role.name] + policy_arn = aws_iam_policy.sra_guardduty_org_policy_guardduty.arn +} + +######################################################################## +# Lambda Function +######################################################################## + +data "archive_file" "hash_check" { + type = "zip" + source_dir = local.src_path + output_path = "${path.module}/lambda/lambda_function.zip" + excludes = ["lambda_function.zip, data.zip"] +} + +resource "null_resource" "package_lambda" { + triggers = { + src_hash = "${data.archive_file.hash_check.output_sha}" + } + + provisioner "local-exec" { + command = < + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + +## Table of Contents + +- [Introduction](#introduction) +- [Deployed Resource Details](#deployed-resource-details) +- [Implementation Instructions](#implementation-instructions) +- [Requirements](#requirements) +- [Providers](#providers) +- [Modules](#modules) +- [Resources](#resources) +- [Inputs](#inputs) +- [Outputs](#outputs) + +--- + +## Introduction + +This Terraform module deploys the IAM Access Analyzer AWS SRA solution. + +The common pre-requisite solution must be installed, in the management account, prior to installing this solution. + +Information on the resources deployed as well as terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for more information and installation instructions. + +*For the CloudFormation version of this AWS SRA solution as well as more information please navigate to the [AWS SRA IAM access analyzer solution documentation](./../../../solutions/iam/iam_access_analyzer/README.md) page.* + +--- + +## Deployed Resource Details + +![Architecture](./../../../solutions/iam/iam_access_analyzer/documentation/iam-access-analyzer-terraform.png) + +### 1.0 Organization Management Account + +#### 1.1 AWS Organizations + +- See [1.2 AWS Organizations](./../../../solutions/iam/iam_access_analyzer/README.md#12-aws-organizations) + +#### 1.2 Account AWS IAM Access Analyzer + +- See [1.3 Account AWS IAM Access Analyzer](./../../../solutions/iam/iam_access_analyzer/README.md#13-account-aws-iam-access-analyzer) + +--- + +### 2.0 Audit Account (Security Tooling) + +#### 2.1 Account AWS IAM Access Analyzer + +- See [2.2 Account AWS IAM Access Analyzer](./../../../solutions/iam/iam_access_analyzer/README.md#22-account-aws-iam-access-analyzer) + +#### 2.2 Organization AWS IAM Access Analyzer + +- See [2.3 Organization AWS IAM Access Analyzer](./../../../solutions/iam/iam_access_analyzer/README.md#23-organization-aws-iam-access-analyzer) + +--- + +### 3.0 All Existing and Future Organization Member Accounts + +#### 3.1 Account AWS IAM Access Analyzer + +- See [3.2 Account AWS IAM Access Analyzer](./../../../solutions/iam/iam_access_analyzer/README.md#32-account-aws-iam-access-analyzer) + +--- + +## Implementation Instructions + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for installation instructions. + + +--- + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 5.1.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [account\_analyzer](#module\_account\_analyzer) | ./account | n/a | +| [org\_analyzer](#module\_org\_analyzer) | ./org | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [access\_analyzer\_name\_prefix](#input\_access\_analyzer\_name\_prefix) | Access Analyzer Name Prefix. The Account ID will be appended to the name. | `string` | `"sra-account-access-analyzer"` | no | +| [account\_id](#input\_account\_id) | Current Account ID | `string` | n/a | yes | +| [audit\_account\_id](#input\_audit\_account\_id) | AWS Account ID of the Control Tower Audit account. | `string` | n/a | yes | +| [home\_region](#input\_home\_region) | Name of the Control Tower home region | `string` | n/a | yes | +| [log\_archive\_account\_id](#input\_log\_archive\_account\_id) | AWS Account ID of the Control Tower Log Archive account. | `string` | n/a | yes | +| [org\_access\_analyzer\_name](#input\_org\_access\_analyzer\_name) | Organization Access Analyzer Name | `string` | `"sra-organization-access-analyzer"` | no | +| [sra\_solution\_name](#input\_sra\_solution\_name) | The SRA solution name. The default value is the folder name of the solution | `string` | `"sra-iam-access-analyzer"` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_access_analyzer/account/data.tf b/aws_sra_examples/terraform/solutions/iam_access_analyzer/account/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_access_analyzer/account/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_access_analyzer/account/main.tf b/aws_sra_examples/terraform/solutions/iam_access_analyzer/account/main.tf new file mode 100644 index 00000000..19c3e974 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_access_analyzer/account/main.tf @@ -0,0 +1,14 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_accessanalyzer_analyzer" "account_access_analyzer" { + analyzer_name = "${var.access_analyzer_name_prefix}-${data.aws_caller_identity.current.account_id}" + + tags = { + "sra-solution" = var.sra_solution_name + } + + type = "ACCOUNT" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_access_analyzer/account/variables.tf b/aws_sra_examples/terraform/solutions/iam_access_analyzer/account/variables.tf new file mode 100644 index 00000000..cebaacf9 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_access_analyzer/account/variables.tf @@ -0,0 +1,16 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "access_analyzer_name_prefix" { + type = string + default = "sra-account-access-analyzer" + description = "Access Analyzer Name Prefix. The Account ID will be appended to the name." +} + +variable "sra_solution_name" { + type = string + default = "sra-iam-access-analyzer" + description = "The SRA solution name. The default value is the folder name of the solution" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_access_analyzer/data.tf b/aws_sra_examples/terraform/solutions/iam_access_analyzer/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_access_analyzer/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_access_analyzer/main.tf b/aws_sra_examples/terraform/solutions/iam_access_analyzer/main.tf new file mode 100644 index 00000000..5e5acf05 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_access_analyzer/main.tf @@ -0,0 +1,23 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +locals { + is_audit_account = var.account_id == var.audit_account_id + is_log_account = var.account_id == var.log_archive_account_id + is_home_region = data.aws_region.current.name == var.home_region +} + +module "account_analyzer" { + source = "./account" + + access_analyzer_name_prefix = var.access_analyzer_name_prefix +} + +module "org_analyzer" { + count = local.is_audit_account ? 1 : 0 + + source = "./org" + + org_access_analyzer_name = var.org_access_analyzer_name +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_access_analyzer/org/main.tf b/aws_sra_examples/terraform/solutions/iam_access_analyzer/org/main.tf new file mode 100644 index 00000000..b727f5ce --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_access_analyzer/org/main.tf @@ -0,0 +1,14 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_accessanalyzer_analyzer" "rOrganizationAccessAnalyzer" { + analyzer_name = var.org_access_analyzer_name + + tags = { + "sra-solution" = var.sra_solution_name + } + + type = "ORGANIZATION" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_access_analyzer/org/variables.tf b/aws_sra_examples/terraform/solutions/iam_access_analyzer/org/variables.tf new file mode 100644 index 00000000..607493dc --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_access_analyzer/org/variables.tf @@ -0,0 +1,16 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "org_access_analyzer_name" { + description = "Organization Access Analyzer Name" + type = string + default = "sra-organization-access-analyzer" +} + +variable "sra_solution_name" { + description = "The SRA solution name. The default value is the folder name of the solution" + type = string + default = "sra-iam-access-analyzer" +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_access_analyzer/providers.tf b/aws_sra_examples/terraform/solutions/iam_access_analyzer/providers.tf new file mode 100644 index 00000000..226f1ca4 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_access_analyzer/providers.tf @@ -0,0 +1,13 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.1.0" + } + } +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_access_analyzer/variables.tf b/aws_sra_examples/terraform/solutions/iam_access_analyzer/variables.tf new file mode 100644 index 00000000..0755a03d --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_access_analyzer/variables.tf @@ -0,0 +1,42 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "account_id" { + description = "Current Account ID" + type = string +} + +variable "access_analyzer_name_prefix" { + type = string + default = "sra-account-access-analyzer" + description = "Access Analyzer Name Prefix. The Account ID will be appended to the name." +} + +variable "org_access_analyzer_name" { + description = "Organization Access Analyzer Name" + type = string + default = "sra-organization-access-analyzer" +} + +variable "sra_solution_name" { + type = string + default = "sra-iam-access-analyzer" + description = "The SRA solution name. The default value is the folder name of the solution" +} + +variable "home_region" { + description = "Name of the Control Tower home region" + type = string +} + +variable "audit_account_id" { + description = "AWS Account ID of the Control Tower Audit account." + type = string +} + +variable "log_archive_account_id" { + description = "AWS Account ID of the Control Tower Log Archive account." + type = string +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_password_policy/README.md b/aws_sra_examples/terraform/solutions/iam_password_policy/README.md new file mode 100644 index 00000000..d6fe3c1f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_password_policy/README.md @@ -0,0 +1,121 @@ +# AWS SRA IAM Password Policy Solution with Terraform + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + +## Table of Contents + +- [Introduction](#introduction) +- [Deployed Resource Details](#deployed-resource-details) +- [Implementation Instructions](#implementation-instructions) +- [Requirements](#requirements) +- [Providers](#providers) +- [Modules](#modules) +- [Resources](#resources) +- [Inputs](#inputs) +- [Outputs](#outputs) + +--- + +## Introduction + +This Terraform module deploys the IAM password policy AWS SRA solution. + +The common pre-requisite solution must be installed, in the management account, prior to installing this solution. + +Information on the resources deployed as well as terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for more information and installation instructions. + +*For the CloudFormation version of this AWS SRA solution as well as more information please navigate to the [AWS SRA IAM password policy solution documentation](./../../../solutions/iam/iam_password_policy/README.md) page.* + +--- + +## Deployed Resource Details + +![Architecture](./../../../solutions/iam/iam_password_policy/documentation/iam-password-policy-terraform.png) + +### 1.0 All Organization Accounts + +#### 1.2 AWS Lambda Function + +- See [1.2 AWS Lambda Function](./../../../solutions/iam/iam_password_policy/README.md#12-aws-lambda-function) + +#### 1.3 Amazon CloudWatch Log Group + +- See [1.3 Amazon CloudWatch Log Group](./../../../solutions/iam/iam_password_policy/README.md#13-amazon-cloudwatch-log-group) + +#### 1.4 Lambda Execution IAM Role + +- See [1.4 Lambda Execution IAM Role](./../../../solutions/iam/iam_password_policy/README.md#14-lambda-execution-iam-role) + +#### 1.5 IAM Password Policy + +- See [1.5 IAM Password Policy](./../../../solutions/iam/iam_password_policy/README.md#15-iam-password-policy) + +--- + +## Implementation Instructions + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for installation instructions. + +--- + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws.main](#provider\_aws.main) | >= 5.1.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [inspector\_configuration](#module\_inspector\_configuration) | ./configuration | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [allow\_users\_to\_change\_password](#input\_allow\_users\_to\_change\_password) | You can permit all IAM users in your account to use the IAM console to change their own passwords. | `string` | `"true"` | no | +| [create\_lambda\_log\_group](#input\_create\_lambda\_log\_group) | Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS Key for encryption. | `string` | `"false"` | no | +| [hard\_expiry](#input\_hard\_expiry) | You can prevent IAM users from choosing a new password after their current password has expired. | `string` | `"false"` | no | +| [home\_region](#input\_home\_region) | Name of the Control Tower home region | `string` | n/a | yes | +| [lambda\_function\_name](#input\_lambda\_function\_name) | Lambda function name | `string` | `"sra-iam-password-policy"` | no | +| [lambda\_log\_group\_kms\_key](#input\_lambda\_log\_group\_kms\_key) | (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side encryption keys. | `string` | `""` | no | +| [lambda\_log\_group\_retention](#input\_lambda\_log\_group\_retention) | Specifies the number of days you want to retain log events | `string` | `"14"` | no | +| [lambda\_log\_level](#input\_lambda\_log\_level) | Lambda Function Logging Level | `string` | `"INFO"` | no | +| [lambda\_role\_name](#input\_lambda\_role\_name) | Lambda role name | `string` | `"sra-iam-password-policy-lambda"` | no | +| [max\_password\_age](#input\_max\_password\_age) | You can set IAM user passwords to be valid for only the specified number of days. | `string` | `90` | no | +| [minimum\_password\_length](#input\_minimum\_password\_length) | You can specify the minimum number of characters allowed in an IAM user password. | `string` | `14` | no | +| [password\_reuse\_prevention](#input\_password\_reuse\_prevention) | You can prevent IAM users from reusing a specified number of previous passwords. | `string` | `24` | no | +| [require\_lowercase\_characters](#input\_require\_lowercase\_characters) | You can require that IAM user passwords contain at least one lowercase character from the ISO basic Latin alphabet (a to z). | `string` | `"true"` | no | +| [require\_numbers](#input\_require\_numbers) | You can require that IAM user passwords contain at least one numeric character (0 to 9). | `string` | `"true"` | no | +| [require\_symbols](#input\_require\_symbols) | You can require that IAM user passwords contain at least one of the following nonalphanumeric characters: ! @ # $ % ^ & * ( ) \_ + - = [ ] {} \| ' | `string` | `"true"` | no | +| [require\_uppercase\_characters](#input\_require\_uppercase\_characters) | You can require that IAM user passwords contain at least one uppercase character from the ISO basic Latin alphabet (A to Z). | `string` | `"true"` | no | +| [sra\_solution\_name](#input\_sra\_solution\_name) | The SRA solution name. The default value is the folder name of the solution | `string` | `"sra-iam-password-policy"` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_password_policy/configuration/data.tf b/aws_sra_examples/terraform/solutions/iam_password_policy/configuration/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_password_policy/configuration/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_password_policy/configuration/invoke.tf b/aws_sra_examples/terraform/solutions/iam_password_policy/configuration/invoke.tf new file mode 100644 index 00000000..680bbef7 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_password_policy/configuration/invoke.tf @@ -0,0 +1,25 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_lambda_invocation" "lambda_invoke" { + function_name = aws_lambda_function.iam_password_policy_lambda_function.function_name + + input = jsonencode({ + "RequestType" : "Create", + "ResourceType" : "Terraform", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.iam_password_policy_lambda_function.arn}", + "HARD_EXPIRY" : "${var.hard_expiry}", + "MAX_PASSWORD_AGE" : "${var.max_password_age}", + "PASSWORD_REUSE_PREVENTION" : "${var.password_reuse_prevention}", + "MINIMUM_PASSWORD_LENGTH" : "${var.minimum_password_length}", + "REQUIRE_LOWERCASE_CHARACTERS" : "${var.require_lowercase_characters}", + "REQUIRE_NUMBERS" : "${var.require_numbers}", + "REQUIRE_SYMBOLS" : "${var.require_symbols}", + "REQUIRE_UPPERCASE_CHARACTERS" : "${var.require_uppercase_characters}", + "ALLOW_USERS_TO_CHANGE_PASSWORD" : "${var.allow_users_to_change_password}", + } + }) +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/iam_password_policy/configuration/main.tf b/aws_sra_examples/terraform/solutions/iam_password_policy/configuration/main.tf new file mode 100644 index 00000000..67f241a7 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/iam_password_policy/configuration/main.tf @@ -0,0 +1,177 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +locals { + create_lambda_log_group = var.create_lambda_log_group == "true" + use_kms_key = var.lambda_log_group_kms_key != "" + partition = data.aws_partition.current.partition + current_account = data.aws_caller_identity.current.account_id + current_region = data.aws_region.current.name + use_graviton = contains( + [ + "ap-northeast-1", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + data.aws_region.current.name, + ) + src_path = "${path.root}/../../solutions/iam/iam_password_policy/lambda/src/" +} + +######################################################################## +# Lambda IAM Role +######################################################################## +resource "aws_iam_role" "iam_password_policy_lambda_role" { + name = var.lambda_role_name + + assume_role_policy = data.aws_iam_policy_document.iam_password_policy_assume_role.json + + tags = { + sra-solution = var.sra_solution_name + } +} + +######################################################################## +# Lambda Policies Documents +######################################################################## +data "aws_iam_policy_document" "iam_password_policy_assume_role" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + +data "aws_iam_policy_document" "lambda_policy" { + statement { + sid = "CreateLogStreamAndEvents" + effect = "Allow" + actions = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ] + resources = [ + "arn:${local.partition}:logs:${local.current_region}:${local.current_account}:log-group:/aws/lambda/${var.lambda_function_name}:log-stream:*", + ] + } + + statement { + sid = "IAMUpdateAccountPasswordPolicy" + effect = "Allow" + actions = [ + "iam:UpdateAccountPasswordPolicy", + ] + resources = ["*"] + } +} + + +######################################################################## +# Lambda Policies +######################################################################## +resource "aws_iam_policy" "lambda_policy" { + name = "sra-iam-password-policy" + description = "Policy for the IAM Password Policy Lambda function" + policy = data.aws_iam_policy_document.lambda_policy.json +} + +######################################################################## +# Lambda Policies Attachment +######################################################################## +resource "aws_iam_role_policy_attachment" "lambda_policy_attachment" { + policy_arn = aws_iam_policy.lambda_policy.arn + role = aws_iam_role.iam_password_policy_lambda_role.name +} + +######################################################################## +# Cloud Watch Log Group +######################################################################## +resource "aws_cloudwatch_log_group" "lambda_log_group" { + count = local.create_lambda_log_group ? 1 : 0 + name = "/aws/lambda/${var.lambda_function_name}" + retention_in_days = var.lambda_log_group_retention + + kms_key_id = local.use_kms_key ? var.lambda_log_group_kms_key : null +} + +######################################################################## +# Lambda Function +######################################################################## + +data "archive_file" "hash_check" { + type = "zip" + source_dir = local.src_path + output_path = "${path.module}/lambda/lambda_function.zip" + excludes = ["lambda_function.zip, data.zip"] +} + +resource "null_resource" "package_lambda" { + triggers = { + src_hash = "${data.archive_file.hash_check.output_sha}" + } + + provisioner "local-exec" { + command = < + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + +## Table of Contents + +- [Introduction](#introduction) +- [Deployed Resource Details](#deployed-resource-details) +- [Implementation Instructions](#implementation-instructions) +- [Requirements](#requirements) +- [Providers](#providers) +- [Modules](#modules) +- [Resources](#resources) +- [Inputs](#inputs) +- [Outputs](#outputs) + +--- + +## Introduction + +This Terraform module deploys the Inspector AWS SRA solution. + +The common pre-requisite solution must be installed, in the management account, prior to installing this solution. + +Information on the resources deployed as well as terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for more information and installation instructions. + +*For the CloudFormation version of this AWS SRA solution as well as more information please navigate to the [AWS SRA Inspector solution documentation](./../../../solutions/inspector/inspector_org/README.md) page.* + +--- + +## Deployed Resource Details + +![Architecture](./../../../solutions/inspector/inspector_org/documentation/inspector-org-terraform.png) + +### 1.0 Organization Management Account + +#### 1.1 IAM Roles + +- See [1.2 IAM Roles](./../../../solutions/inspector/inspector_org/README.md#12-iam-roles) + +#### 1.2 Regional Event Rules + +- See [1.3 Regional Event Rules](./../../../solutions/inspector/inspector_org/README.md#13-regional-event-rules) + +#### 1.3 Global Event Rules + +- See [1.4 Global Event Rules](./../../../solutions/inspector/inspector_org/README.md#14-global-event-rules) + +#### 1.4 SNS Topic + +- See [1.5 SNS Topic](./../../../solutions/inspector/inspector_org/README.md#15-sns-topic) + +#### 1.5 Dead Letter Queue (DLQ) + +- See [1.6 Dead Letter Queue (DLQ)](./../../../solutions/inspector/inspector_org/README.md#16-dead-letter-queue-dlq) + +#### 1.6 AWS Lambda Function + +- See [1.7 AWS Lambda Function](./../../../solutions/inspector/inspector_org/README.md#17-aws-lambda-function) + +#### 1.7 Lambda CloudWatch Log Group + +- See [1.8 Lambda CloudWatch Log Group](./../../../solutions/inspector/inspector_org/README.md#18-lambda-cloudwatch-log-group) + +#### 1.8 Alarm SNS Topic + +- See [1.9 Alarm SNS Topic](./../../../solutions/inspector/inspector_org/README.md#19-alarm-sns-topic) + +#### 1.9 Inspector + +- See [1.10 Inspector](./../../../solutions/inspector/inspector_org/README.md#110-inspector) + +#### 1.10 Lambda Layer + +- See [1.11 Lambda Layer](./../../../solutions/inspector/inspector_org/README.md#111-lambda-layer) + +--- + +### 2.0 Audit Account + +#### 2.2 Configuration IAM Role + +- See [2.2 Configuration IAM Role](./../../../solutions/inspector/inspector_org/README.md#22-configuration-iam-role) + +#### 2.2 Inspector (Delegated admin) + +- See [2.3 Inspector (Delegated admin)](./../../../solutions/inspector/inspector_org/README.md#23-inspector-delegated-admin) + +--- + +### 3.0 All Existing and Future Organization Member Accounts + +#### 3.1 Configuration IAM Role + +- See [3.2 Configuration IAM Role](./../../../solutions/inspector/inspector_org/README.md#32-configuration-iam-role) + +#### 3.2 Inspector (Members) + +- See [3.3 Inspector (Members)](./../../../solutions/inspector/inspector_org/README.md#33-inspector-members) + +--- + +## Implementation Instructions + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for installation instructions. + +--- + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws.main](#provider\_aws.main) | >= 5.1.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [inspector\_configuration](#module\_inspector\_configuration) | ./configuration | n/a | +| [inspector\_configuration\_role](#module\_inspector\_configuration\_role) | ./configuration_role | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [audit\_account\_id](#input\_audit\_account\_id) | AWS Account ID of the Control Tower Audit account. | `string` | n/a | yes | +| [ecr\_rescan\_duration](#input\_ecr\_rescan\_duration) | ECR Rescan Duration | `string` | n/a | yes | +| [enabled\_regions](#input\_enabled\_regions) | (Optional) Enabled regions (AWS regions, separated by commas). Leave blank to enable all regions. | `string` | `""` | no | +| [home\_region](#input\_home\_region) | Name of the Control Tower home region | `string` | n/a | yes | +| [inspector\_configuration\_role\_name](#input\_inspector\_configuration\_role\_name) | Inspector Configuration role to assume in the delegated administrator account | `string` | `"sra-inspector-configuration"` | no | +| [inspector\_control\_tower\_regions\_only](#input\_inspector\_control\_tower\_regions\_only) | Only enable in the Control Tower governed regions | `bool` | `true` | no | +| [inspector\_org\_lambda\_function\_name](#input\_inspector\_org\_lambda\_function\_name) | Lambda function name | `string` | `"sra-inspector-org"` | no | +| [inspector\_org\_lambda\_role\_name](#input\_inspector\_org\_lambda\_role\_name) | Inspector configuration Lambda role name | `string` | `"sra-inspector-org-lambda"` | no | +| [log\_archive\_account\_id](#input\_log\_archive\_account\_id) | AWS Account ID of the Control Tower Log Archive account. | `string` | n/a | yes | +| [management\_account\_id](#input\_management\_account\_id) | Organization Management Account ID | `string` | n/a | yes | +| [organization\_id](#input\_organization\_id) | AWS Organizations ID | `string` | n/a | yes | +| [scan\_components](#input\_scan\_components) | Components to scan (e.g., 'ec2,ecs') | `string` | n/a | yes | +| [sra\_solution\_name](#input\_sra\_solution\_name) | The SRA solution name. The default value is the folder name of the solution. | `string` | `"sra-inspector-org"` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/inspector/configuration/data.tf b/aws_sra_examples/terraform/solutions/inspector/configuration/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/inspector/configuration/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/inspector/configuration/invoke.tf b/aws_sra_examples/terraform/solutions/inspector/configuration/invoke.tf new file mode 100644 index 00000000..4f889c12 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/inspector/configuration/invoke.tf @@ -0,0 +1,53 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_lambda_invocation" "lambda_invoke" { + function_name = aws_lambda_function.inspector_org_lambda_function.function_name + + input = jsonencode({ + "RequestType" : "Update", + "ResourceType" : "Terraform", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.inspector_org_lambda_function.arn}", + "LOG_LEVEL" : "${var.lambda_log_level}", + "AWS_PARTITION" : "${local.partition}", + "CONFIGURATION_ROLE_NAME" : "${var.inspector_configuration_role_name}", + "CONTROL_TOWER_REGIONS_ONLY" : "${var.inspector_control_tower_regions_only}", + "DELEGATED_ADMIN_ACCOUNT_ID" : "${var.delegated_admin_account_id}", + "ENABLED_REGIONS" : "${var.enabled_regions}", + "MANAGEMENT_ACCOUNT_ID" : "${local.current_account}", + "SNS_TOPIC_ARN" : "${aws_sns_topic.inspector_org_topic.arn}", + "SCAN_COMPONENTS" : "${var.scan_components}", + "ECR_SCAN_DURATION" : "${var.ecr_rescan_duration}", + } + }) + + # lifecycle_scope = "CRUD" + lifecycle_scope = "CREATE_ONLY" +} + +resource "aws_lambda_invocation" "lambda_disable_invoke" { + count = var.disable_inspector ? 1 : 0 + function_name = aws_lambda_function.inspector_org_lambda_function.function_name + input = jsonencode({ + "RequestType" : "Delete", + "ResourceType" : "Terraform", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.inspector_org_lambda_function.arn}", + "LOG_LEVEL" : "${var.lambda_log_level}", + "AWS_PARTITION" : "${local.partition}", + "CONFIGURATION_ROLE_NAME" : "${var.inspector_configuration_role_name}", + "CONTROL_TOWER_REGIONS_ONLY" : "${var.inspector_control_tower_regions_only}", + "DELEGATED_ADMIN_ACCOUNT_ID" : "${var.delegated_admin_account_id}", + "ENABLED_REGIONS" : "${var.enabled_regions}", + "MANAGEMENT_ACCOUNT_ID" : "${local.current_account}", + "SNS_TOPIC_ARN" : "${aws_sns_topic.inspector_org_topic.arn}", + "SCAN_COMPONENTS" : "${var.scan_components}", + "ECR_SCAN_DURATION" : "${var.ecr_rescan_duration}", + } + }) + + lifecycle_scope = "CREATE_ONLY" +} diff --git a/aws_sra_examples/terraform/solutions/inspector/configuration/main.tf b/aws_sra_examples/terraform/solutions/inspector/configuration/main.tf new file mode 100644 index 00000000..131a08a4 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/inspector/configuration/main.tf @@ -0,0 +1,569 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +locals { + create_lambda_log_group = var.create_lambda_log_group == "true" + use_kms_key = var.lambda_log_group_kms_key != "" + not_global_region_us_east_1 = data.aws_region.current.name != "us-east-1" + compliance_frequency_single_day = var.compliance_frequency == 1 + create_dlq_alarm = var.sra_alarm_email != "" + partition = data.aws_partition.current.partition + current_account = data.aws_caller_identity.current.account_id + current_region = data.aws_region.current.name + use_graviton = contains( + [ + "ap-northeast-1", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + data.aws_region.current.name, + ) + src_path = "${path.root}/../../solutions/inspector/inspector_org/lambda/src/" +} + +######################################################################## +# Lambda IAM Role +######################################################################## +resource "aws_iam_role" "inspector_org_lambda_role" { + name = var.inspector_org_lambda_role_name + + assume_role_policy = data.aws_iam_policy_document.inspector_org_assume_role.json + + tags = { + sra-solution = var.sra_solution_name + } +} + +######################################################################## +# Lambda Policies Documents +######################################################################## +data "aws_iam_policy_document" "inspector_org_assume_role" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} +######################################################################## +# Lambda Policies +######################################################################## +data "aws_iam_policy_document" "cloudformation" { + statement { + sid = "CloudFormation" + effect = "Allow" + actions = ["cloudformation:ListStackInstances"] + resources = ["arn:${local.partition}:cloudformation:${local.current_region}:${local.current_account}:stackset/AWSControlTowerBP-*"] + } +} + +data "aws_iam_policy_document" "ssm_access" { + statement { + effect = "Allow" + actions = ["ssm:GetParameter", "ssm:GetParameters"] + resources = ["arn:${local.partition}:ssm:${local.current_region}:${local.current_account}:parameter/sra*"] + } +} + +data "aws_iam_policy_document" "inspector" { + statement { + sid = "AllowAllTest" + effect = "Allow" + actions = [ + "inspector2:ListDelegatedAdminAccounts", + "inspector2:DisableDelegatedAdminAccount", + "inspector2:BatchGetAccountStatus", + "inspector2:EnableDelegatedAdminAccount", + "inspector2:Enable", + "inspector2:Disable", + ] + resources = ["*"] + } +} + +data "aws_iam_policy_document" "iam" { + statement { + sid = "AssumeRole" + effect = "Allow" + actions = ["sts:AssumeRole"] + resources = ["arn:${local.partition}:iam::*:role/${var.inspector_configuration_role_name}"] + condition { + test = "StringEquals" + variable = "aws:PrincipalOrgId" + values = [var.organization_id] + } + } + + statement { + sid = "AllowReadIamActions" + effect = "Allow" + actions = ["iam:GetRole"] + resources = ["arn:${local.partition}:iam::${local.current_account}:role/*"] + } + + statement { + sid = "AllowCreateServiceLinkedRole" + effect = "Allow" + actions = ["iam:CreateServiceLinkedRole"] + condition { + test = "StringLike" + variable = "iam:AWSServiceName" + values = ["inspector2.amazonaws.com"] + } + resources = ["arn:${local.partition}:iam::${local.current_account}:role/aws-service-role/inspector2.amazonaws.com/AWSServiceRoleForAmazonInspector2"] + } + + statement { + sid = "AllowPolicyActions" + effect = "Allow" + actions = ["iam:PutRolePolicy"] + resources = ["arn:${local.partition}:iam::${local.current_account}:role/aws-service-role/inspector2.amazonaws.com/AWSServiceRoleForAmazonInspector2"] + } + + statement { + sid = "AllowDeleteServiceLinkedRole" + effect = "Allow" + actions = ["iam:DeleteServiceLinkedRole"] + resources = ["arn:${local.partition}:iam::${local.current_account}:role/aws-service-role/inspector2.amazonaws.com/AWSServiceRoleForAmazonInspector2"] + } +} + +data "aws_iam_policy_document" "logs" { + statement { + sid = "CreateLogGroupAndEvents" + effect = "Allow" + actions = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"] + resources = ["arn:${local.partition}:logs:${local.current_region}:${local.current_account}:log-group:/aws/lambda/${var.inspector_org_lambda_function_name}:log-stream:*"] + } +} + +data "aws_iam_policy_document" "organizations" { + statement { + effect = "Allow" + sid = "OrganizationsReadAccess" + actions = [ + "organizations:DescribeOrganization", + "organizations:ListAWSServiceAccessForOrganization", + "organizations:ListAccounts", + "organizations:ListDelegatedAdministrators", + ] + resources = ["*"] + } + + statement { + effect = "Allow" + sid = "AWSServiceAccess" + actions = ["organizations:DisableAWSServiceAccess", "organizations:EnableAWSServiceAccess"] + condition { + test = "StringLikeIfExists" + variable = "organizations:ServicePrincipal" + values = ["inspector2.amazonaws.com"] + } + resources = ["*"] + } + + statement { + effect = "Allow" + sid = "RegisterDeregisterDelegatedAdministrator" + actions = ["organizations:DeregisterDelegatedAdministrator", "organizations:RegisterDelegatedAdministrator"] + condition { + test = "StringLikeIfExists" + variable = "organizations:ServicePrincipal" + values = ["inspector2.amazonaws.com"] + } + resources = ["arn:${local.partition}:organizations::*:account/o-*/*"] + } +} + +data "aws_iam_policy_document" "sns" { + statement { + sid = "SNSPublish" + effect = "Allow" + actions = ["sns:Publish", "sns:PublishBatch"] + resources = [aws_sns_topic.inspector_org_topic.arn] + } +} + +data "aws_iam_policy_document" "sqs" { + statement { + sid = "SQSSendMessage" + effect = "Allow" + actions = ["sqs:SendMessage"] + resources = [aws_sqs_queue.inspector_org_dlq.arn] + } +} + +######################################################################## +# Lambda Policies +######################################################################## +resource "aws_iam_policy" "cloudformation_policy" { + name = "sra-inspector-org-policy-cloudformation" + description = "IAM policy for CloudFormation" + policy = data.aws_iam_policy_document.cloudformation.json +} + +resource "aws_iam_policy" "ssm_access_policy" { + name = "sra-inspector-ssm-access" + description = "IAM policy for SSM access" + policy = data.aws_iam_policy_document.ssm_access.json +} + +resource "aws_iam_policy" "inspector_policy" { + name = "sra-inspector-org-policy-inspector" + description = "IAM policy for Amazon Inspector" + policy = data.aws_iam_policy_document.inspector.json +} + +resource "aws_iam_policy" "iam_policy" { + name = "sra-inspector-org-policy-iam" + description = "IAM policy for IAM roles" + policy = data.aws_iam_policy_document.iam.json +} + +resource "aws_iam_policy" "logs_policy" { + name = "sra-inspector-org-policy-logs" + description = "IAM policy for CloudWatch Logs" + policy = data.aws_iam_policy_document.logs.json +} + +resource "aws_iam_policy" "organizations_policy" { + name = "sra-inspector-org-policy-organizations" + description = "IAM policy for AWS Organizations" + policy = data.aws_iam_policy_document.organizations.json +} + +resource "aws_iam_policy" "sns_policy" { + name = "sra-inspector-org-policy-sns" + description = "IAM policy for SNS" + policy = data.aws_iam_policy_document.sns.json +} + +resource "aws_iam_policy" "sqs_policy" { + name = "sra-inspector-org-policy-sqs" + description = "IAM policy for SQS" + policy = data.aws_iam_policy_document.sqs.json +} + +######################################################################## +# Lambda Policies Attachment +######################################################################## +resource "aws_iam_role_policy_attachment" "cloudformation_attachment" { + policy_arn = aws_iam_policy.cloudformation_policy.arn + role = aws_iam_role.inspector_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "ssm_access_attachment" { + policy_arn = aws_iam_policy.ssm_access_policy.arn + role = aws_iam_role.inspector_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "inspector_attachment" { + policy_arn = aws_iam_policy.inspector_policy.arn + role = aws_iam_role.inspector_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "iam_attachment" { + policy_arn = aws_iam_policy.iam_policy.arn + role = aws_iam_role.inspector_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "logs_attachment" { + policy_arn = aws_iam_policy.logs_policy.arn + role = aws_iam_role.inspector_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "organizations_attachment" { + policy_arn = aws_iam_policy.organizations_policy.arn + role = aws_iam_role.inspector_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "sns_attachment" { + policy_arn = aws_iam_policy.sns_policy.arn + role = aws_iam_role.inspector_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "sqs_attachment" { + policy_arn = aws_iam_policy.sqs_policy.arn + role = aws_iam_role.inspector_org_lambda_role.name +} + +######################################################################## +# Cloud Watch Log Group +######################################################################## +resource "aws_cloudwatch_log_group" "inspector_org_lambda_log_group" { + count = local.create_lambda_log_group ? 1 : 0 + + name = "/aws/lambda/${var.inspector_org_lambda_function_name}" + retention_in_days = var.lambda_log_group_retention + kms_key_id = local.use_kms_key ? var.lambda_log_group_kms_key : null +} + +######################################################################## +# Lambda Function +######################################################################## + +data "archive_file" "hash_check" { + type = "zip" + source_dir = local.src_path + output_path = "${path.module}/lambda/lambda_function.zip" + excludes = ["lambda_function.zip, data.zip"] +} + +resource "null_resource" "package_lambda" { + triggers = { + src_hash = "${data.archive_file.hash_check.output_sha}" + } + + provisioner "local-exec" { + command = < + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + +## Table of Contents + +- [Introduction](#introduction) +- [Deployed Resource Details](#deployed-resource-details) +- [Implementation Instructions](#implementation-instructions) +- [Requirements](#requirements) +- [Providers](#providers) +- [Modules](#modules) +- [Resources](#resources) +- [Inputs](#inputs) +- [Outputs](#outputs) + +--- + +## Introduction + +This Terraform module deploys the Inspector AWS SRA solution. + +The common pre-requisite solution must be installed, in the management account, prior to installing this solution. + +Information on the resources deployed as well as terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for more information and installation instructions. + +*For the CloudFormation version of this AWS SRA solution as well as more information please navigate to the [AWS SRA Macie solution documentation](./../../../solutions/macie/macie_org/README.md) page.* + +--- + +## Deployed Resource Details + +![Architecture](./../../../solutions/macie/macie_org/documentation/macie-org-terraform.png) + +### 1.0 Organization Management Account + +#### 1.1 AWS Lambda Function + +- See [1.2 AWS Lambda Function](./../../../solutions/macie/macie_org/README.md#12-aws-lambda-function) + +#### 1.2 Lambda IAM Role + +- See [1.3 Lambda IAM Role](./../../../solutions/macie/macie_org/README.md#13-lambda-iam-role) + +#### 1.3 Lambda CloudWatch Log Group + +- See [1.4 Lambda CloudWatch Log Group](./../../../solutions/macie/macie_org/README.md#14-lambda-cloudwatch-log-group) + +#### 1.4 Configuration SNS Topic + +- See [1.5 Configuration SNS Topic](./../../../solutions/macie/macie_org/README.md#15-configuration-sns-topic) + +#### 1.5 Dead Letter Queue (DLQ) + +- See [1.6 Dead Letter Queue (DLQ)](./../../../solutions/macie/macie_org/README.md#16-dead-letter-queue-dlq) + +#### 1.6 Alarm SNS Topic + +- See [1.7 Alarm SNS Topic](./../../../solutions/macie/macie_org/README.md#17-alarm-sns-topic) + +#### 1.7 Macie + +- See [1.8 Macie](./../../../solutions/macie/macie_org/README.md#18-macie) + +--- + +### 2.0 Log Archive Account + +#### 2.1 Macie Delivery S3 Bucket + +- See [2.2 Macie Delivery S3 Bucket](./../../../solutions/macie/macie_org/README.md#22-macie-delivery-s3-bucket) + +#### 2.2 Macie + +- See [2.3 Macie](./../../../solutions/macie/macie_org/README.md#23-macie) + +--- + +### 3.0 Audit Account (Security Tooling) + +#### 3.1 Macie Delivery KMS Key + +- See [3.2 Macie Delivery KMS Key](./../../../solutions/macie/macie_org/README.md#32-macie-delivery-kms-key) + +#### 3.2 Configuration IAM Role + +- See [3.3 Configuration IAM Role](./../../../solutions/macie/macie_org/README.md#33-configuration-iam-role) + +#### 3.3 Macie + +- See [3.4 Macie](./../../../solutions/macie/macie_org/README.md#34-macie) + +--- + +### 4.0 All Existing and Future Organization Member Accounts + +#### 4.1 Macie + +- See [4.1 Macie](./../../../solutions/macie/macie_org/README.md#41-macie) + +#### 4.2 Disable Macie Role + +- See [4.2 Disable Macie Role](./../../../solutions/macie/macie_org/README.md#42-disable-macie-role) + +--- + +## Implementation Instructions + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for installation instructions. + +--- + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws.main](#provider\_aws.main) | >= 5.1.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [configuration\_role](#module\_configuration\_role) | ./configuration_role | n/a | +| [delivery\_kms\_key](#module\_delivery\_kms\_key) | ./delivery_kms_key | n/a | +| [delivery\_s3\_bucket](#module\_delivery\_s3\_bucket) | ./delivery_s3_bucket | n/a | +| [disable\_role](#module\_disable\_role) | ./disable_role | n/a | +| [macie\_configuration](#module\_macie\_configuration) | ./configuration | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [audit\_account\_id](#input\_audit\_account\_id) | AWS Account ID of the Control Tower Audit account. | `string` | n/a | yes | +| [disable\_macie](#input\_disable\_macie) | Disabled Macie SRA solution | `string` | n/a | yes | +| [home\_region](#input\_home\_region) | Name of the Control Tower home region | `string` | n/a | yes | +| [log\_archive\_account\_id](#input\_log\_archive\_account\_id) | AWS Account ID of the Control Tower Log Archive account. | `string` | n/a | yes | +| [macie\_finding\_publishing\_frequency](#input\_macie\_finding\_publishing\_frequency) | Macie finding publishing frequency | `string` | n/a | yes | +| [macie\_org\_configuration\_role\_name](#input\_macie\_org\_configuration\_role\_name) | Configuration IAM Role Name | `string` | `"sra-macie-org-configuration"` | no | +| [macie\_org\_lambda\_role\_name](#input\_macie\_org\_lambda\_role\_name) | Lambda Role Name | `string` | `"sra-macie-org-lambda"` | no | +| [management\_account\_id](#input\_management\_account\_id) | Organization Management Account ID | `string` | n/a | yes | +| [organization\_id](#input\_organization\_id) | AWS Organization ID | `string` | n/a | yes | +| [secrets\_key\_alias\_arn](#input\_secrets\_key\_alias\_arn) | (Optional) SRA Secrets Manager KMS Key Alias ARN | `string` | `""` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/macie/configuration/data.tf b/aws_sra_examples/terraform/solutions/macie/configuration/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/macie/configuration/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/macie/configuration/invoke.tf b/aws_sra_examples/terraform/solutions/macie/configuration/invoke.tf new file mode 100644 index 00000000..0fa2302a --- /dev/null +++ b/aws_sra_examples/terraform/solutions/macie/configuration/invoke.tf @@ -0,0 +1,52 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_lambda_invocation" "lambda_invoke" { + count = var.disable_macie ? 0 : 1 + function_name = aws_lambda_function.r_macie_org_lambda_function.function_name + + input = jsonencode({ + "RequestType" : "Create", + "ResourceType" : "Custom::LambdaCustomResource", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.r_macie_org_lambda_function.arn}", + "DELEGATED_ADMIN_ACCOUNT_ID" : "${var.p_delegated_admin_account_id}", + "DISABLE_MACIE" : "${var.disable_macie}", + "DISABLE_MACIE_ROLE_NAME" : "${var.p_disable_macie_role_name}", + "PUBLISHING_DESTINATION_BUCKET_NAME" : "${var.p_publishing_destination_bucket_name}", + "SNS_TOPIC_ARN" : "${aws_sns_topic.r_macie_org_topic.arn}", + "KMS_KEY_ARN" : "${var.p_kms_key_arn}", + "CONTROL_TOWER_REGIONS_ONLY" : "${var.p_control_tower_regions_only}", + "MANAGEMENT_ACCOUNT_ID" : "${var.p_management_account_id}", + "CONFIGURATION_ROLE_NAME" : "${var.p_macie_org_configuration_role_name}", + "FINDING_PUBLISHING_FREQUENCY" : "${var.p_finding_publishing_frequency}", + "ENABLED_REGIONS" : "${var.p_enabled_regions}" + } + }) +} + +resource "aws_lambda_invocation" "lambda_disable_invoke" { + count = var.disable_macie ? 1 : 0 + function_name = aws_lambda_function.r_macie_org_lambda_function.function_name + + input = jsonencode({ + "RequestType" : "Update", + "ResourceType" : "Custom::LambdaCustomResource", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.r_macie_org_lambda_function.arn}", + "DELEGATED_ADMIN_ACCOUNT_ID" : "${var.p_delegated_admin_account_id}", + "DISABLE_MACIE" : "${var.disable_macie}", + "DISABLE_MACIE_ROLE_NAME" : "${var.p_disable_macie_role_name}", + "PUBLISHING_DESTINATION_BUCKET_NAME" : "${var.p_publishing_destination_bucket_name}", + "SNS_TOPIC_ARN" : "${aws_sns_topic.r_macie_org_topic.arn}", + "KMS_KEY_ARN" : "${var.p_kms_key_arn}", + "CONTROL_TOWER_REGIONS_ONLY" : "${var.p_control_tower_regions_only}", + "MANAGEMENT_ACCOUNT_ID" : "${var.p_management_account_id}", + "CONFIGURATION_ROLE_NAME" : "${var.p_macie_org_configuration_role_name}", + "FINDING_PUBLISHING_FREQUENCY" : "${var.p_finding_publishing_frequency}", + "ENABLED_REGIONS" : "${var.p_enabled_regions}" + } + }) +} diff --git a/aws_sra_examples/terraform/solutions/macie/configuration/main.tf b/aws_sra_examples/terraform/solutions/macie/configuration/main.tf new file mode 100644 index 00000000..249da258 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/macie/configuration/main.tf @@ -0,0 +1,433 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +locals { + src_path = "${path.root}/../../solutions/macie/macie_org/lambda/src/" +} + +resource "aws_cloudwatch_log_group" "rMacieOrgLambdaLogGroup" { + count = var.p_create_lambda_log_group == "true" ? 1 : 0 + name = "/aws/lambda/${var.p_macie_org_lambda_function_name}" + retention_in_days = var.p_lambda_log_group_retention + kms_key_id = var.p_lambda_log_group_kms_key != "" ? var.p_lambda_log_group_kms_key : null +} + +######################################################################## +# Lambda Policies Documents +######################################################################## +resource "aws_iam_role" "r_macie_org_lambda_role" { + name = var.p_macie_org_lambda_role_name + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [{ + Effect = "Allow", + Principal = { + Service = "lambda.amazonaws.com" + }, + Action = "sts:AssumeRole" + }] + }) + + tags = { + "sra-solution" = var.p_sra_solution_name + } +} + +# IAM Policies +data "aws_iam_policy_document" "sra_macie_org_policy_logs" { + version = "2012-10-17" + + statement { + sid = "CreateLogStreamAndEvents" + effect = "Allow" + actions = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"] + resources = [format("arn:%s:logs:%s:%s:log-group:/aws/lambda/%s:log-stream:*", data.aws_partition.current.partition, data.aws_region.current.name, data.aws_caller_identity.current.account_id, var.p_macie_org_lambda_function_name)] + } +} + +data "aws_iam_policy_document" "sra_macie_org_policy_organizations" { + version = "2012-10-17" + + statement { + sid = "OrganizationsReadAccess" + effect = "Allow" + + actions = [ + "organizations:DescribeOrganization", + "organizations:ListAWSServiceAccessForOrganization", + "organizations:ListAccounts", + "organizations:ListDelegatedAdministrators", + ] + + resources = ["*"] + } + + statement { + sid = "AWSServiceAccess" + effect = "Allow" + actions = ["organizations:DisableAWSServiceAccess", "organizations:EnableAWSServiceAccess"] + condition { + test = "StringLikeIfExists" + variable = "organizations:ServicePrincipal" + values = ["macie.amazonaws.com"] + } + resources = ["*"] + } + + statement { + sid = "RegisterDeregisterDelegatedAdministrator" + effect = "Allow" + actions = ["organizations:DeregisterDelegatedAdministrator", "organizations:RegisterDelegatedAdministrator"] + condition { + test = "StringLikeIfExists" + variable = "organizations:ServicePrincipal" + values = ["macie.amazonaws.com"] + } + resources = [format("arn:%s:organizations::*:account/o-*/*", data.aws_partition.current.partition)] + } +} + +data "aws_iam_policy_document" "sra_macie_org_policy_macie" { + version = "2012-10-17" + + statement { + sid = "MacieNoResource" + effect = "Allow" + actions = [ + "macie2:DisableOrganizationAdminAccount", + "macie2:EnableMacie", + "macie2:EnableOrganizationAdminAccount", + "macie2:ListOrganizationAdminAccounts", + ] + resources = ["*"] + } +} + +data "aws_iam_policy_document" "sra_macie_org_policy_iam" { + version = "2012-10-17" + + statement { + sid = "AssumeRole" + effect = "Allow" + actions = ["sts:AssumeRole"] + resources = [ + format("arn:%s:iam::%s:role/%s", data.aws_partition.current.partition, var.p_delegated_admin_account_id, var.p_macie_org_configuration_role_name), + format("arn:%s:iam::*:role/%s", data.aws_partition.current.partition, var.p_disable_macie_role_name), + ] + condition { + test = "StringEquals" + variable = "aws:PrincipalOrgId" + values = [var.p_organization_id] + } + } + + statement { + sid = "AllowReadIamActions" + effect = "Allow" + actions = ["iam:GetRole"] + resources = [format("arn:%s:iam::%s:role/*", data.aws_partition.current.partition, data.aws_caller_identity.current.account_id)] + } + + statement { + sid = "AllowCreateServiceLinkedRole" + effect = "Allow" + actions = ["iam:CreateServiceLinkedRole"] + resources = [format("arn:%s:iam::%s:role/aws-service-role/macie.amazonaws.com/AWSServiceRoleForAmazonMacie", data.aws_partition.current.partition, data.aws_caller_identity.current.account_id)] + condition { + test = "StringLike" + variable = "iam:AWSServiceName" + values = ["macie.amazonaws.com"] + } + } + + statement { + sid = "AllowPolicyActions" + effect = "Allow" + actions = ["iam:PutRolePolicy"] + resources = [format("arn:%s:iam::%s:role/aws-service-role/macie.amazonaws.com/AWSServiceRoleForAmazonMacie", data.aws_partition.current.partition, data.aws_caller_identity.current.account_id)] + } +} + +data "aws_iam_policy_document" "macie_org_policy_cloudformation" { + version = "2012-10-17" + + statement { + effect = "Allow" + actions = ["cloudformation:ListStackInstances"] + resources = [format("arn:%s:cloudformation:%s:%s:stackset/AWSControlTowerBP-*", data.aws_partition.current.partition, data.aws_region.current.name, data.aws_caller_identity.current.account_id)] + } +} + +data "aws_iam_policy_document" "sra_macie_org_policy_sns" { + version = "2012-10-17" + + statement { + sid = "SNSPublish" + effect = "Allow" + actions = ["sns:Publish"] + resources = [aws_sns_topic.r_macie_org_topic.arn] + } +} + +data "aws_iam_policy_document" "sra_macie_org_policy_sqs" { + version = "2012-10-17" + + statement { + sid = "SQSSendMessage" + effect = "Allow" + actions = ["sqs:SendMessage"] + resources = [aws_sqs_queue.macie_org_dlq.arn] + } +} + +data "aws_iam_policy_document" "sra_macie_org_policy_ssm" { + version = "2012-10-17" + + statement { + sid = "SSMAccess" + effect = "Allow" + actions = [ + "ssm:GetParameter", + "ssm:GetParameters", + ] + resources = [format("arn:%s:ssm:%s:%s:parameter/sra*", data.aws_partition.current.partition, data.aws_region.current.name, data.aws_caller_identity.current.account_id)] + } +} + +######################################################################## +# Lambda Policies +######################################################################## +resource "aws_iam_policy" "sra_macie_org_policy_logs" { + name = "sra-macie-org-policy-logs" + description = "IAM policy for Macie Org Lambda Logs" + policy = data.aws_iam_policy_document.sra_macie_org_policy_logs.json +} + +resource "aws_iam_policy" "sra_macie_org_policy_organizations" { + name = "sra-macie-org-policy-organizations" + description = "IAM policy for Macie Org Lambda Organizations" + policy = data.aws_iam_policy_document.sra_macie_org_policy_organizations.json +} + +resource "aws_iam_policy" "sra_macie_org_policy_macie" { + name = "sra-macie-org-policy-macie" + description = "IAM policy for Macie Org Lambda Macie" + policy = data.aws_iam_policy_document.sra_macie_org_policy_macie.json +} + +resource "aws_iam_policy" "sra_macie_org_policy_iam" { + name = "sra-macie-org-policy-iam" + description = "IAM policy for Macie Org Lambda IAM" + policy = data.aws_iam_policy_document.sra_macie_org_policy_iam.json +} + +resource "aws_iam_policy" "macie_org_policy_cloudformation" { + name = "macie-org-policy-cloudformation" + description = "IAM policy for Macie Org Lambda CloudFormation" + policy = data.aws_iam_policy_document.macie_org_policy_cloudformation.json +} + +resource "aws_iam_policy" "sra_macie_org_policy_sns" { + name = "sra-macie-org-policy-sns" + description = "IAM policy for Macie Org Lambda SNS" + policy = data.aws_iam_policy_document.sra_macie_org_policy_sns.json +} + +resource "aws_iam_policy" "sra_macie_org_policy_sqs" { + name = "sra-macie-org-policy-sqs" + description = "IAM policy for Macie Org Lambda SQS" + policy = data.aws_iam_policy_document.sra_macie_org_policy_sqs.json +} + +resource "aws_iam_policy" "sra_macie_org_policy_ssm" { + name = "sra-macie-org-policy-ssm" + description = "IAM policy for Macie Org Lambda SSM" + policy = data.aws_iam_policy_document.sra_macie_org_policy_ssm.json +} + +######################################################################## +# Lambda Attachment +######################################################################## +resource "aws_iam_role_policy_attachment" "rMacieOrgLambdaLogsPolicyAttachment" { + policy_arn = aws_iam_policy.sra_macie_org_policy_logs.arn + role = aws_iam_role.r_macie_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "rMacieOrgLambdaOrganizationsPolicyAttachment" { + policy_arn = aws_iam_policy.sra_macie_org_policy_organizations.arn + role = aws_iam_role.r_macie_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "rMacieOrgLambdaMaciePolicyAttachment" { + policy_arn = aws_iam_policy.sra_macie_org_policy_macie.arn + role = aws_iam_role.r_macie_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "rMacieOrgLambdaIamPolicyAttachment" { + policy_arn = aws_iam_policy.sra_macie_org_policy_iam.arn + role = aws_iam_role.r_macie_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "rMacieOrgLambdaCloudFormationPolicyAttachment" { + policy_arn = aws_iam_policy.macie_org_policy_cloudformation.arn + role = aws_iam_role.r_macie_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "rMacieOrgLambdaSnsPolicyAttachment" { + policy_arn = aws_iam_policy.sra_macie_org_policy_sns.arn + role = aws_iam_role.r_macie_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "rMacieOrgLambdaSqsPolicyAttachment" { + policy_arn = aws_iam_policy.sra_macie_org_policy_sqs.arn + role = aws_iam_role.r_macie_org_lambda_role.name +} + +resource "aws_iam_role_policy_attachment" "rMacieOrgLambdaSsmPolicyAttachment" { + policy_arn = aws_iam_policy.sra_macie_org_policy_ssm.arn + role = aws_iam_role.r_macie_org_lambda_role.name +} + +######################################################################## +# Lambda Function +######################################################################## +data "archive_file" "hash_check" { + type = "zip" + source_dir = local.src_path + output_path = "${path.module}/lambda/lambda_function.zip" + excludes = ["lambda_function.zip, data.zip"] +} + +resource "null_resource" "package_lambda" { + triggers = { + src_hash = "${data.archive_file.hash_check.output_sha}" + } + + provisioner "local-exec" { + command = < + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + +## Table of Contents + +- [Introduction](#introduction) +- [Deployed Resource Details](#deployed-resource-details) +- [Implementation Instructions](#implementation-instructions) +- [Requirements](#requirements) +- [Providers](#providers) +- [Modules](#modules) +- [Resources](#resources) +- [Inputs](#inputs) +- [Outputs](#outputs) + +--- + +## Introduction + +This Terraform module deploys the register delegated administrator AWS SRA solution. + +The common pre-requisite solution must be installed, in the management account, prior to installing this solution. + +Information on the resources deployed as well as terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for more information and installation instructions. + +*For the CloudFormation version of this AWS SRA solution as well as more information please navigate to the [AWS SRA register delegated admin solution documentation](./../../../solutions/common/common_register_delegated_administrator/README.md) page.* + +--- + +## Deployed Resource Details + +![Architecture](./../../../solutions/common/common_register_delegated_administrator/documentation/sra-common-register-delegated-administrator-terraform.png) + +### 1.0 Organization Management Account + +#### 1.2 AWS Lambda Function + +- See [1.2 AWS Lambda Function](#./../../../solutions/common/common_register_delegated_administrator/README.md12-aws-lambda-function) + +#### 1.3 Lambda CloudWatch Log Group + +- See [1.3 Lambda CloudWatch Log Group](#./../../../solutions/common/common_register_delegated_administrator/README.md13-lambda-cloudwatch-log-group) + +#### 1.4 Lambda Execution IAM Role + +- See [1.4 Lambda Execution IAM Role](#./../../../solutions/common/common_register_delegated_administrator/README.md14-lambda-execution-iam-role) + +#### 1.5 AWS Organizations + +- See [1.5 AWS Organizations](#./../../../solutions/common/common_register_delegated_administrator/README.md15-aws-organizations) + +--- + +### 2.0 Delegated Administrator Account (Audit) + +#### 2.1 Services Supported + +- See [2.1 Services Supported](#./../../../solutions/common/common_register_delegated_administrator/README.md21-services-supported) + +--- + +## Implementation Instructions + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for installation instructions. + +--- + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | >= 5.1.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [register\_delegated\_admin](#module\_register\_delegated\_admin) | ./register_admin | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [delegated\_admin\_account\_id](#input\_delegated\_admin\_account\_id) | Delegated Admin Account ID | `string` | n/a | yes | +| [register\_delegated\_admin\_lambda\_function\_name](#input\_register\_delegated\_admin\_lambda\_function\_name) | Register Delegated Admin - Lambda Function Name | `string` | `"sra-common-register-delegated-admin"` | no | +| [register\_delegated\_admin\_lambda\_role\_name](#input\_register\_delegated\_admin\_lambda\_role\_name) | Register Delegated Admin - Lambda Role Name | `string` | `"sra-common-register-delegated-admin-lambda"` | no | +| [service\_principal\_list](#input\_service\_principal\_list) | Comma delimited list of AWS service principals to delegate an administrator account | `list(string)` |
[
"access-analyzer.amazonaws.com",
"config-multiaccountsetup.amazonaws.com",
"config.amazonaws.com"
]
| no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/register_delegated_administrator/data.tf b/aws_sra_examples/terraform/solutions/register_delegated_administrator/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/register_delegated_administrator/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/register_delegated_administrator/main.tf b/aws_sra_examples/terraform/solutions/register_delegated_administrator/main.tf new file mode 100644 index 00000000..c9c4d37e --- /dev/null +++ b/aws_sra_examples/terraform/solutions/register_delegated_administrator/main.tf @@ -0,0 +1,12 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +module "register_delegated_admin" { + source = "./register_admin" + + register_delegated_admin_lambda_role_name = var.register_delegated_admin_lambda_role_name + register_delegated_admin_lambda_function_name = var.register_delegated_admin_lambda_function_name + service_principal_list = var.service_principal_list + delegated_admin_account_id = var.delegated_admin_account_id +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/register_delegated_administrator/providers.tf b/aws_sra_examples/terraform/solutions/register_delegated_administrator/providers.tf new file mode 100644 index 00000000..226f1ca4 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/register_delegated_administrator/providers.tf @@ -0,0 +1,13 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 5.1.0" + } + } +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/register_delegated_administrator/register_admin/data.tf b/aws_sra_examples/terraform/solutions/register_delegated_administrator/register_admin/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/register_delegated_administrator/register_admin/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/register_delegated_administrator/register_admin/invoke.tf b/aws_sra_examples/terraform/solutions/register_delegated_administrator/register_admin/invoke.tf new file mode 100644 index 00000000..39dfc20e --- /dev/null +++ b/aws_sra_examples/terraform/solutions/register_delegated_administrator/register_admin/invoke.tf @@ -0,0 +1,20 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_lambda_invocation" "lambda_invoke" { + function_name = aws_lambda_function.register_delegated_admin_lambda_function.function_name + + input = jsonencode({ + "RequestType" : "Create", + "ResourceType" : "Custom::LambdaCustomResource", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.register_delegated_admin_lambda_function.arn}", + "AWS_SERVICE_PRINCIPAL_LIST" : "${var.service_principal_list}", + "DELEGATED_ADMIN_ACCOUNT_ID" : "${var.delegated_admin_account_id}", + }, + "StackId" : "dummystackid/dummystack", + "RequestId" : "" + }) +} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/register_delegated_administrator/register_admin/main.tf b/aws_sra_examples/terraform/solutions/register_delegated_administrator/register_admin/main.tf new file mode 100644 index 00000000..cd9b84d9 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/register_delegated_administrator/register_admin/main.tf @@ -0,0 +1,165 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +locals { + src_path = "${path.root}/../../solutions/common/common_register_delegated_administrator/lambda/src/" +} + +resource "aws_cloudwatch_log_group" "register_delegated_admin_lambda_log_group" { + count = var.create_lambda_log_group == "true" ? 1 : 0 + name = "/aws/lambda/${var.register_delegated_admin_lambda_function_name}" + retention_in_days = var.lambda_log_group_retention + kms_key_id = var.lambda_log_group_kms_key != "" ? var.lambda_log_group_kms_key : null +} + +resource "aws_iam_role" "register_delegated_admin_lambda_role" { + name = var.register_delegated_admin_lambda_role_name + + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [ + { + Action = "sts:AssumeRole", + Effect = "Allow", + Principal = { + Service = "lambda.amazonaws.com" + } + } + ] + }) + + tags = { + "sra-solution" = var.sra_solution_name + } +} + +data "aws_iam_policy_document" "register_delegated_admin_policy_logs" { + version = "2012-10-17" + + statement { + sid = "CreateLogStreamAndEvents" + effect = "Allow" + + actions = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ] + + resources = [ + "arn:${data.aws_partition.current.partition}:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/${var.register_delegated_admin_lambda_function_name}:log-stream:*" + ] + } +} + +data "aws_iam_policy_document" "register_delegated_admin_policy_organizations" { + #checkov:skip=CKV_AWS_111: Ensure IAM policies does not allow write access without constraints + #checkov:skip=CKV_AWS_356: Ensure no IAM policies documents allow "*" as a statement's resource for restrictable actions + + version = "2012-10-17" + + statement { + sid = "OrganizationsAccess" + effect = "Allow" + + actions = [ + "organizations:DeregisterDelegatedAdministrator", + "organizations:DescribeOrganization", + "organizations:DisableAWSServiceAccess", + "organizations:EnableAWSServiceAccess", + "organizations:ListAWSServiceAccessForOrganization", + "organizations:ListDelegatedAdministrators", + "organizations:RegisterDelegatedAdministrator", + ] + + resources = ["*"] + } +} + +resource "aws_iam_policy" "register_delegated_admin_policy_logs" { + name = "sra-register-delegated-admin-policy-logs" + policy = data.aws_iam_policy_document.register_delegated_admin_policy_logs.json +} + +resource "aws_iam_policy" "register_delegated_admin_policy_organizations" { + name = "sra-register-delegated-admin-policy-organizations" + policy = data.aws_iam_policy_document.register_delegated_admin_policy_organizations.json +} + +resource "aws_iam_policy_attachment" "register_delegated_admin_policy_attachment_logs" { + name = "sra-register-delegated-admin-policy-logs-attachment" + roles = [aws_iam_role.register_delegated_admin_lambda_role.name] + policy_arn = aws_iam_policy.register_delegated_admin_policy_logs.arn +} + +resource "aws_iam_policy_attachment" "register_delegated_admin_policy_attachment_organizations" { + name = "sra-register-delegated-admin-policy-organizations-attachment" + roles = [aws_iam_role.register_delegated_admin_lambda_role.name] + policy_arn = aws_iam_policy.register_delegated_admin_policy_organizations.arn +} + +######################################################################## +# Lambda Function +######################################################################## + +data "archive_file" "hash_check" { + type = "zip" + source_dir = local.src_path + output_path = "${path.module}/lambda/lambda_function.zip" + excludes = ["lambda_function.zip, data.zip"] +} + +resource "null_resource" "package_lambda" { + triggers = { + src_hash = "${data.archive_file.hash_check.output_sha}" + } + + provisioner "local-exec" { + command = < + + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0 + +--- + +⚠️**Influence the future of the AWS Security Reference Architecture (AWS SRA) code library by taking a [short survey](https://amazonmr.au1.qualtrics.com/jfe/form/SV_9oFz0p67iCw3obk).** + +## + + +## Table of Contents + +- [Introduction](#introduction) +- [Deployed Resource Details](#deployed-resource-details) +- [Implementation Instructions](#implementation-instructions) +- [Requirements](#requirements) +- [Providers](#providers) +- [Modules](#modules) +- [Resources](#resources) +- [Inputs](#inputs) +- [Outputs](#outputs) + +--- + +## Introduction + +This Terraform module deploys Security Hub Organization AWS SRA solution. + +The common pre-requisite solution must be installed, in the management account, prior to installing this solution. + +Information on the resources deployed as well as terraform requirements, providers, modules, resources, and inputs of this module are documented below. + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for more information and installation instructions. + +*For the CloudFormation version of this AWS SRA solution as well as more information please navigate to the [AWS SRA Security Hub solution documentation](./../../../solutions/securityhub/securityhub_org/README.md) page.* + +--- + +## Deployed Resource Details + +![Architecture](./../../../solutions/securityhub/securityhub_org/documentation/securityhub-org-terraform.png) + +### 1.0 Organization Management Account + +#### 1.1 Lambda IAM Role + +- See [1.2 Lambda IAM Role](./../../../solutions/securityhub/securityhub_org/README.md#12-lambda-iam-role). + +#### 1.2 Regional Event Rule + +- See [1.3 Regional Event Rule](./../../../solutions/securityhub/securityhub_org/README.md#13-regional-event-rule) + +#### 1.3 Global Event Rules + +- See [1.4 Global Event Rules](./../../../solutions/securityhub/securityhub_org/README.md#14-global-event-rules) + +#### 1.4 SNS Topic + +- See [1.5 SNS Topic](./../../../solutions/securityhub/securityhub_org/README.md#15-sns-topic) + +#### 1.5 Dead Letter Queue (DLQ) + +- See [1.6 Dead Letter Queue (DLQ)](./../../../solutions/securityhub/securityhub_org/README.md#16-dead-letter-queue-dlq) + +#### 1.6 AWS Lambda Function + +- See [1.7 AWS Lambda Function](./../../../solutions/securityhub/securityhub_org/README.md#17-aws-lambda-function) + +#### 1.7 Lambda CloudWatch Log Group + +- See [1.8 Lambda CloudWatch Log Group](./../../../solutions/securityhub/securityhub_org/README.md#18-lambda-cloudwatch-log-group) + +#### 1.8 Alarm SNS Topic + +- See [1.9 Alarm SNS Topic](./../../../solutions/securityhub/securityhub_org/README.md#19-alarm-sns-topic) + +#### 1.9 Security Hub + +- See [1.10 Security Hub](./../../../solutions/securityhub/securityhub_org/README.md#110-security-hub) + +#### 1.10 Configuration IAM Role + +- See [1.11 Configuration IAM Role](./../../../solutions/securityhub/securityhub_org/README.md#111-configuration-iam-role) + +#### 1.11 Scheduled Event Rule + +- See [1.12 Regional Event Rule](./../../../solutions/securityhub/securityhub_org/README.md#112-regional-event-rule) + +#### 1.12 Config Recorder Start Event Rule + +- See [1.13 Config Recorder Start Event Rule](./../../../solutions/securityhub/securityhub_org/README.md#113-config-recorder-start-event-rule) + +#### 1.13 EventBridge IAM Role + +- See [1.14 EventBridge IAM Role](./../../../solutions/securityhub/securityhub_org/README.md#114-eventbridge-iam-role) + +--- + +### 2.0 Audit (Security Tooling) Account + +#### 2.1 Configuration IAM Role + +- See [2.2 Configuration IAM Role](./../../../solutions/securityhub/securityhub_org/README.md#22-configuration-iam-role) + +#### 2.2 Security Hub (Home Region) + +- See [2.3 Security Hub (Home Region)](./../../../solutions/securityhub/securityhub_org/README.md#23-security-hub-home-region) + +#### 2.3 Security Hub (Regions) + +- See [2.4 Security Hub (Regions)](./../../../solutions/securityhub/securityhub_org/README.md#24-security-hub-regions) + +#### 2.4 Config Recorder Start Event Rule + +- See [2.5 Config Recorder Start Event Rule](./../../../solutions/securityhub/securityhub_org/README.md#25-config-recorder-start-event-rule) + +#### 2.5 EventBridge IAM Role + +- See [2.6 EventBridge IAM Role](./../../../solutions/securityhub/securityhub_org/README.md#26-eventbridge-iam-role) + +--- + +### 3.0 All Existing and Future Organization Member Accounts + +#### 3.1 Configuration IAM Role + +- See [3.2 Configuration IAM Role](./../../../solutions/securityhub/securityhub_org/README.md#32-configuration-iam-role) + +#### 3.2 Security Hub + +- See [3.3 Security Hub](./../../../solutions/securityhub/securityhub_org/README.md#33-security-hub) + +#### 3.3 Config Recorder Start Event Rule + +- See [3.4 Config Recorder Start Event Rule](./../../../solutions/securityhub/securityhub_org/README.md#34-config-recorder-start-event-rule) + +#### 3.4 EventBridge IAM Role + +- See [3.5 EventBridge IAM Role](./../../../solutions/securityhub/securityhub_org/README.md#35-eventbridge-iam-role) + +--- + +## Implementation Instructions + +Please navigate to the [installing the AWS SRA Solutions](./../../README.md#installing-the-aws-sra-solutions) section of the documentation for installation instructions. + + +--- + +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | >= 5.1.0 | + +## Providers + +| Name | Version | +|------|---------| +| [aws.main](#provider\_aws.main) | >= 5.1.0 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [recorder\_start\_event](#module\_recorder\_start\_event) | ./recorder_start_event | n/a | +| [security\_hub](#module\_security\_hub) | ./configuration | n/a | +| [securityhub\_configuration\_role](#module\_securityhub\_configuration\_role) | ./configuration_role | n/a | + +## Resources + +| Name | Type | +|------|------| +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [audit\_account\_id](#input\_audit\_account\_id) | AWS Account ID of the Control Tower Audit account. | `string` | n/a | yes | +| [cis\_standard\_version](#input\_cis\_standard\_version) | CIS Standard Version | `string` | `"1.4.0"` | no | +| [compliance\_frequency](#input\_compliance\_frequency) | Frequency to Check for Organizational Compliance (in days between 1 and 30, default is 7) | `number` | `7` | no | +| [control\_tower\_lifecycle\_rule\_name](#input\_control\_tower\_lifecycle\_rule\_name) | The name of the AWS Control Tower Life Cycle Rule | `string` | `"sra-securityhub-org-trigger"` | no | +| [create\_lambda\_log\_group](#input\_create\_lambda\_log\_group) | Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function | `bool` | `false` | no | +| [delegated\_admin\_account\_id](#input\_delegated\_admin\_account\_id) | Delegated administrator account ID | `string` | n/a | yes | +| [disable\_security\_hub](#input\_disable\_security\_hub) | Update to 'true' to disable Security Hub in all accounts and regions before deleting the stack | `bool` | `false` | no | +| [enable\_cis\_standard](#input\_enable\_cis\_standard) | Indicates whether to enable the CIS AWS Foundations Benchmark Standard | `bool` | `false` | no | +| [enable\_nist\_standard](#input\_enable\_nist\_standard) | Indicates whether to enable the National Institute of Standards and Technology (NIST) SP 800-53 Rev. 5 | `bool` | `false` | no | +| [enable\_pci\_standard](#input\_enable\_pci\_standard) | Indicates whether to enable the Payment Card Industry Data Security Standard (PCI DSS) | `bool` | `false` | no | +| [enable\_security\_best\_practices\_standard](#input\_enable\_security\_best\_practices\_standard) | Indicates whether to enable the AWS Foundational Security Best Practices Standard | `bool` | `true` | no | +| [enabled\_regions](#input\_enabled\_regions) | (Optional) Enabled regions (AWS regions, separated by commas). Leave blank to enable all regions. | `string` | n/a | yes | +| [event\_rule\_role\_name](#input\_event\_rule\_role\_name) | Event rule role name for putting events on the home region event bus | `string` | `"sra-security-hub-global-events"` | no | +| [home\_region](#input\_home\_region) | Name of the Control Tower home region | `string` | n/a | yes | +| [lambda\_log\_group\_kms\_key](#input\_lambda\_log\_group\_kms\_key) | (Optional) KMS Key ARN to use for encrypting the Lambda logs data | `string` | `""` | no | +| [lambda\_log\_group\_retention](#input\_lambda\_log\_group\_retention) | Specifies the number of days you want to retain log events | `number` | `14` | no | +| [lambda\_log\_level](#input\_lambda\_log\_level) | Lambda Function Logging Level | `string` | `"INFO"` | no | +| [log\_archive\_account\_id](#input\_log\_archive\_account\_id) | AWS Account ID of the Control Tower Log Archive account. | `string` | n/a | yes | +| [management\_account\_id](#input\_management\_account\_id) | Organization Management Account ID | `string` | n/a | yes | +| [nist\_standard\_version](#input\_nist\_standard\_version) | NIST Standard Version | `string` | `"5.0.0"` | no | +| [organization\_id](#input\_organization\_id) | AWS Organizations ID | `string` | n/a | yes | +| [pci\_standard\_version](#input\_pci\_standard\_version) | PCI Standard Version | `string` | `"3.2.1"` | no | +| [region\_linking\_mode](#input\_region\_linking\_mode) | Indicates whether to aggregate findings from all of the available Regions in the current partition | `string` | `"SPECIFIED_REGIONS"` | no | +| [sechub\_rule\_name](#input\_sechub\_rule\_name) | Eventbridge rule name | `string` | `"sra-config-recorder"` | no | +| [security\_best\_practices\_standard\_version](#input\_security\_best\_practices\_standard\_version) | SBP Standard Version | `string` | `"1.0.0"` | no | +| [security\_hub\_configuration\_role\_name](#input\_security\_hub\_configuration\_role\_name) | SecurityHub Configuration role to assume in the delegated administrator account | `string` | `"sra-securityhub-configuration"` | no | +| [security\_hub\_org\_lambda\_function\_name](#input\_security\_hub\_org\_lambda\_function\_name) | Lambda function name | `string` | `"sra-securityhub-org"` | no | +| [security\_hub\_org\_lambda\_role\_name](#input\_security\_hub\_org\_lambda\_role\_name) | SecurityHub configuration Lambda role name | `string` | `"sra-securityhub-org-lambda"` | no | +| [securityhub\_control\_tower\_regions\_only](#input\_securityhub\_control\_tower\_regions\_only) | Only enable in the Control Tower governed regions | `bool` | `true` | no | +| [sra\_alarm\_email](#input\_sra\_alarm\_email) | (Optional) Email address for receiving DLQ alarms | `string` | `""` | no | +| [sra\_solution\_name](#input\_sra\_solution\_name) | The SRA solution name. The default value is the folder name of the solution. | `string` | `"sra-securityhub-org"` | no | + +## Outputs + +No outputs. + +--- + diff --git a/aws_sra_examples/terraform/solutions/security_hub/configuration/data.tf b/aws_sra_examples/terraform/solutions/security_hub/configuration/data.tf new file mode 100644 index 00000000..90baa06f --- /dev/null +++ b/aws_sra_examples/terraform/solutions/security_hub/configuration/data.tf @@ -0,0 +1,8 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} \ No newline at end of file diff --git a/aws_sra_examples/terraform/solutions/security_hub/configuration/invoke.tf b/aws_sra_examples/terraform/solutions/security_hub/configuration/invoke.tf new file mode 100644 index 00000000..6b824c69 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/security_hub/configuration/invoke.tf @@ -0,0 +1,29 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +resource "aws_lambda_invocation" "lambda_invoke" { + function_name = aws_lambda_function.security_hub_lambda_function.function_name + + input = jsonencode({ + "RequestType" : "Update", + "ResourceType" : "Custom::LambdaCustomResource", + "ResourceProperties" : { + "ServiceToken" : "${aws_lambda_function.security_hub_lambda_function.arn}", + "LOG_LEVEL" : "${var.lambda_log_level}", + "CIS_VERSION" : "${var.cis_standard_version}", + "CONFIGURATION_ROLE_NAME" : "${var.security_hub_configuration_role_name}", + "DISABLE_SECURITY_HUB" : "${var.disable_security_hub}", + "ENABLED_REGIONS" : "${var.enabled_regions}", + "ENABLE_CIS_STANDARD" : "${var.enable_cis_standard}", + "ENABLE_PCI_STANDARD" : "${var.enable_pci_standard}", + "ENABLE_NIST_STANDARD" : "${var.enable_nist_standard}", + "ENABLE_SECURITY_BEST_PRACTICES_STANDARD" : "${var.enable_security_best_practices_standard}", + "PCI_VERSION" : "${var.pci_standard_version}", + "NIST_VERSION" : "${var.nist_standard_version}", + "REGION_LINKING_MODE" : "${var.region_linking_mode}", + "SECURITY_BEST_PRACTICES_VERSION" : "${var.security_best_practices_standard_version}", + } + }) +} diff --git a/aws_sra_examples/terraform/solutions/security_hub/configuration/main.tf b/aws_sra_examples/terraform/solutions/security_hub/configuration/main.tf new file mode 100644 index 00000000..9204c589 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/security_hub/configuration/main.tf @@ -0,0 +1,644 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +locals { + #TODO: Figure out? + graviton_regions = [ + "ap-northeast-1", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ] + create_dlq_alarm = var.sra_alarm_email != "" ? true : false + src_path = "${path.root}/../../solutions/securityhub/securityhub_org/lambda/src/" +} + +######################################################################## +# Lambda Policies Documents +######################################################################## + +data "aws_iam_policy_document" "security_hub_org_assume_role" { + statement { + actions = ["sts:AssumeRole"] + effect = "Allow" + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "security_hub_org_lambda_role" { + name = var.security_hub_org_lambda_role_name + description = "Role for '${var.security_hub_org_lambda_role_name}' Lambda function" + + assume_role_policy = data.aws_iam_policy_document.security_hub_org_assume_role.json + + tags = { + "sra-solution" = var.sra_solution_name + } +} + +data "aws_iam_policy_document" "security_hub_org_policy_cloudformation" { + statement { + sid = "CloudFormation" + effect = "Allow" + actions = ["cloudformation:ListStackInstances"] + resources = ["arn:${data.aws_partition.current.partition}:cloudformation:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:stackset/AWSControlTowerBP-*"] + } +} + +data "aws_iam_policy_document" "security_hub_org_policy_ssm_access" { + statement { + sid = "SSMAccess" + effect = "Allow" + actions = [ + "ssm:GetParameter", + "ssm:GetParameters", + ] + resources = ["arn:${data.aws_partition.current.partition}:ssm:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:parameter/sra*"] + } +} + +data "aws_iam_policy_document" "security_hub_org_policy_securityhub" { + #checkov:skip=CKV_AWS_111: Ensure IAM policies does not allow write access without constraints + #checkov:skip=CKV_AWS_356: Ensure no IAM policies documents allow "*" as a statement's resource for restrictable actions + + statement { + sid = "SecurityHubNoResource" + effect = "Allow" + actions = [ + "securityhub:DisableOrganizationAdminAccount", + "securityhub:EnableOrganizationAdminAccount", + "securityhub:ListOrganizationAdminAccounts", + ] + resources = ["*"] + } + + statement { + sid = "SecurityHubWithResource" + effect = "Allow" + actions = [ + "securityhub:EnableSecurityHub", + ] + resources = [ + "arn:${data.aws_partition.current.partition}:securityhub:*:${data.aws_caller_identity.current.account_id}:hub/default", + "arn:${data.aws_partition.current.partition}:securityhub:*:${data.aws_caller_identity.current.account_id}:/accounts", + ] + } +} + +data "aws_iam_policy_document" "security_hub_org_policy_iam" { + statement { + sid = "AllowReadIamActions" + effect = "Allow" + actions = ["iam:GetRole"] + resources = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/*"] + } + + statement { + sid = "AllowCreateServiceLinkedRole" + effect = "Allow" + actions = ["iam:CreateServiceLinkedRole"] + condition { + test = "StringLike" + variable = "iam:AWSServiceName" + values = ["securityhub.amazonaws.com"] + } + resources = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/securityhub.amazonaws.com/AWSServiceRoleForSecurityHub"] + } + + statement { + sid = "AllowPolicyActions" + effect = "Allow" + actions = ["iam:PutRolePolicy"] + resources = ["arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/securityhub.amazonaws.com/AWSServiceRoleForSecurityHub"] + } + + statement { + sid = "AssumeRole" + effect = "Allow" + actions = ["sts:AssumeRole"] + condition { + test = "StringEquals" + variable = "aws:PrincipalOrgId" + values = [var.organization_id] + } + resources = [ + "arn:${data.aws_partition.current.partition}:iam::*:role/${var.security_hub_configuration_role_name}", + ] + } +} + +data "aws_iam_policy_document" "security_hub_org_policy_logs" { + statement { + sid = "CreateLogGroupAndEvents" + effect = "Allow" + actions = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"] + resources = ["arn:${data.aws_partition.current.partition}:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:log-group:/aws/lambda/${var.security_hub_org_lambda_function_name}:log-stream:*"] + } +} + +data "aws_iam_policy_document" "security_hub_org_policy_organizations" { + statement { + sid = "OrganizationsReadAccess" + effect = "Allow" + actions = [ + "organizations:DescribeOrganization", + "organizations:ListAWSServiceAccessForOrganization", + "organizations:ListAccounts", + "organizations:ListDelegatedAdministrators", + ] + resources = ["*"] + } + + statement { + sid = "AWSServiceAccess" + effect = "Allow" + actions = [ + "organizations:DisableAWSServiceAccess", + "organizations:EnableAWSServiceAccess", + ] + condition { + test = "StringLikeIfExists" + variable = "organizations:ServicePrincipal" + values = ["securityhub.amazonaws.com"] + } + resources = ["*"] + } + + statement { + sid = "RegisterDeregisterDelegatedAdministrator" + effect = "Allow" + actions = [ + "organizations:DeregisterDelegatedAdministrator", + "organizations:RegisterDelegatedAdministrator", + ] + condition { + test = "StringLikeIfExists" + variable = "organizations:ServicePrincipal" + values = ["securityhub.amazonaws.com"] + } + resources = ["arn:${data.aws_partition.current.partition}:organizations::*:account/o-*/*"] + } +} + +data "aws_iam_policy_document" "security_hub_org_policy_sns" { + statement { + sid = "SNSPublish" + effect = "Allow" + actions = ["sns:Publish", "sns:PublishBatch"] + resources = [aws_sns_topic.securityhub_org_topic.arn] + } +} + +data "aws_iam_policy_document" "security_hub_org_policy_sqs" { + statement { + sid = "SQSSendMessage" + effect = "Allow" + actions = ["sqs:SendMessage"] + resources = [aws_sqs_queue.securityhub_org_dlq.arn] + } +} + +######################################################################## +# Lambda Policies +######################################################################## + +resource "aws_iam_policy" "security_hub_org_policy_logs" { + name = "sra-security-hub-org-policy-logs" + policy = data.aws_iam_policy_document.security_hub_org_policy_logs.json +} + +resource "aws_iam_policy" "security_hub_org_policy_securityhub" { + name = "sra-security-hub-org-policy-securityhub" + policy = data.aws_iam_policy_document.security_hub_org_policy_securityhub.json +} + +resource "aws_iam_policy" "security_hub_org_policy_iam" { + name = "sra-security-hub-org-policy-iam" + policy = data.aws_iam_policy_document.security_hub_org_policy_iam.json +} + +resource "aws_iam_policy" "security_hub_org_policy_cloudformation" { + name = "sra-security-hub-org-policy-cloudformation" + policy = data.aws_iam_policy_document.security_hub_org_policy_cloudformation.json +} + +resource "aws_iam_policy" "security_hub_org_policy_ssm_access" { + name = "sra-security-hub-org-policy-ssm-access" + policy = data.aws_iam_policy_document.security_hub_org_policy_ssm_access.json +} + +resource "aws_iam_policy" "security_hub_org_policy_organizations" { + name = "sra-security-hub-org-policy-organizations-lambda" + policy = data.aws_iam_policy_document.security_hub_org_policy_organizations.json +} + +resource "aws_iam_policy" "security_hub_org_policy_sns" { + name = "sra-security-hub-org-policy-sns" + policy = data.aws_iam_policy_document.security_hub_org_policy_sns.json +} + +resource "aws_iam_policy" "security_hub_org_policy_sqs" { + name = "sra-security-hub-org-policy-sqs" + policy = data.aws_iam_policy_document.security_hub_org_policy_sqs.json +} + +######################################################################## +# Lambda Attachment +######################################################################## + +resource "aws_iam_policy_attachment" "security_hub_org_policy_attachment_logs" { + name = "sra-security-hub-org-policy-attachment-logs" + roles = [aws_iam_role.security_hub_org_lambda_role.name] + policy_arn = aws_iam_policy.security_hub_org_policy_logs.arn +} + +resource "aws_iam_policy_attachment" "security_hub_org_policy_attachment_securityhub" { + name = "sra-security-hub-org-policy-attachment-securityhub" + roles = [aws_iam_role.security_hub_org_lambda_role.name] + policy_arn = aws_iam_policy.security_hub_org_policy_securityhub.arn +} + +resource "aws_iam_policy_attachment" "security_hub_org_policy_attachment_iam" { + name = "sra-security-hub-org-policy-attachment-iam" + roles = [aws_iam_role.security_hub_org_lambda_role.name] + policy_arn = aws_iam_policy.security_hub_org_policy_iam.arn +} + +resource "aws_iam_policy_attachment" "security_hub_org_policy_attachment_cloudformation" { + name = "sra-security-hub-org-policy-attachment-cloudformation" + roles = [aws_iam_role.security_hub_org_lambda_role.name] + policy_arn = aws_iam_policy.security_hub_org_policy_cloudformation.arn +} + +resource "aws_iam_policy_attachment" "security_hub_org_policy_attachment_ssm_access" { + name = "sra-security-hub-org-policy-attachment-ssm-access" + roles = [aws_iam_role.security_hub_org_lambda_role.name] + policy_arn = aws_iam_policy.security_hub_org_policy_ssm_access.arn +} + +resource "aws_iam_policy_attachment" "security_hub_org_policy_attachment_organizations" { + name = "sra-securityhub-org-policy-attachment-organizations" + roles = [aws_iam_role.security_hub_org_lambda_role.name] + policy_arn = aws_iam_policy.security_hub_org_policy_organizations.arn +} + +resource "aws_iam_policy_attachment" "security_hub_org_policy_attachment_sns" { + name = "sra-securityhub-org-policy-attachment-sns" + roles = [aws_iam_role.security_hub_org_lambda_role.name] + policy_arn = aws_iam_policy.security_hub_org_policy_sns.arn +} + +resource "aws_iam_policy_attachment" "security_hub_org_policy_attachment_sqs" { + name = "sra-securityhub-org-policy-attachment-sqs" + roles = [aws_iam_role.security_hub_org_lambda_role.name] + policy_arn = aws_iam_policy.security_hub_org_policy_sqs.arn +} + +######################################################################## +# Cloud Watch Log Group +######################################################################## + +resource "aws_cloudwatch_log_group" "rSecurityHubOrgLambdaLogGroup" { + count = var.create_lambda_log_group ? 1 : 0 + name = "/aws/lambda/${var.security_hub_org_lambda_function_name}" + retention_in_days = var.lambda_log_group_retention + + kms_key_id = var.lambda_log_group_kms_key != null ? var.lambda_log_group_kms_key : null +} + +######################################################################## +# Lambda Function +######################################################################## + +data "archive_file" "hash_check" { + type = "zip" + source_dir = local.src_path + output_path = "${path.module}/lambda/lambda_function.zip" + excludes = ["lambda_function.zip, data.zip"] +} + +resource "null_resource" "package_lambda" { + triggers = { + src_hash = "${data.archive_file.hash_check.output_sha}" + } + + provisioner "local-exec" { + command = < None: + """Initialize the terraform project.""" + subprocess.run("terraform init -backend-config=backend.tfvars", check=True, shell=True) # nosec B602 # noqa: S602,S607,DUO116 + + +def set_supported_region() -> None: + """Set the supported regions from parameter store.""" + global SUPPORTED_REGIONS + + ssm_client = boto3.client("ssm") + customer_regions_parameter_name = "/sra/regions/customer-control-tower-regions" + home_region = "/sra/control-tower/home-region" + + response = ssm_client.get_parameter(Name=customer_regions_parameter_name, WithDecryption=True) # Use this if the parameter is encrypted with KMS + + customer_regions = response["Parameter"]["Value"] + + # Split the comma-separated values into a list + SUPPORTED_REGIONS = customer_regions.split(",") + + response = ssm_client.get_parameter(Name=home_region, WithDecryption=True) # Use this if the parameter is encrypted with KMS + + home_region = response["Parameter"]["Value"] + + if home_region in SUPPORTED_REGIONS: + SUPPORTED_REGIONS.remove(home_region) + SUPPORTED_REGIONS.insert(0, home_region) + + +def get_audit_account() -> str: + """Get audit account from AWS Organization. + + Returns: + str: audit account id + """ + ssm_client = boto3.client("ssm") + response = ssm_client.get_parameter( + Name="/sra/control-tower/audit-account-id", WithDecryption=True # Use this if the parameter is encrypted with KMS + ) + + return response["Parameter"]["Value"] + + +def get_accounts() -> list: + """Get all accounts from AWS Organization. + + Returns: + list: list of accounts in org + """ + organizations = boto3.client("organizations") + paginator = organizations.get_paginator("list_accounts") + + accounts = [account["Id"] for page in paginator.paginate() for account in page["Accounts"]] + audit_account = get_audit_account() + + # audit account needs to go last + if audit_account in accounts: + accounts.remove(audit_account) + accounts.append(audit_account) + + return accounts + + +def workspace_exists(account: str, region: str) -> bool: + """Check to see if workspace already exists for current terraform project. + + Args: + account (str): Account ID + region (str): Region + + Returns: + bool: Returns true if workspace already exists, false otherwise. + """ + completed_process = subprocess.run(f"terraform workspace list | grep {account}-{region}", shell=True) # nosec B602 # noqa: S602,DUO116 + return completed_process.returncode == 0 + + +def create_workspace(account: str, region: str) -> None: + """Create new workspace for terraform and saves it into state file. + + Args: + account (str): Account ID + region (str): Region + """ + subprocess.run(f"terraform workspace new {account}-{region}", check=True, shell=True) # nosec B602 # noqa: S602,DUO116 + + +def switch_to_workspace(account: str, region: str) -> None: + """Switch to a created workspace in Terraform. + + Args: + account (str): Account ID + region (str): Region + """ + subprocess.run(f"terraform workspace select {account}-{region}", check=True, shell=True) # nosec B602 # noqa: S602,DUO116 + + +def plan(account: str, region: str) -> None: + """Perform a terraform plan operation on all stacks. + + Args: + account (str): Account ID + region (str): Region + """ + subprocess.run( # noqa: DUO116 + f"terraform plan -var-file=config.tfvars -var account_id={account} -var account_region={region}", check=True, shell=True # noqa: S602,DUO116 + ) # nosec B602 # noqa: S602,DUO116 + + +def apply(account: str, region: str) -> None: + """Perform a terraform apply operation on all stacks. + + Args: + account (str): Account ID + region (str): Region + """ + subprocess.run( # noqa: DUO116 + f"terraform apply -var-file=config.tfvars -var account_id={account} -var account_region={region} -auto-approve", # noqa: DUO116 + check=True, + shell=True, # noqa: S602 + ) # nosec B602 # noqa: S602,DUO116 + + +def destroy(account: str, region: str) -> None: + """Perform a terraform destroy operation on all stacks. + + Args: + account (str): Account ID + region (str): Region + """ + subprocess.run( # noqa: DUO116 + f"terraform destroy -var-file=config.tfvars -var account_id={account} -var account_region={region} -auto-approve", # noqa: DUO116 + check=True, + shell=True, # noqa: S602 + ) # nosec B602 # noqa: S602,DUO116 + + +def main() -> None: # noqa: CCR001 + """Run the script.""" + # parse arguments + parser = argparse.ArgumentParser(description="Terraform Script to Deploy Stacksets") + parser.add_argument("cmd", help="terraform command to run") + args = parser.parse_args() + + set_supported_region() + + if args.cmd == "init": + init() + elif args.cmd == "plan": + for account in get_accounts(): + for region in SUPPORTED_REGIONS: + if not workspace_exists(account, region): + create_workspace(account, region) + + switch_to_workspace(account, region) + plan(account, region) + elif args.cmd == "apply": + for account in get_accounts(): + for region in SUPPORTED_REGIONS: + if not workspace_exists(account, region): + create_workspace(account, region) + + switch_to_workspace(account, region) + apply(account, region) + elif args.cmd == "destroy": + for account in get_accounts(): + for region in SUPPORTED_REGIONS: + if not workspace_exists(account, region): + create_workspace(account, region) + + switch_to_workspace(account, region) + destroy(account, region) + + +if __name__ == "__main__": + main() diff --git a/aws_sra_examples/terraform/solutions/variables.tf b/aws_sra_examples/terraform/solutions/variables.tf new file mode 100644 index 00000000..c52aa830 --- /dev/null +++ b/aws_sra_examples/terraform/solutions/variables.tf @@ -0,0 +1,351 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## + +variable "account_region" { + description = "Account Region used for assuming role" + type = string +} + +variable "account_id" { + description = "Account ID used for assuming role" + type = string +} +######################################################################## +# Main Configuration Parameters +######################################################################## + +variable "customer_control_tower_regions" { + description = "The name for customer control tower regions." + type = string +} + +variable "customer_control_tower_regions_without_home_region" { + description = "The name for customer control tower regions without home region." + type = string +} + +variable "enabled_regions" { + description = "The name for enabled regions." + type = string +} + +variable "enabled_regions_without_home_region" { + description = "The name for enabled regions without home region." + type = string +} + +variable "home_region" { + description = "The name for the home region." + type = string +} + +variable "audit_account_id" { + description = "The name for the audit account ID." + type = string +} + +variable "log_archive_account_id" { + description = "The name for the log archive account ID." + type = string +} + +variable "management_account_id" { + description = "The name for the management account ID." + type = string +} + +variable "organization_id" { + description = "The SSM parameter name for the organization ID." + type = string +} + +variable "root_organizational_unit_id" { + description = "The name for the root organizational unit ID." + type = string +} + +variable "sra_alarm_email" { + description = "(Optional) Email address for receiving DLQ alarms" + type = string + default = "" +} + +######################################################################## +# Service Configurations +######################################################################## +variable "enable_member_account_parameters" { + description = "Enable or disable Members Account Paramters module" + type = bool + default = true +} + +variable "enable_gd" { + description = "Enable or disable Guard Duty module" + type = bool + default = true +} + +variable "enable_sh" { + description = "Enable or disable Security Hub module" + type = bool + default = true +} + +variable "enable_access_analyzer" { + description = "Enable or disable IAM Access Analyzer module" + type = bool + default = true +} + +variable "enable_macie" { + description = "Enable or disable Macie module" + type = bool + default = true +} + +variable "enable_cloudtrail_org" { + description = "Enable or disable CloudTrail Organization module" + type = bool + default = true +} + +variable "enable_inspector" { + description = "Enable or disable Inspector module" + type = bool + default = true +} + +variable "enable_iam_password_policy" { + description = "Enable or disable IAM Password Policy Module" + type = bool + default = true +} + +######################################################################## +# Guard Duty Settings +######################################################################## +variable "disable_guard_duty" { + description = "Update to 'true' to disable GuardDuty in all accounts and regions before deleting the TF." + type = string + default = "false" +} + +variable "enable_s3_logs" { + description = "Auto enable S3 logs" + type = string +} + +variable "enable_kubernetes_audit_logs" { + description = "Auto enable Kubernetes Audit Logs" + type = string +} + +variable "enable_malware_protection" { + description = "Auto enable Malware Protection" + type = string +} + +variable "enable_rds_login_events" { + description = "Auto enable RDS Login Events" + type = string +} + +variable "enable_eks_runtime_monitoring" { + description = "Auto enable EKS Runtime Monitoring" + type = string +} + +variable "enable_eks_addon_management" { + description = "Auto enable EKS Add-on Management" + type = string +} + +variable "enable_lambda_network_logs" { + description = "Auto enable Lambda Network Logs" + type = string +} + +variable "finding_publishing_frequency" { + description = "Finding publishing frequency" + type = string + default = "FIFTEEN_MINUTES" +} + +variable "guardduty_control_tower_regions_only" { + description = "Only enable in the Control Tower governed regions" + type = string + default = "true" +} + +######################################################################## +# Security Hub Configurations +######################################################################## +variable "cis_standard_version" { + description = "CIS Standard Version" + type = string +} + +variable "compliance_frequency" { + description = "Frequency to Check for Organizational Compliance (in days between 1 and 30, default is 7)" + type = number +} + +variable "securityhub_control_tower_regions_only" { + description = "Only enable in the Control Tower governed regions" + type = bool +} + +variable "disable_security_hub" { + description = "Update to 'true' to disable Security Hub in all accounts and regions before deleting the stack" + type = bool +} + +variable "enable_cis_standard" { + description = "Indicates whether to enable the CIS AWS Foundations Benchmark Standard" + type = bool +} + +variable "enable_pci_standard" { + description = "Indicates whether to enable the Payment Card Industry Data Security Standard (PCI DSS)" + type = bool +} + +variable "enable_nist_standard" { + description = "Indicates whether to enable the National Institute of Standards and Technology (NIST) SP 800-53 Rev. 5" + type = bool +} + +variable "enable_security_best_practices_standard" { + description = "Indicates whether to enable the AWS Foundational Security Best Practices Standard" + type = bool +} + +variable "pci_standard_version" { + description = "PCI Standard Version" + type = string +} + +variable "nist_standard_version" { + description = "NIST Standard Version" + type = string +} + +variable "security_best_practices_standard_version" { + description = "SBP Standard Version" + type = string +} + +######################################################################## +# Inspector Configurations +######################################################################## +variable "ecr_rescan_duration" { + description = "ECR Rescan Duration" + type = string + default = "LIFETIME" +} + +variable "scan_components" { + description = "Components to scan (e.g., 'ec2,ecs')" + type = string + default = "ec2" +} + +variable "inspector_control_tower_regions_only" { + description = "Only enable in the Control Tower governed regions" + type = string + default = "true" +} + +variable "disable_inspector" { + description = "Set to true BEFORE removing/destroying the solution to reduce the chance of orphaned resources/configuraitons" + type = bool + default = false +} + +######################################################################## +# IAM Password Policy +######################################################################## +variable "iam_password_policy_allow_users_to_change_password" { + type = string + description = "You can permit all IAM users in your account to use the IAM console to change their own passwords." +} + +variable "iam_password_policy_hard_expiry" { + type = string + description = "You can prevent IAM users from choosing a new password after their current password has expired." +} + +variable "iam_password_policy_max_password_age" { + type = string + description = "You can set IAM user passwords to be valid for only the specified number of days." +} + +variable "iam_password_policy_minimum_password_length" { + type = string + description = "You can specify the minimum number of characters allowed in an IAM user password." +} + +variable "iam_password_policy_password_reuse_prevention" { + type = string + description = "You can prevent IAM users from reusing a specified number of previous passwords." +} + +variable "iam_password_policy_require_lowercase_characters" { + type = string + description = "You can require that IAM user passwords contain at least one lowercase character from the ISO basic Latin alphabet (a to z)." +} + +variable "iam_password_policy_require_numbers" { + type = string + description = "You can require that IAM user passwords contain at least one numeric character (0 to 9)." +} + +variable "iam_password_policy_require_symbols" { + type = string + description = "You can require that IAM user passwords contain at least one of the following nonalphanumeric characters: ! @ # $ % ^ & * ( ) _ + - = [ ] {} | '" +} + +variable "iam_password_policy_require_uppercase_characters" { + type = string + description = "You can require that IAM user passwords contain at least one uppercase character from the ISO basic Latin alphabet (A to Z)." +} + +######################################################################## +# Macie Configurations +######################################################################## +variable "macie_finding_publishing_frequency" { + type = string + description = "Macie finding publishing frequency" +} + +variable "disable_macie" { + type = string + description = "Update to 'true' to disable Macie in all accounts and regions before deleting the TF." +} + +######################################################################## +# CloudTrail Configurations +######################################################################## + +variable "enable_data_events_only" { + description = "Only Enable Cloud Trail Data Events" + type = string +} + +variable "enable_lambda_data_events" { + description = "Enable Cloud Trail Data Events for all Lambda functions" + type = string +} + +variable "enable_s3_data_events" { + description = "Enable Cloud Trail S3 Data Events for all buckets" + type = string +} + +variable "disable_cloudtrail" { + description = "set to TRUE before disabling the entire solution to remove its configuration before destroying resources" + type = bool + default = false +}