{ "Resources": { "NATRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "ec2.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [{ "PolicyName": "NAT_Takeover", "PolicyDocument": { "Statement": [{ "Effect": "Allow", "Resource": "*", "Action": [ "ec2:DescribeInstances", "ec2:DescribeRouteTables", "ec2:CreateRoute", "ec2:ReplaceRoute", "ec2:StartInstances", "ec2:StopInstances" ] }] } }] } }, "NATRoleProfile": { "Type": "AWS::IAM::InstanceProfile", "Properties": { "Path": "/", "Roles": [{"Ref": "NATRole"}] } }, "BastionBoxSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Allow the application instances to access the NAT device", "VpcId" : { "Ref" : "VPC" }, "SecurityGroupIngress": [ {"IpProtocol": "-1", "CidrIp": "0.0.0.0/0"} ], "SecurityGroupEgress": [ {"IpProtocol": "-1", "CidrIp": "0.0.0.0/0"} ] } }, "BastionBoxReadyWaitHandle": {"Type": "AWS::CloudFormation::WaitConditionHandle", "Properties": {}}, "BastionBoxReady": {"Type": "AWS::CloudFormation::WaitCondition", "DependsOn": ["BastionBox"], "Properties": { "Handle": {"Ref": "BastionBoxReadyWaitHandle"}, "Count": "1", "Timeout": "1200" }}, "BastionBox" : { "Type" : "AWS::EC2::Instance", "Metadata": { "AWS::CloudFormation::Init": {} }, "Properties" : { "InstanceType": "m1.small", "ImageId": {"Ref": "InstanceAMIVar"}, "SourceDestCheck": "false", "NetworkInterfaces": [{ "DeviceIndex": "0", "AssociatePublicIpAddress": "true", "DeleteOnTermination": "true", "SubnetId": {"Ref": "PublicSubnet"}, "GroupSet" : [{"Ref" : "BastionBoxSecurityGroup"}] }], "IamInstanceProfile" : {"Ref": "NATRoleProfile"}, "KeyName": {"Ref": "IAMKeypairNameVar"}, "UserData": {"Fn::Base64": {"Fn::Join": ["", [ "#!/bin/bash\n", "export AWS_REGION='", {"Ref": "AWS::Region"}, "'\n", "export AWS_STACK_NAME='", {"Ref": "AWS::StackName"}, "'\n", "export AWS_INSTANCE_LOGICAL_NAME='BastionBox'\n", "export AWS_INSTANCE_WAIT_HANDLE='", {"Ref": "BastionBoxReadyWaitHandle"}, "'\n", "export VPN_DOMAIN='", {"Fn::FindInMap": ["StackZoneRecords", "VPN", "DNSName"]}, "'\n", "export NAT_PRIVATE_ROUTE_TABLE='", {"Ref": "PrivateRouteTable"}, "'\n", {"Ref": "UserDataEnvironmentVar"}, "\n", {"Ref": "CommonRoleScriptVar"}, "\n", {"Ref": "NATRoleScriptVar"}, "\n", {"Ref": "VPNRoleScriptVar"}, "\n" ]]}} } }, "BastionBoxIPAddress" : { "Type" : "AWS::EC2::EIP", "DependsOn" : "GatewayToInternet", "Properties" : { "Domain" : "vpc" } }, "BastionBoxIPAddressAttachment": { "Type": "AWS::EC2::EIPAssociation", "Properties": { "InstanceId": {"Ref": "BastionBox"}, "AllocationId": {"Fn::GetAtt": ["BastionBoxIPAddress", "AllocationId"]} } }, "VPNDNSRecord": { "Type": "AWS::Route53::RecordSet", "Properties": { "HostedZoneId" : { "Fn::FindInMap" : [ "StackZoneRecords", "VPN", "HostedZoneId" ]}, "Name" : { "Fn::FindInMap" : [ "StackZoneRecords", "VPN", "DNSName" ]}, "Type": "A", "TTL": "300", "ResourceRecords": [{"Ref": "BastionBoxIPAddress"}] } } } }