AWSTemplateFormatVersion: '2010-09-09'
Description:  This template deploys the infrastructure for the EMR on Outposts blog post

Parameters:
# -----------------------------------------------------------------------------------
# S3 bucket used to store the support files
#
  S3BucketName:
    Type: "String"
    Description: "The bucket name used to store the sample data/EMR logs.The stack will append the bucket name you provide with the text outpostblog-<account_id>"
    Default: "emroutpostblog-123"

# -----------------------------------------------------------------------------------
# VPC and subnet CIDRs
#
  VpcCIDR:
    Type: "String"
    Description: "VPC CIDR. Corresponds to circle 1 in the architecture diagram"
    Default: "172.29.0.0/16"

  OutpostSubnetCIDR:
    Type: "String"
    Description: "CIDR of the private subnet created in the Outpost.Corresponds to circle 2 in the architecture diagram"
    Default: "172.29.0.0/24"

  PrivateSubnetAZACIDR:
    Description: "Please enter the IP range (CIDR notation) for the private subnet in the region. Corresponds to circle 4 in the architecture diagram"
    Type: String
    Default: 172.29.10.0/24

  AmazonS3SubnetCIDR:
    Description: "Please enter the IP range (CIDR notation) for subnet to access the Amazon S3 on the region privately. Corresponds to circle 6 in the architecture diagram"
    Type: String
    Default: "10.11.0.0/24"

# -----------------------------------------------------------------------------------
#  Information about the AWS Outposts Rack
#
  OutpostARN:
    Type: "String"
    Description: "The Amazon Resource Name (ARN) of the Outpost (ex: arn:aws:outposts:us-east-1:012345678901:outpost/op-01234567890abcdef)"
    Default: "arn:aws:outposts:eu-central-1:<accountNumber>:outpost/<outpostID>"

  OutpostId:
    Type: "String"
    Description: "The Outpost ID"
    Default: "<outpostID>"
  
  LocalGatewayId:
    Type: "String"
    Description: "The Local Gateway ID"
    Default: "<LocalGateWayId>"

  LocalGatewayRouteTableId:
    Type: "String"
    Description: "The ID of the local gateway route table (ex: lgw-rtb-01234567890123456)"
    Default: "<LocalGatewayRouteTableId>"
  
  OutpostAvailabilityZone:
    Type: "String"
    Description: "Availability zone of Outposts (ex: us-east-1a)"
    Default: "eu-central-1c"

Resources:
# -----------------------------------------------------------------------------------
#  Bucket to store the support files to deploy the EMR on Outposts
#
  S3BucketBlogEMROnOutposts:
    Type: 'AWS::S3::Bucket'
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W35
            reason: "Logs will not be enable for this bucket"
          - id: W51
            reason: "Bucket policy will not be defined for this bucket"
      checkov:
        skip:
          - id: CKV_AWS_18
            comment: "S3 access logging is not required for this bucket as per our internal policy"
    Properties:
      BucketName: !Sub '${S3BucketName}outpostblog-${AWS::AccountId}'
      BucketEncryption:
        ServerSideEncryptionConfiguration: 
        - ServerSideEncryptionByDefault:
            SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      VersioningConfiguration:
        Status: Enabled

# -----------------------------------------------------------------------------------
#  VPC used to deploy EMR cluster on Outposts
#
  VPCEMRonOutposts:
    Type: 'AWS::EC2::VPC'
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W60
            reason: "VPC flow log will not be enable in this sample code. If you need to enable it, follow the instructions in https://docs.aws.amazon.com/vpc/latest/userguide/working-with-flow-logs.html"
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: "Name"
          Value: "vpc-emr-on-outposts"
        - Key: "for-use-with-amazon-emr-managed-policies"
          Value: "true"

  # VPC association with the Outpost Local Gateway
  VPCAssociationLGWRouteTable:
    Type: 'AWS::EC2::LocalGatewayRouteTableVPCAssociation'
    Properties:
         LocalGatewayRouteTableId: !Ref LocalGatewayRouteTableId
         VpcId: !Ref VPCEMRonOutposts

# -----------------------------------------------------------------------------------
# Internet Gateway
#
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: "vpc-emr-on-outposts-igw"
  
  # Internet Gateway Attachment
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPCEMRonOutposts

# -----------------------------------------------------------------------------------
# NAT Gateway
#
  # Nat Gateway IP to allow SSM Session Manager Connections
  NatGatewayZAEIP:
    Type: AWS::EC2::EIP
    DependsOn: InternetGatewayAttachment
    Properties:
      Domain: vpc
  # Nat Gateway to allow SSM Session Manager Connections
  NatGatewayZA:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NatGatewayZAEIP.AllocationId
      SubnetId: !Ref PublicSubnetAZA

