AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: Amazon S3 Find and Forget VPC (uksb-1qjminsd5) Globals: Function: Runtime: python3.9 Timeout: 30 Layers: !Ref CommonLayers Parameters: FlowLogsGroup: Type: String Default: "" FlowLogsRoleArn: Type: String Default: "" KMSKeyArns: Description: Comma-delimited list of KMS Key Id Arns used for Client-side Hash. Leave list empty if data is not encrypted with CSE-KMS Type: String Default: "" PrivateSubnetIpBlocks: Description: Comma-delimited list of CIDR blocks for the private subnets Type: CommaDelimitedList Default: "10.0.0.0/22,10.0.4.0/22,10.0.8.0/22" VpcIpBlock: Description: CIDR block for the VPC Type: String Default: 10.0.0.0/16 AllowedPattern: ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(1[6-9]|2[0-8]))$ CommonLayers: Type: CommaDelimitedList Mappings: Regions: ap-northeast-1: HasThreeAZs: true ap-northeast-2: HasThreeAZs: true ap-south-1: HasThreeAZs: true ap-southeast-1: HasThreeAZs: true ap-southeast-2: HasThreeAZs: true ca-central-1: HasThreeAZs: true eu-central-1: HasThreeAZs: true eu-north-1: HasThreeAZs: true eu-west-1: HasThreeAZs: true eu-west-2: HasThreeAZs: true eu-west-3: HasThreeAZs: true sa-east-1: HasThreeAZs: true us-east-1: HasThreeAZs: true us-east-2: HasThreeAZs: true us-west-1: HasThreeAZs: false us-west-2: HasThreeAZs: true cn-north-1: HasThreeAZs: true Conditions: HasThreeAZs: !Equals [!FindInMap [Regions, !Ref "AWS::Region", HasThreeAZs], true] EnableFlowLogs: !And - !Not [!Equals [!Ref FlowLogsGroup, ""]] - !Not [!Equals [!Ref FlowLogsRoleArn, ""]] WithKMS: !Not [!Equals [!Ref KMSKeyArns, ""]] ChinaRegion: !Equals [!Select [0, !Split ["-", !Ref "AWS::Region"]], "cn"] Resources: VPC: Type: AWS::EC2::VPC Properties: EnableDnsSupport: true EnableDnsHostnames: true CidrBlock: !Ref VpcIpBlock Tags: - Key: Name Value: !Sub ${AWS::StackName} VPC FlowLog: Type: AWS::EC2::FlowLog Condition: EnableFlowLogs Properties: DeliverLogsPermissionArn: !Ref FlowLogsRoleArn LogGroupName: !Ref FlowLogsGroup ResourceId: !Ref VPC ResourceType: VPC TrafficType: ALL PrivateNetworkAcl: Type: AWS::EC2::NetworkAcl Properties: VpcId: !Ref VPC PrivateNetworkAclEntryInAllowVPC: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref PrivateNetworkAcl RuleNumber: 99 Protocol: -1 RuleAction: allow Egress: false CidrBlock: 0.0.0.0/0 PrivateNetworkAclEntryOutAllowVPC: Type: AWS::EC2::NetworkAclEntry Properties: NetworkAclId: !Ref PrivateNetworkAcl RuleNumber: 99 Protocol: -1 RuleAction: allow Egress: true CidrBlock: 0.0.0.0/0 PrivateRouteTable1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC PrivateRouteTable2: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC PrivateRouteTable3: Type: AWS::EC2::RouteTable Condition: HasThreeAZs Properties: VpcId: !Ref VPC PrivateRouteTableAssociation1: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnet1 RouteTableId: !Ref PrivateRouteTable1 PrivateRouteTableAssociation2: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PrivateSubnet2 RouteTableId: !Ref PrivateRouteTable2 PrivateRouteTableAssociation3: Type: AWS::EC2::SubnetRouteTableAssociation Condition: HasThreeAZs Properties: SubnetId: !Ref PrivateSubnet3 RouteTableId: !Ref PrivateRouteTable3 PrivateSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: !Select [0, !Ref PrivateSubnetIpBlocks] AvailabilityZone: !Select [0, !GetAZs ''] Tags: - Key: Name Value: !Sub ${AWS::StackName} Private Subnet 1 PrivateSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: !Select [1, !Ref PrivateSubnetIpBlocks] AvailabilityZone: !Select [1, !GetAZs ''] Tags: - Key: Name Value: !Sub ${AWS::StackName} Private Subnet 2 PrivateSubnet3: Type: AWS::EC2::Subnet Condition: HasThreeAZs Properties: VpcId: !Ref VPC CidrBlock: !Select [2, !Ref PrivateSubnetIpBlocks] AvailabilityZone: !Select [2, !GetAZs ''] Tags: - Key: Name Value: !Sub ${AWS::StackName} Private Subnet 3 PrivateSubnetNetworkAclAssociation1: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PrivateSubnet1 NetworkAclId: !Ref PrivateNetworkAcl PrivateSubnetNetworkAclAssociation2: Type: AWS::EC2::SubnetNetworkAclAssociation Properties: SubnetId: !Ref PrivateSubnet2 NetworkAclId: !Ref PrivateNetworkAcl PrivateSubnetNetworkAclAssociation3: Type: AWS::EC2::SubnetNetworkAclAssociation Condition: HasThreeAZs Properties: SubnetId: !Ref PrivateSubnet3 NetworkAclId: !Ref PrivateNetworkAcl SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Ref AWS::StackName VpcId: !Ref VPC SecurityGroupEgress: - IpProtocol: tcp Description: Egress Rule for VPC Endpoints FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 SecurityGroupIngress: - IpProtocol: tcp Description: Ingress Rule FromPort: 443 ToPort: 443 CidrIp: !Ref VpcIpBlock GetEndpointSubnetFunction: Type: AWS::Serverless::Function Properties: Handler: get_vpce_subnets.handler CodeUri: ../backend/lambdas/custom_resources/ Description: Custom Lambda resource for the Amazon S3 Find and Forget Cloudformation Stack Policies: - Statement: - Effect: Allow Action: - ec2:DescribeSubnets - ec2:DescribeVpcEndpointServices Resource: '*' # Endpoints CloudWatchEndpointSubnets: Type: Custom::Setup Condition: ChinaRegion Properties: ServiceToken: !GetAtt GetEndpointSubnetFunction.Arn ServiceName: !Sub 'com.amazonaws.${AWS::Region}.monitoring' SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface CloudWatchEndpoint: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: [!Ref SecurityGroup] ServiceName: !If - ChinaRegion - !GetAtt CloudWatchEndpointSubnets.ServiceName - !Sub 'com.amazonaws.${AWS::Region}.monitoring' SubnetIds: !If - ChinaRegion - !Split [',', !Ref CloudWatchEndpointSubnets] - - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface VpcId: !Ref VPC CloudWatchLogsEndpointSubnets: Type: Custom::Setup Condition: ChinaRegion Properties: ServiceToken: !GetAtt GetEndpointSubnetFunction.Arn ServiceName: !Sub 'com.amazonaws.${AWS::Region}.logs' SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface CloudWatchLogsEndpoint: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: [!Ref SecurityGroup] ServiceName: !If - ChinaRegion - !GetAtt CloudWatchLogsEndpointSubnets.ServiceName - !Sub 'com.amazonaws.${AWS::Region}.logs' SubnetIds: !If - ChinaRegion - !Split [',', !Ref CloudWatchLogsEndpointSubnets] - - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface VpcId: !Ref VPC ECREndpointSubnets: Type: Custom::Setup Condition: ChinaRegion Properties: ServiceToken: !GetAtt GetEndpointSubnetFunction.Arn ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.dkr' SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface ECREndpoint: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: [!Ref SecurityGroup] ServiceName: !If - ChinaRegion - !GetAtt ECREndpointSubnets.ServiceName - !Sub 'com.amazonaws.${AWS::Region}.ecr.dkr' SubnetIds: !If - ChinaRegion - !Split [',', !Ref ECREndpointSubnets] - - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface VpcId: !Ref VPC ECRAPIEndpointSubnets: Type: Custom::Setup Condition: ChinaRegion Properties: ServiceToken: !GetAtt GetEndpointSubnetFunction.Arn ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.api' SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface ECRAPIEndpoint: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: [!Ref SecurityGroup] ServiceName: !If - ChinaRegion - !GetAtt ECRAPIEndpointSubnets.ServiceName - !Sub 'com.amazonaws.${AWS::Region}.ecr.api' SubnetIds: !If - ChinaRegion - !Split [',', !Ref ECRAPIEndpointSubnets] - - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface VpcId: !Ref VPC S3Endpoint: Type: AWS::EC2::VPCEndpoint Properties: RouteTableIds: - !Ref PrivateRouteTable1 - !Ref PrivateRouteTable2 - !If [HasThreeAZs, !Ref PrivateRouteTable3, !Ref 'AWS::NoValue'] ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3' VpcId: !Ref VPC SQSEndpointSubnets: Type: Custom::Setup Condition: ChinaRegion Properties: ServiceToken: !GetAtt GetEndpointSubnetFunction.Arn ServiceName: !Sub 'com.amazonaws.${AWS::Region}.sqs' SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface SQSEndpoint: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: [!Ref SecurityGroup] ServiceName: !If - ChinaRegion - !GetAtt SQSEndpointSubnets.ServiceName - !Sub 'com.amazonaws.${AWS::Region}.sqs' SubnetIds: !If - ChinaRegion - !Split [',', !Ref SQSEndpointSubnets] - - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface VpcId: !Ref VPC DynamoEndpoint: Type: AWS::EC2::VPCEndpoint Properties: RouteTableIds: - !Ref PrivateRouteTable1 - !Ref PrivateRouteTable2 - !If [HasThreeAZs, !Ref PrivateRouteTable3, !Ref 'AWS::NoValue'] ServiceName: !Sub 'com.amazonaws.${AWS::Region}.dynamodb' VpcId: !Ref VPC STSEndpointSubnets: Type: Custom::Setup Condition: ChinaRegion Properties: ServiceToken: !GetAtt GetEndpointSubnetFunction.Arn ServiceName: !Sub 'com.amazonaws.${AWS::Region}.sts' SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface STSEndpoint: Type: AWS::EC2::VPCEndpoint Properties: PrivateDnsEnabled: true SecurityGroupIds: [!Ref SecurityGroup] ServiceName: !If - ChinaRegion - !GetAtt STSEndpointSubnets.ServiceName - !Sub 'com.amazonaws.${AWS::Region}.sts' SubnetIds: !If - ChinaRegion - !Split [',', !Ref STSEndpointSubnets] - - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface VpcId: !Ref VPC KMSEndpointSubnets: Type: Custom::Setup Condition: ChinaRegion Properties: ServiceToken: !GetAtt GetEndpointSubnetFunction.Arn ServiceName: !Sub 'com.amazonaws.${AWS::Region}.kms' SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface KMSEndpoint: Type: AWS::EC2::VPCEndpoint Condition: WithKMS Properties: PrivateDnsEnabled: true SecurityGroupIds: [!Ref SecurityGroup] ServiceName: !If - ChinaRegion - !GetAtt KMSEndpointSubnets.ServiceName - !Sub 'com.amazonaws.${AWS::Region}.kms' SubnetIds: !If - ChinaRegion - !Split [',', !Ref KMSEndpointSubnets] - - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !If [HasThreeAZs, !Ref PrivateSubnet3, !Ref 'AWS::NoValue'] VpcEndpointType: Interface VpcId: !Ref VPC Outputs: Subnets: Value: !If - HasThreeAZs - !Sub ${PrivateSubnet1},${PrivateSubnet2},${PrivateSubnet3} - !Sub ${PrivateSubnet1},${PrivateSubnet2} SecurityGroup: Value: !Ref SecurityGroup Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "Network Configuration" Parameters: - VpcIpBlock - PrivateSubnetIpBlocks - Label: default: "Optional Logging Configuration" Parameters: - FlowLogsGroup - FlowLogsRoleArn