diff --git a/aws_sra_examples/solutions/account/account_alternate_contacts/lambda/src/app.py b/aws_sra_examples/solutions/account/account_alternate_contacts/lambda/src/app.py index 56c91080a..a60c324cd 100644 --- a/aws_sra_examples/solutions/account/account_alternate_contacts/lambda/src/app.py +++ b/aws_sra_examples/solutions/account/account_alternate_contacts/lambda/src/app.py @@ -24,7 +24,7 @@ from aws_lambda_typing.context import Context from aws_lambda_typing.events import CloudFormationCustomResourceEvent from mypy_boto3_account import AccountClient - from mypy_boto3_account.type_defs import DeleteAlternateContactRequestRequestTypeDef, PutAlternateContactRequestRequestTypeDef + from mypy_boto3_account.type_defs import DeleteAlternateContactRequestTypeDef, PutAlternateContactRequestTypeDef from mypy_boto3_organizations import OrganizationsClient from mypy_boto3_organizations.type_defs import AccountTypeDef, DescribeAccountResponseTypeDef, TagTypeDef from mypy_boto3_sns import SNSClient @@ -156,7 +156,7 @@ def add_alternate_contact( phone: Phone number for the alternate contact title: Title for the alternate contact """ - contact_parameters: PutAlternateContactRequestRequestTypeDef = { + contact_parameters: PutAlternateContactRequestTypeDef = { "AlternateContactType": contact_type, "EmailAddress": email, "Name": name, @@ -178,7 +178,7 @@ def delete_alternate_contact( aws_account: AWS account to update contact_type: Alternate contact type you want to update """ - contact_parameters: DeleteAlternateContactRequestRequestTypeDef = {"AlternateContactType": contact_type} + contact_parameters: DeleteAlternateContactRequestTypeDef = {"AlternateContactType": contact_type} try: account_client.delete_alternate_contact(**contact_parameters) LOGGER.info(f"Deleted {contact_type} Alternate Contact for account: {aws_account['Id']} ({aws_account['Name']})") diff --git a/aws_sra_examples/solutions/security_lake/security_lake_org/lambda/src/app.py b/aws_sra_examples/solutions/security_lake/security_lake_org/lambda/src/app.py index 8fdfe58f0..9559214a8 100644 --- a/aws_sra_examples/solutions/security_lake/security_lake_org/lambda/src/app.py +++ b/aws_sra_examples/solutions/security_lake/security_lake_org/lambda/src/app.py @@ -37,6 +37,8 @@ BOTO3_CONFIG = Config(retries={"max_attempts": 10, "mode": "standard"}) UNEXPECTED = "Unexpected!" SERVICE_NAME = "securitylake.amazonaws.com" +RESOURCE_MGMT_SERVICE_NAME = "resource-management.securitylake.amazonaws.com" +SLR_NAME = "AWSServiceRoleForSecurityLakeResourceManagement" HOME_REGION = ssm.get_home_region() AUDIT_ACCT_ID = ssm.get_security_acct() AWS_LOG_SOURCES = ["ROUTE53", "VPC_FLOW", "SH_FINDINGS", "CLOUD_TRAIL_MGMT", "LAMBDA_EXECUTION", "S3_DATA", "EKS_AUDIT", "WAF"] @@ -388,6 +390,14 @@ def add_log_sources(params: dict, regions: list, org_accounts: dict) -> None: aws_log_sources.append(configurations) if aws_log_sources: security_lake.add_aws_log_source(sl_client, aws_log_sources) + for region in regions: + formatted_region = region.replace("-", "_") + lf_client = delegated_admin_session.client("lakeformation", region) + principal_identifier = ( + f"arn:{PARTITION}:iam::{params['DELEGATED_ADMIN_ACCOUNT_ID']}:role/aws-service-role/{RESOURCE_MGMT_SERVICE_NAME}/{SLR_NAME}" + ) + db_name = f"amazon_security_lake_glue_db_{formatted_region}" + security_lake.set_lake_formation_permissions_for_slr(lf_client, params["DELEGATED_ADMIN_ACCOUNT_ID"], principal_identifier, db_name) def update_log_sources(params: dict, regions: list, org_accounts: dict) -> None: diff --git a/aws_sra_examples/solutions/security_lake/security_lake_org/lambda/src/security_lake.py b/aws_sra_examples/solutions/security_lake/security_lake_org/lambda/src/security_lake.py index 851e3e043..c51ec656f 100644 --- a/aws_sra_examples/solutions/security_lake/security_lake_org/lambda/src/security_lake.py +++ b/aws_sra_examples/solutions/security_lake/security_lake_org/lambda/src/security_lake.py @@ -897,6 +897,35 @@ def create_table_in_data_catalog(glue_client: GlueClient, shared_db_name: str, s raise ValueError(f"Error calling glue:CreateTable {e}") from None +def set_lake_formation_permissions_for_slr(lf_client: LakeFormationClient, account: str, principal_identifier: str, db_name: str) -> None: + """Set Lake Formation permissions. + + Args: + lf_client: boto3 client + account: AWS account + principal_identifier: data lake principal identifier + db_name: database name + + Raises: + ClientError: If there is an issue interacting with the AWS API + + """ + LOGGER.info(f"Setting lakeformation permissions for '{db_name}'") + try: + resource: Union[ResourceTypeDef] = { + "Table": {"CatalogId": account, "DatabaseName": db_name, "TableWildcard": {}}, + } + lf_client.grant_permissions( + CatalogId=account, + Principal={"DataLakePrincipalIdentifier": principal_identifier}, + Resource=resource, + Permissions=["ALTER", "DESCRIBE"], + ) + except ClientError as e: + LOGGER.error(f"Error calling GrantPermissions {e}.") + raise + + def set_lake_formation_permissions(lf_client: LakeFormationClient, account: str, db_name: str) -> None: """Set Lake Formation permissions. diff --git a/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-configuration-role.yaml b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-configuration-role.yaml index 518864747..d7a72bc93 100644 --- a/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-configuration-role.yaml +++ b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-configuration-role.yaml @@ -182,6 +182,17 @@ Resources: Condition: StringLike: ram:ResourceShareName: !Sub "*-${pAuditAccountQuerySubscriberExternalId}" + - PolicyName: sra-security-lake-org-policy-slr + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: AllowGrantPermissions + Effect: Allow + Action: + - lakeformation:GrantPermissions + - glue:GetDatabase + - glue:GetTable + Resource: "*" Tags: - Key: sra-solution Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-configuration.yaml b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-configuration.yaml index 0d62d8706..024066057 100644 --- a/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-configuration.yaml +++ b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-configuration.yaml @@ -472,17 +472,21 @@ Resources: Resource: "*" - Sid: AllowCreateServiceLinkedRole Effect: Allow - Action: iam:CreateServiceLinkedRole + Action: + - iam:CreateServiceLinkedRole + - iam:GetRole Condition: StringLike: - iam:AWSServiceName: securitylake.amazonaws.com + iam:AWSServiceName: + - securitylake.amazonaws.com + - resource-management.securitylake.amazonaws.com Resource: "*" - Sid: SecurityLakeRemoveAdministratorAccess Effect: Allow Action: - organizations:DeregisterDelegatedAdministrator Resource: "*" - - PolicyName: sra-account-alternate-contacts-policy-organizations + - PolicyName: sra-security-lake-policy-organizations PolicyDocument: Version: 2012-10-17 Statement: diff --git a/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-kms-key.yaml b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-kms-key.yaml index 6b8018b60..da55de89f 100644 --- a/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-kms-key.yaml +++ b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-kms-key.yaml @@ -122,6 +122,19 @@ Resources: - kms:Decrypt Resource: '*' - !Ref AWS::NoValue + - Sid: Allow SLR + Effect: Allow + Principal: + AWS: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/resource-management.securitylake.amazonaws.com/AWSServiceRoleForSecurityLakeResourceManagement' + Action: + - kms:Decrypt + - kms:GenerateDataKey* + Resource: '*' + Condition: + StringLike: + 'kms:EncryptionContext:aws:s3:arn': + - !Sub 'arn:${AWS::Partition}:s3:::aws-security-data-lake-${AWS::Region}*' + 'kms:ViaService': !Sub 's3.${AWS::Region}.amazonaws.com' Tags: - Key: sra-solution Value: !Ref pSRASolutionName diff --git a/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-main-ssm.yaml b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-main-ssm.yaml index 899bdeae1..637647afe 100644 --- a/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-main-ssm.yaml +++ b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-security-lake-org-main-ssm.yaml @@ -31,6 +31,7 @@ Metadata: - pDisableSecurityLake - pControlTowerRegionsOnly - pEnabledRegions + - pCreateAWSServiceRoleForSecurityLakeResourceManagementSlr - pSecurityLakeOrgKeyAlias - pSecurityLakeWarning - pSRASecurityLakeMetaStoreManagerRoleName @@ -93,6 +94,8 @@ Metadata: default: CloudTrail - Lambda Data Events (recommended) pCloudTrailS3DataEvents: default: CloudTrail - S3 Data Events (high volume data) + pCreateAWSServiceRoleForSecurityLakeResourceManagementSlr: + default: Create AWS Service Role for Security Lake Resource Management. pCustomerControlTowerRegions: default: Customer Regions pSecurityHubFindings: @@ -167,6 +170,11 @@ Metadata: default: Lambda Role Name Parameters: + pCreateAWSServiceRoleForSecurityLakeResourceManagementSlr: + AllowedValues: ['true', 'false'] + Default: 'true' + Description: Indicates whether to create a AWSServiceRoleForSecurityLakeResourceManagement service-linked role. Select True if this role does not exist in the Log Archive account + Type: String pSecurityLakeOrgLambdaRoleName: AllowedPattern: '^[\w+=,.@-]{1,64}$' ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] @@ -419,6 +427,9 @@ Conditions: cCreateLakeFormationSlr: !Equals - !Ref pCreateLakeFormationSlr - 'true' + cAWSServiceRoleForSecurityLakeResourceManagement: !Equals + - !Ref pCreateAWSServiceRoleForSecurityLakeResourceManagementSlr + - 'true' Rules: VerifySecurityLakeDisclaimer: @@ -598,9 +609,42 @@ Resources: - Key: sra-solution Value: !Ref pSRASolutionName + + rAWSServiceRoleForSecurityLakeResourceManagementSLRStackSet: + Type: AWS::CloudFormation::StackSet + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Condition: cAWSServiceRoleForSecurityLakeResourceManagement + Properties: + StackSetName: sra-security-lake-resource-management-slr + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole} + CallAs: SELF + Capabilities: + - CAPABILITY_NAMED_IAM + Description: !Sub ${pSRASolutionVersion} - Deploys AWS Lake Formation service-linked role via ${pSRASolutionName} + ExecutionRoleName: !Ref pStackExecutionRole + ManagedExecution: + Active: true + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !Ref pLogArchiveAccountId + Regions: + - !Ref AWS::Region + TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-service-role-for-asl-resource-management.yaml + Tags: + - Key: sra-solution + Value: !Ref pSRASolutionName + rSecurityLakeKMSKeyStackSet: Type: AWS::CloudFormation::StackSet - DependsOn: rSecurityLakeConfigurationIAMRoleStackSet + DependsOn: + - rSecurityLakeConfigurationIAMRoleStackSet DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: @@ -644,7 +688,7 @@ Resources: rSecurityLakeMetaStoreManagerIAMRoleStackSet: Type: AWS::CloudFormation::StackSet - DeletionPolicy: Delete + DeletionPolicy: Retain UpdateReplacePolicy: Delete Properties: StackSetName: sra-security-lake-meta-store-manager-role diff --git a/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-service-role-for-asl-resource-management.yaml b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-service-role-for-asl-resource-management.yaml new file mode 100644 index 000000000..822c7e9d7 --- /dev/null +++ b/aws_sra_examples/solutions/security_lake/security_lake_org/templates/sra-service-role-for-asl-resource-management.yaml @@ -0,0 +1,19 @@ +######################################################################## +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: MIT-0 +######################################################################## +AWSTemplateFormatVersion: 2010-09-09 +Description: + This template creates an IAM role to configure the delegated administrator account - - 'security_lake_org' solution in the repo, + https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8p) + +Metadata: + SRA: + Version: 1.0 + Order: 2 + +Resources: + rAWSServiceRoleForSecurityLakeResourceManagementSLR: + Type: AWS::IAM::ServiceLinkedRole + Properties: + AWSServiceName: resource-management.securitylake.amazonaws.com