# -----------------------------------------------------------------------------------
# Subnets
#
  # Public subnet to allow SSM Session Manager Connections
  PublicSubnetAZA:
    Type: AWS::EC2::Subnet
    Metadata:
      cfn-lint:
        config:
          ignore_checks:
            - W3010
    Properties:
      VpcId: !Ref VPCEMRonOutposts
      CidrBlock: !Ref PrivateSubnetAZACIDR
      MapPublicIpOnLaunch: false
      Tags:
        - Key: "for-use-with-amazon-emr-managed-policies"
          Value: "true"

  # Subnet create in the Outposts for the EMR Cluster
  OutpostPrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPCEMRonOutposts
      CidrBlock: !Ref OutpostSubnetCIDR
      OutpostArn: !Ref OutpostARN
      AvailabilityZone: !Ref OutpostAvailabilityZone
      MapPublicIpOnLaunch: false
      Tags:
        - Key: "Name"
          Value: "outpost-private-subnet"
        - Key: "for-use-with-amazon-emr-managed-policies"
          Value: "true"

# -----------------------------------------------------------------------------------
#  Route tables
#
  # Public Route Table to allow SSM Session Manager Connections
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPCEMRonOutposts

  # Route table for the private subnet created in the Outposts
  OutpostPrivateSubnetRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPCEMRonOutposts
      Tags:
        - Key: Name
          Value: "outpost-private-subnet-route-table"

# -----------------------------------------------------------------------------------
#  Route table subnet association
#
  # Private Subnet Route Table Association to allow SSM Session Manager Connections
  PrivateSubnetZARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PublicRouteTable
      SubnetId: !Ref PublicSubnetAZA

  # Association of the route table with the private subnet created in the Outposts
  OutpostPrivateSubnetZARouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref OutpostPrivateSubnetRouteTable
      SubnetId: !Ref OutpostPrivateSubnet

  # Default Public Route to allow SSM Session Manager Connections
  DefaultPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: InternetGatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  
  OutpostPrivateSubnetNatRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref OutpostPrivateSubnetRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGatewayZA

  OutpostPrivateSubnetS3Access:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref OutpostPrivateSubnetRouteTable
      DestinationCidrBlock: !Ref AmazonS3SubnetCIDR
      LocalGatewayId: 
        Ref: LocalGatewayId

# -----------------------------------------------------------------------------------
#  Outpost S3 endpoint, access point, and bucket
#
  # Security group for the S3 endpoint
  OutpostsEndpointsSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: Allow HTTPS traffic from the VPC
      VpcId: !Ref VPCEMRonOutposts
      SecurityGroupIngress:
        - Description: Allow inboud traffic inside the VPC on port 443
          IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !GetAtt VPCEMRonOutposts.CidrBlock
      SecurityGroupEgress:
        - Description: Allow outbound traffic inside the VPC
          IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: !GetAtt VPCEMRonOutposts.CidrBlock

  # S3 Outposts endpoint
  S3OutpostsEndpoint:
    Type: AWS::S3Outposts::Endpoint
    Properties:
      OutpostId: !Ref OutpostId
      SecurityGroupId: !Ref OutpostsEndpointsSecurityGroup
      SubnetId: !Ref OutpostPrivateSubnet
      AccessType: Private

  # S3 Bucket on Outposts
  S3OutpostsBucket:
    Type: AWS::S3Outposts::Bucket
    Properties:
      BucketName: !Sub 's3-outposts-bucket-outpostblog-${AWS::AccountId}'
      OutpostId: !Ref OutpostId

  # S3 on Outposts access point
  S3OutpostsAccessPoint:
    Type: AWS::S3Outposts::AccessPoint
    Properties:
      Bucket:
        Ref: S3OutpostsBucket
      Name: s3outpostsaccesspoint
      VpcConfiguration:
        VpcId: !Ref VPCEMRonOutposts
  
Outputs:
  StackVPC:
    Description: The VPC ID
    Value: !Ref VPCEMRonOutposts
    Export:
      Name: "VPCID"

  StackOutpostsPrivateSubnet:
    Description: The Outposts Private Subnet ID
    Value: !Ref OutpostPrivateSubnet
    Export:
      Name: "OutpostsPrivateSubnet"

  StackPrivateSubnet:
    Description: The Private Subnet ID
    Value: !Ref PublicSubnetAZA
    Export:
      Name: "PrivateSubnet"

  S3BucketNameInRegion:
    Description: The S3 Bucket name in the region
    Value: !Ref S3BucketBlogEMROnOutposts
    Export:
      Name: "S3BucketBlogEMROnOutposts"

  StackS3OutpostsAccessPoint:
    Description: S3 access point ARN on Outposts 
    Value: !Ref S3OutpostsAccessPoint
    Export:
      Name: "S3OutpostsAccessPoint"

  StackS3OutpostsBucket:
    Description: S3 on Outpost bucket name 
    Value: !Ref S3OutpostsBucket
    Export:
      Name: "S3OutpostsBucket"

  StackOutpostSubnetCIDR:
    Description: Outpost Subnet CIDR
    Value: !Ref OutpostSubnetCIDR
    Export:
      Name: "OutpostSubnetCIDR"

  StackAmazonS3SubnetCIDR:
    Description: Outpost Subnet CIDR
    Value: !Ref AmazonS3SubnetCIDR
    Export:
      Name: "AmazonS3SubnetCIDR"

  StackVPCEndpointSecurityGroup:
    Description: Security Group for VPC endpoints
    Value: !Ref OutpostsEndpointsSecurityGroup
    Export:
      Name: "VPCEndpointsSecurityGroup"
