Skip to content

Instantly share code, notes, and snippets.

@Millward2000
Created August 31, 2022 14:14
Show Gist options
  • Save Millward2000/1f1dd1fcf9b1667df94b997eb483c809 to your computer and use it in GitHub Desktop.
Save Millward2000/1f1dd1fcf9b1667df94b997eb483c809 to your computer and use it in GitHub Desktop.
TGW with three VPCs and optional VPN using strongswan on EC2
Description: Base Template for TGW testing with three VPCs
Parameters:
AvailabilityZones:
Description: 'Lists of Availability Zones to use for the subnets in the VPC. Note: The logical order is preserved.'
Type: List<AWS::EC2::AvailabilityZone::Name>
createCgw:
Type: String
Description: If you want to create a CGW with an existing public IP address and attach it to the TGW, choose true
AllowedValues: ['True','False']
Default: 'False'
cgwPublicIp:
Type: String
Description: The public IP address of the customer side VPN Appliance. Not required if you do not want to create a Customer Gateway and attachment at this time
Default: '1.1.1.1'
cidrVpcA:
Type: String
Description: CIDR block for VPC-A
Default: '10.64.0.0/16'
cidrVpcB:
Type: String
Description: CIDR block for VPC-B
Default: '10.65.0.0/16'
cidrVpcC:
Type: String
Description: CIDR block for VPC-C
Default: '10.66.0.0/16'
cidrSubnetA:
Type: String
Description: CIDR block for Subnet-A
Default: '10.64.0.0/24'
cidrSubnetB:
Type: String
Description: CIDR block for Subnet-B
Default: '10.65.0.0/24'
cidrSubnetC:
Type: String
Description: CIDR block for Subnet-C
Default: '10.66.0.0/24'
keyName:
Description: The existing AWS Key that you would like to use
Type: AWS::EC2::KeyPair::KeyName
Default: eu-west-1
sgCidrSummary:
Type: String
Description: The summarised range of VPC Subnets that you would like to permit, ideally as a /14 assuming 3 /16 CIDR blocks and one for the on-premises network
Default: '10.64.0.0/14'
Mappings:
RegionMap:
eu-west-1:
ami: ami-0ffea00000f287d30
af-south-1:
ami: ami-050312a64b6fd7ad9
Conditions:
deployCgw: !Equals
- !Ref createCgw
- True
Resources:
myTransitGateway:
Type: "AWS::EC2::TransitGateway"
Properties:
AmazonSideAsn: 65000
Description: "TGW Route Integration Test"
AutoAcceptSharedAttachments: "disable"
DefaultRouteTableAssociation: "enable"
DnsSupport: "enable"
VpnEcmpSupport: "enable"
Tags:
- Key: Name
Value: TGW
myCustomerGateway:
Type: AWS::EC2::CustomerGateway
Condition: deployCgw
Properties:
Type: ipsec.1
BgpAsn: 65001
IpAddress: !Ref cgwPublicIp
myVPNConnection:
Type: AWS::EC2::VPNConnection
Condition: deployCgw
Properties:
Type: ipsec.1
StaticRoutesOnly: true
CustomerGatewayId:
!Ref myCustomerGateway
TransitGatewayId:
!Ref myTransitGateway
myVpcA:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref cidrVpcA
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: VPC-A
myVpcB:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref cidrVpcB
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: VPC-B
myVpcC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref cidrVpcC
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: VPC-C
mySubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref myVpcA
CidrBlock: !Ref cidrSubnetA
AvailabilityZone: !Select ['0', !Ref 'AvailabilityZones']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: Subnet-A
mySubnetB:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref myVpcB
CidrBlock: !Ref cidrSubnetB
AvailabilityZone: !Select ['0', !Ref 'AvailabilityZones']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: Subnet-B
mySubnetC:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref myVpcC
CidrBlock: !Ref cidrSubnetC
AvailabilityZone: !Select ['0', !Ref 'AvailabilityZones']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: Subnet-C
myIgA:
Type: 'AWS::EC2::InternetGateway'
myIgAttachA:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
InternetGatewayId: !Ref myIgA
VpcId: !Ref myVpcA
myRtA:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref myVpcA
myRouteA:
Type: 'AWS::EC2::Route'
Properties:
RouteTableId: !Ref myRtA
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref myIgA
mySrtaA:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref myRtA
SubnetId: !Ref mySubnetA
myIgB:
Type: 'AWS::EC2::InternetGateway'
myIgAttachB:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
InternetGatewayId: !Ref myIgB
VpcId: !Ref myVpcB
myRtB:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref myVpcB
myRouteB:
Type: 'AWS::EC2::Route'
Properties:
RouteTableId: !Ref myRtB
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref myIgB
mySrtaB:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref myRtB
SubnetId: !Ref mySubnetB
myIgC:
Type: 'AWS::EC2::InternetGateway'
myIgAttachC:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
InternetGatewayId: !Ref myIgC
VpcId: !Ref myVpcC
myRtC:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref myVpcC
myRouteC:
Type: 'AWS::EC2::Route'
Properties:
RouteTableId: !Ref myRtC
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref myIgC
mySrtaC:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref myRtC
SubnetId: !Ref mySubnetC
myEc2InstanceA:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", ami]
InstanceType: t3.micro
KeyName: !Ref keyName
SubnetId: !Ref mySubnetA
SecurityGroupIds:
- !Ref mySgA
mySgA:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: Security Group that Permits EC2 Instances B and C to connect
GroupName: SG-A
SecurityGroupIngress:
- CidrIp: !Ref sgCidrSummary
Description: IP Traffic from all Private CIDR Blocks
IpProtocol: '-1'
- CidrIp: 0.0.0.0/0
Description: Allow SSH Access on port 22 for Testing
FromPort: 22
IpProtocol: tcp
ToPort: 22
VpcId: !Ref myVpcA
myEc2InstanceB:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", ami]
InstanceType: t3.micro
KeyName: !Ref keyName
SubnetId: !Ref mySubnetB
SecurityGroupIds:
- !Ref mySgB
mySgB:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: Security Group that Permits EC2 Instances A and C to connect
GroupName: SG-B
SecurityGroupIngress:
- CidrIp: !Ref sgCidrSummary
Description: IP Traffic from all Private CIDR Blocks
IpProtocol: '-1'
- CidrIp: 0.0.0.0/0
Description: Allow SSH Access on port 22 for Testing
FromPort: 22
IpProtocol: tcp
ToPort: 22
VpcId: !Ref myVpcB
myEc2InstanceC:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", ami]
InstanceType: t3.micro
KeyName: !Ref keyName
SubnetId: !Ref mySubnetC
SecurityGroupIds:
- !Ref mySgC
mySgC:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: Security Group that Permits EC2 Instances A and B to connect
GroupName: SG-C
SecurityGroupIngress:
- CidrIp: !Ref sgCidrSummary
Description: IP Traffic from all Private CIDR Blocks
IpProtocol: '-1'
- CidrIp: 0.0.0.0/0
Description: Allow SSH Access on port 22 for Testing
FromPort: 22
IpProtocol: tcp
ToPort: 22
VpcId: !Ref myVpcC
Outputs:
aPublicIp:
Value: !GetAtt myEc2InstanceA.PublicIp
Description: Public IP address of Instance A
aPrivateIp:
Value: !GetAtt myEc2InstanceA.PrivateIp
Description: Private IP address of Instance A
bPublicIp:
Value: !GetAtt myEc2InstanceB.PublicIp
Description: Public IP address of Instance B
bPrivateIp:
Value: !GetAtt myEc2InstanceB.PrivateIp
Description: Private IP address of Instance B
cPublicIp:
Value: !GetAtt myEc2InstanceC.PublicIp
Description: Public IP address of Instance C
cPrivateIp:
Value: !GetAtt myEc2InstanceC.PrivateIp
Description: Private IP address of Instance C
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# Adapted from AWS Quick Start
AWSTemplateFormatVersion: '2010-09-09'
Description: strongSwan VPN Gateway as an EC2 Instance
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: System Classification
Parameters:
- pOrg
- pSystem
- pApp
- Label:
default: System Environment
Parameters:
- pEnvPurpose
- Label:
default: Authentication
Parameters:
- pAuthType
- pCertBucket
- pCgwCert
- pCgwPrivateKey
- pCgwPrivateKeyPassphraseSecretName
- pRootCaCert
- pSubordinateCaCert
- Label:
default: VPN Tunnel 1
Parameters:
- pTunnel1PskSecretName
- pTunnel1VgwCertDomainName
- pTunnel1VgwOutsideIpAddress
- pTunnel1CgwInsideIpAddress
- pTunnel1VgwInsideIpAddress
- pTunnel1VgwBgpAsn
- pTunnel1BgpNeighborIpAddress
- Label:
default: VPN Tunnel 2
Parameters:
- pTunnel2PskSecretName
- pTunnel2VgwCertDomainName
- pTunnel2VgwOutsideIpAddress
- pTunnel2CgwInsideIpAddress
- pTunnel2VgwInsideIpAddress
- pTunnel2VgwBgpAsn
- pTunnel2BgpNeighborIpAddress
- Label:
default: Local Network Configuration
Parameters:
- pVpcId
- pVpcCidr
- pSubnetId
- pUseElasticIp
- pEipAllocationId
- pLocalBgpAsn
- Label:
default: EC2
Parameters:
- pAmiId
- pInstanceType
ParameterLabels:
pOrg:
default: Organization Identifier
pSystem:
default: System Identifier
pApp:
default: Application Identifier
pEnvPurpose:
default: Environment Purpose
pAuthType:
default: "Authentication type: 'psk' - Pre-shared key or 'pubkey' - Certificate"
pCertBucket:
default: S3 Bucket Containing Certificates and Client Private Key
pCgwCert:
default: Customer Gateway Certificate (S3 key)
pCgwPrivateKey:
default: Customer Gateway Private Key (S3 key)
pCgwPrivateKeyPassphraseSecretName:
default: Name of secret in AWS Secrets Manager for Customer Gateway Private Key Passphrase
pRootCaCert:
default: Root CA Certificate (S3 key)
pSubordinateCaCert:
default: Subordinate CA Certificate (S3 key)
pTunnel1PskSecretName:
default: Name of secret in AWS Secrets Manager for VPN Tunnel 1 Pre-Shared Key
pTunnel1VgwCertDomainName:
default: VPN Tunnel 1 Virtual Private Gateway Domain Name - Certificate Authentication. e.g vpn-07..78.endpoint-0
pTunnel1VgwOutsideIpAddress:
default: VPN Tunnel 1 Virtual Private Gateway Outside IP Address
pTunnel1CgwInsideIpAddress:
default: VPN Tunnel 1 Customer Gateway Inside IP Address
pTunnel1VgwInsideIpAddress:
default: VPN Tunnel 1 Virtual Private Gateway Inside IP Address
pTunnel1VgwBgpAsn:
default: VPN Tunnel 1 Virtual Private Gateway BGP ASN
pTunnel1BgpNeighborIpAddress:
default: VPN Tunnel 1 BGP Neighbor IP Address
pTunnel2PskSecretName:
default: Name of secret in AWS Secrets Manager for VPN Tunnel 2 Pre-Shared Key
pTunnel2VgwCertDomainName:
default: VPN Tunnel 2 Virtual Private Gateway Domain Name - Certificate Authentication. e.g vpn-07..78.endpoint-1
pTunnel2VgwOutsideIpAddress:
default: VPN Tunnel 2 Virtual Private Gateway Outside IP Address
pTunnel2CgwInsideIpAddress:
default: VPN Tunnel 2 Customer Gateway Inside IP Address
pTunnel2VgwInsideIpAddress:
default: VPN Tunnel 2 Virtual Private Gateway Inside IP Address
pTunnel2VgwBgpAsn:
default: VPN Tunnel 2 Virtual Private Gateway BGP ASN
pTunnel2BgpNeighborIpAddress:
default: VPN Tunnel 2 BGP Neighbor IP Address
pUseElasticIp:
default: Use Elastic IP Address? (true/false)
pEipAllocationId:
default: Elastic IP Address Allocation ID
pLocalBgpAsn:
default: Local VPN Gateway's BGP ASN
pVpcId:
default: VPC ID
pVpcCidr:
default: VPC CIDR Block
pSubnetId:
default: Subnet ID for VPN Gateway
pInstanceType:
default: EC2 Instance Type
pAmiId:
default: EC2 AMI ID
Parameters:
pOrg:
Type: String
Description: Used to qualify resource names
Default: example
pSystem:
Type: String
Description: Used to qualify resource names
Default: infra
pApp:
Type: String
Description: Used to qualify resource names
Default: vpngw
pEnvPurpose:
Type: String
Description: Used to qualify resource names. 10 characters max.
AllowedPattern: '^[a-zA-Z0-9-_]{1,10}$'
Default: test
pAuthType:
Type: String
Description: "Authentication type: 'psk' - Pre-shared key or 'pubkey' - Certificate"
Default: psk
AllowedValues:
- psk
- pubkey
pCertBucket:
Description: S3 Bucket Containing Certificates and Customer Gateway Private Key. Required for certificate-based authentication.
Type: String
Default: ''
pCgwCert:
Description: Customer Gateway Certificate (S3 key). Required for certificate-based authentication.
Type: String
Default: ''
pCgwPrivateKey:
Description: Customer Gateway Private Key (S3 key). Required for certificate-based authentication.
Type: String
Default: ''
pCgwPrivateKeyPassphraseSecretName:
Description: Name of secret in AWS Secrets Manager for Customer Gateway Private Key Passphrase. Required for certificate-based authentication.
Type: String
Default: ''
pRootCaCert:
Description: Root CA Certificate (S3 key). Required for certificate-based authentication.
Type: String
Default: ''
pSubordinateCaCert:
Description: Subordinate CA Certificate (S3 key). Required for certificate-based authentication.
Type: String
Default: ''
pTunnel1PskSecretName:
Description: Name of secret in AWS Secrets Manager for VPN Tunnel 1 Pre-Shared Key. Required for PSK-based authentication.
Type: String
Default: ''
pTunnel1VgwCertDomainName:
Description: VPN Tunnel 1 Virtual Private Gateway Domain Name. Required for certificate-based authentication. e.g vpn-07..78.endpoint-1
Type: String
Default: ''
pTunnel1VgwOutsideIpAddress:
Description: VPN Tunnel 1 Virtual Private Gateway Outside IP Address
Type: String
pTunnel1CgwInsideIpAddress:
Description: VPN Tunnel 1 Customer Gateway Inside IP Address
Type: String
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]|3[0-8]))$
pTunnel1VgwInsideIpAddress:
Description: VPN Tunnel 1 Virtual Private Gateway Inside IP Address
Type: String
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]|3[0-8]))$
pTunnel1VgwBgpAsn:
Description: VPN Tunnel 1 Virtual Private Gateway BGP ASN
Type: Number
Default: 64512
pTunnel1BgpNeighborIpAddress:
Description: VPN Tunnel 1 BGP Neighbor IP Address
Type: String
pTunnel2PskSecretName:
Description: Name of secret in AWS Secrets Manager for VPN Tunnel 2 Pre-Shared Key. Required for PSK-based authentication.
Type: String
Default: ''
pTunnel2VgwCertDomainName:
Description: VPN Tunnel 2 Virtual Private Gateway Domain Name. Required for certificate-based authentication. e.g vpn-07..78.endpoint-1
Type: String
Default: ''
pTunnel2VgwOutsideIpAddress:
Description: VPN Tunnel 2 Virtual Private Gateway Outside IP Address
Type: String
pTunnel2CgwInsideIpAddress:
Description: VPN Tunnel 2 Customer Gateway Inside IP Address
Type: String
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]|3[0-8]))$
pTunnel2VgwInsideIpAddress:
Description: VPN Tunnel 2 Virtual Private Gateway Inside IP Address
Type: String
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]|3[0-8]))$
pTunnel2VgwBgpAsn:
Description: VPN Tunnel 2 Virtual Private Gateway BGP ASN
Type: Number
Default: 64512
pUseElasticIp:
Type: String
Description: Whether Elastic IP address is to be used.
Default: true
AllowedValues: [true, false]
pEipAllocationId:
Description: Elastic IP Address Allocation ID
Type: String
Default: ''
pLocalBgpAsn:
Description: Local VPN Gateway's BGP ASN
Type: Number
Default: 65000
pTunnel2BgpNeighborIpAddress:
Description: VPN Tunnel 2 BGP Neighbor IP Address
Type: String
pVpcId:
Description: VPC ID
Type: AWS::EC2::VPC::Id
pVpcCidr:
Description: VPC CIDR Block
Type: String
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]))$
pSubnetId:
Description: Subnet ID for VPN Gateway
Type: AWS::EC2::Subnet::Id
pInstanceType:
Description: EC2 Instance Type
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small
- t3.medium
ConstraintDescription: must be a valid EC2 instance type.
pAmiId:
Description: EC2 AMI ID
Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-ebs'
Rules:
SubnetsInVPC:
Assertions:
- Assert:
'Fn::EachMemberIn':
- 'Fn::ValueOfAll':
- 'AWS::EC2::Subnet::Id'
- VpcId
- 'Fn::RefAll': 'AWS::EC2::VPC::Id'
AssertDescription: All subnets must in the VPC
Conditions:
cUseCertAuth: !Equals [ !Ref 'pAuthType', 'pubkey' ]
cUsePskAuth: !Equals [ !Ref 'pAuthType', 'psk' ]
cUseElasticIp: !Equals [ !Ref 'pUseElasticIp', true ]
Resources:
rInstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub '${pSystem}-${pApp}-ec2-${pEnvPurpose}'
VpcId: !Ref pVpcId
GroupDescription: Allow traffic from other VPN gateway and all locally sourced traffic
SecurityGroupIngress:
- IpProtocol: udp
FromPort: 500
ToPort: 500
CidrIp: !Sub '${pTunnel1VgwOutsideIpAddress}/32'
- IpProtocol: udp
FromPort: 500
ToPort: 500
CidrIp: !Sub '${pTunnel2VgwOutsideIpAddress}/32'
- IpProtocol: udp
FromPort: 4500
ToPort: 4500
CidrIp: !Sub '${pTunnel1VgwOutsideIpAddress}/32'
- IpProtocol: udp
FromPort: 4500
ToPort: 4500
CidrIp: !Sub '${pTunnel2VgwOutsideIpAddress}/32'
- IpProtocol: '50'
CidrIp: !Sub '${pTunnel1VgwOutsideIpAddress}/32'
- IpProtocol: '50'
CidrIp: !Sub '${pTunnel2VgwOutsideIpAddress}/32'
- IpProtocol: '51'
CidrIp: !Sub '${pTunnel1VgwOutsideIpAddress}/32'
- IpProtocol: '51'
CidrIp: !Sub '${pTunnel2VgwOutsideIpAddress}/32'
- IpProtocol: '-1'
FromPort: 0
ToPort: 65535
CidrIp: !Ref pVpcCidr
rLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Sub '${pSystem}-${pApp}-${pEnvPurpose}'
LaunchTemplateData:
InstanceType: !Ref pInstanceType
ImageId: !Ref pAmiId
IamInstanceProfile:
Arn: !GetAtt rInstanceProfile.Arn
NetworkInterfaces:
- DeviceIndex: 0
DeleteOnTermination: true
Description: !Sub '${pSystem}-${pApp}-${pEnvPurpose}'
Groups:
- !Ref rInstanceSecurityGroup
AssociatePublicIpAddress: !Ref pUseElasticIp
UserData:
Fn::Base64: !Sub |
#!/bin/bash -x
yum install -y amazon-cloudwatch-agent
/opt/aws/bin/cfn-init \
--verbose \
--stack ${AWS::StackName} \
--resource rLaunchTemplate \
--configsets ${pAuthType} \
--region ${AWS::Region}
/opt/aws/bin/cfn-signal \
--exit-code $? \
'${rVpnGatewayWaitHandle}'
Metadata:
AWS::CloudFormation::Authentication:
S3BucketAccessCredential:
type: "S3"
roleName: !Ref rRole
AWS::CloudFormation::Init:
configSets:
psk:
- 01-config-cloudwatch-agent
- 02-restart-cloudwatch-agent
- 03-install-epel
- 04-config-vpn-gateway-config
- 05-config-vpn-gateway-secrets-psk
- 06-config-vpn-gateway-commands
pubkey:
- 01-config-cloudwatch-agent
- 02-restart-cloudwatch-agent
- 03-install-epel
- 04-config-vpn-gateway-config
- 05-config-vpn-gateway-cert-files
- 06-config-vpn-gateway-commands
01-config-cloudwatch-agent:
files:
/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json:
content: !Sub |
{
"metrics": {
"metrics_collected": {
"cpu": {
"resources": [
"*"
],
"measurement": [
"usage_idle",
"usage_nice",
"usage_guest"
],
"totalcpu": false,
"metrics_collection_interval": 10
},
"mem": {
"measurement": [
"total",
"used",
"used_percent"
]
},
"swap": {
"measurement": [
"free",
"used",
"used_percent"
]
},
"netstat": {
"measurement": [
"tcp_established",
"tcp_syn_sent",
"tcp_close"
],
"metrics_collection_interval": 60
},
"disk": {
"measurement": [
"total",
"free",
"used",
"used_percent"
],
"resources": [
"*"
],
"drop_device": true
},
"processes": {
"measurement": [
"running",
"sleeping",
"dead"
]
}
},
"append_dimensions": {
"ImageId": "${!aws:ImageId}",
"InstanceId": "${!aws:InstanceId}",
"InstanceType": "${!aws:InstanceType}"
},
"aggregation_dimensions" : [["InstanceId", "InstanceType"],[]]
},
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log",
"log_group_name": "amazon-cloudwatch-agent.log",
"log_stream_name": "amazon-cloudwatch-agent.log",
"timezone": "UTC"
},
{
"file_path": "/var/log/cloud-init.log",
"log_group_name": "${rCloudWatchLogsAgentGroup}",
"log_stream_name": "{instance_id}/cloud-init.log",
"timezone": "UTC"
},
{
"file_path": "/var/log/cloud-init-output.log",
"log_group_name": "${rCloudWatchLogsAgentGroup}",
"log_stream_name": "{instance_id}/cloud-init-output.log",
"timezone": "UTC"
},
{
"file_path": "/var/log/cfn-init.log",
"log_group_name": "${rCloudWatchLogsAgentGroup}",
"log_stream_name": "{instance_id}/cfn-init.log",
"timezone": "UTC"
},
{
"file_path": "/var/log/cfn-wire.log",
"log_group_name": "${rCloudWatchLogsAgentGroup}",
"log_stream_name": "{instance_id}/cfn-wire.log",
"timezone": "UTC"
},
{
"file_path": "/var/log/charon.log",
"log_group_name": "${rCloudWatchLogsAgentGroup}",
"log_stream_name": "{instance_id}/charon.log",
"timezone": "UTC"
},
{
"file_path": "/var/log/quagga/zebra.log",
"log_group_name": "${rCloudWatchLogsAgentGroup}",
"log_stream_name": "{instance_id}/zebra.log",
"timezone": "UTC"
},
{
"file_path": "/var/log/quagga/bgpd.log",
"log_group_name": "${rCloudWatchLogsAgentGroup}",
"log_stream_name": "{instance_id}/bgpd.log",
"timezone": "UTC"
}
]
}
},
"log_stream_name": "${rCloudWatchLogsAgentGroup}",
"force_flush_interval" : 15
}
}
mode: '000444'
owner: root
group: root
02-restart-cloudwatch-agent:
commands:
01-stop-service:
command: /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a stop
02-start-service:
command: /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s
03-install-epel:
commands:
01-install-epel:
command: amazon-linux-extras install epel -y
04-config-vpn-gateway-config:
packages:
yum:
strongswan: []
ntp: []
quagga: []
jq: []
files:
/etc/strongswan/strongswan.conf:
content: |
# strongswan.conf - strongSwan configuration file
#
# Refer to the strongswan.conf(5) manpage for details
#
# Configuration changes should be made in the included files
charon {
plugins {
include strongswan.d/charon/*.conf
}
load_modular = yes
filelog {
charon {
path = /var/log/charon.log
time_format = %b %e %T
ike_name = yes
append = yes
}
}
}
mode: '000600'
owner: root
group: root
/etc/strongswan/ipsec.conf:
content: !Join
- ''
-
- !Sub |
conn %default
leftauth=${pAuthType}
rightauth=${pAuthType}
ike=aes256-sha256-modp2048s256,aes128-sha1-modp1024!
ikelifetime=28800s
aggressive=no
esp=aes128-sha256-modp2048s256,aes128-sha1-modp1024!
lifetime=3600s
type=tunnel
dpddelay=10s
dpdtimeout=30s
keyexchange=ikev1
rekey=yes
reauth=no
dpdaction=restart
closeaction=restart
left=%defaultroute
leftsubnet=0.0.0.0/0,::/0
rightsubnet=0.0.0.0/0,::/0
leftupdown=/etc/strongswan/ipsec-vti.sh
installpolicy=yes
compress=no
mobike=no
conn AWS-VPC-TUNNEL-1
left=%any
right=${pTunnel1VgwOutsideIpAddress}
auto=start
mark=100
- !If
- cUseCertAuth
- !Sub |2
leftcert=client-public-cert.pem
rightid="CN=${pTunnel1VgwCertDomainName}"
- ''
- !Sub |
conn AWS-VPC-TUNNEL-2
left=%any
right=${pTunnel2VgwOutsideIpAddress}
auto=start
mark=200
- !If
- cUseCertAuth
- !Sub |2
leftcert=client-public-cert.pem
rightid="CN=${pTunnel2VgwCertDomainName}"
- ''
mode: '000600'
owner: root
group: root
/etc/strongswan/ipsec-vti.sh:
content: !Sub |
#!/bin/bash
#@ /etc/strongswan/ipsec-vti.sh (Centos) or /etc/strongswan.d/ipsec-vti.sh (Ubuntu)
# AWS VPC Hardware VPN Strongswan updown Script
# Usage Instructions:
# Add "install_routes = no" to /etc/strongswan/strongswan.d/charon.conf or /etc/strongswan.d/charon.conf
# Add "install_virtual_ip = no" to /etc/strongswan/strongswan.d/charon.conf or /etc/strongswan.d/charon.conf
# For Ubuntu: Add "leftupdown=/etc/strongswan.d/ipsec-vti.sh" to /etc/ipsec.conf
# For RHEL/Centos: Add "leftupdown=/etc/strongswan/ipsec-vti.sh" to /etc/strongswan/ipsec.conf
# For RHEL/Centos 6 and below: git clone git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git && cd iproute2 && make && cp ./ip/ip /usr/local/sbin/ip
# Adjust the below according to the Generic Gateway Configuration file provided to you by AWS.
# Sample: http://docs.aws.amazon.com/AmazonVPC/latest/NetworkAdminGuide/GenericConfig.html
IP=$(which ip)
IPTABLES=$(which iptables)
PLUTO_MARK_OUT_ARR=(${!PLUTO_MARK_OUT//// })
PLUTO_MARK_IN_ARR=(${!PLUTO_MARK_IN//// })
case "$PLUTO_CONNECTION" in
AWS-VPC-TUNNEL-1)
VTI_INTERFACE=vti1
VTI_LOCALADDR=${pTunnel1CgwInsideIpAddress}
VTI_REMOTEADDR=${pTunnel1VgwInsideIpAddress}
;;
AWS-VPC-TUNNEL-2)
VTI_INTERFACE=vti2
VTI_LOCALADDR=${pTunnel2CgwInsideIpAddress}
VTI_REMOTEADDR=${pTunnel2VgwInsideIpAddress}
;;
esac
case "${!PLUTO_VERB}" in
up-client)
#$IP tunnel add ${!VTI_INTERFACE} mode vti local ${!PLUTO_ME} remote ${!PLUTO_PEER} okey ${!PLUTO_MARK_OUT_ARR[0]} ikey ${!PLUTO_MARK_IN_ARR[0]}
$IP link add ${!VTI_INTERFACE} type vti local ${!PLUTO_ME} remote ${!PLUTO_PEER} okey ${!PLUTO_MARK_OUT_ARR[0]} ikey ${!PLUTO_MARK_IN_ARR[0]}
sysctl -w net.ipv4.conf.${!VTI_INTERFACE}.disable_policy=1
sysctl -w net.ipv4.conf.${!VTI_INTERFACE}.rp_filter=2 || sysctl -w net.ipv4.conf.${!VTI_INTERFACE}.rp_filter=0
$IP addr add ${!VTI_LOCALADDR} remote ${!VTI_REMOTEADDR} dev ${!VTI_INTERFACE}
$IP link set ${!VTI_INTERFACE} up mtu 1436
$IPTABLES -t mangle -I FORWARD -o ${!VTI_INTERFACE} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
$IPTABLES -t mangle -I INPUT -p esp -s ${!PLUTO_PEER} -d ${!PLUTO_ME} -j MARK --set-xmark ${!PLUTO_MARK_IN}
$IP route flush table 220
#/etc/init.d/bgpd reload || /etc/init.d/quagga force-reload bgpd
;;
down-client)
#$IP tunnel del ${!VTI_INTERFACE}
$IP link del ${!VTI_INTERFACE}
$IPTABLES -t mangle -D FORWARD -o ${!VTI_INTERFACE} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
$IPTABLES -t mangle -D INPUT -p esp -s ${!PLUTO_PEER} -d ${!PLUTO_ME} -j MARK --set-xmark ${!PLUTO_MARK_IN}
;;
esac
mode: '000700'
owner: root
group: root
/etc/quagga/zebra.conf:
content: |
hostname {HOSTNAME}
password zebra
enable password zebra
!
log file /var/log/quagga/zebra.log
!
! Configure interfaces
interface lo
! Change preferred source ip address of received routes
route-map RM_SET_SRC permit 10
set src {PRIVATE_IP}
ip protocol bgp route-map RM_SET_SRC
!
line vty
mode: '000600'
owner: quagga
group: quagga
/etc/quagga/bgpd.conf:
content: !Sub |
hostname bgpd
password zebra
enable password zebra
!
log file /var/log/quagga/bgpd.log
!
debug bgp events
debug bgp filters
debug bgp fsm
debug bgp keepalives
debug bgp updates
!
router bgp ${pLocalBgpAsn}
bgp router-id {PRIVATE_IP}
network ${pVpcCidr}
neighbor ${pTunnel1BgpNeighborIpAddress} remote-as ${pTunnel1VgwBgpAsn}
neighbor ${pTunnel2BgpNeighborIpAddress} remote-as ${pTunnel2VgwBgpAsn}
neighbor ${pTunnel2BgpNeighborIpAddress} route-map RM_LOWER_PRIORITY out
!
route-map RM_LOWER_PRIORITY permit 10
set as-path prepend ${pLocalBgpAsn} ${pLocalBgpAsn} ${pLocalBgpAsn}
!
line vty
mode: '000600'
owner: quagga
group: quagga
/etc/sysctl.conf:
content: |
# sysctl settings are defined through files in
# /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/.
#
# Vendors settings live in /usr/lib/sysctl.d/.
# To override a whole file, create a new file with the same in
# /etc/sysctl.d/ and put new settings there. To override
# only specific settings, add a file with a lexically later
# name in /etc/sysctl.d/ and put new settings there.
#
# For more information, see sysctl.conf(5) and sysctl.d(5).
net.ipv4.ip_forward = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_max_syn_backlog = 1280
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_mtu_probing = 1
mode: '000600'
owner: root
group: root
05-config-vpn-gateway-secrets-psk:
files:
/etc/strongswan/ipsec.secrets:
content: !Sub |
${pTunnel1VgwOutsideIpAddress} : PSK "{TUNNEL_1_PSK}"
${pTunnel2VgwOutsideIpAddress} : PSK "{TUNNEL_2_PSK}"
mode: '000600'
owner: root
group: root
/tmp/set-psk.sh:
content: !Sub |
#!/bin/bash
for (( i=0; i<2; ++i)); do
TUNNEL_NUM=$((${!i} + 1))
if (( $TUNNEL_NUM == 1 )) ; then
SECRET_NAME=${pTunnel1PskSecretName}
else
SECRET_NAME=${pTunnel2PskSecretName}
fi
PSK=$(aws secretsmanager get-secret-value --secret-id ${!SECRET_NAME} --region ${AWS::Region} | jq -r '.SecretString' | jq -r '.psk') &&
if test -z "$PSK"
then
echo "\$PSK is empty"
exit 1
else
echo "\$PSK is NOT empty"
sed -i -e "s/{TUNNEL_${!TUNNEL_NUM}_PSK}/${!PSK}/" /etc/strongswan/ipsec.secrets
fi
done
mode: '000700'
owner: root
group: root
commands:
00-set-psk:
command: >-
/tmp/set-psk.sh
05-config-vpn-gateway-cert-files:
files:
/etc/strongswan/ipsec.d/cacerts/root-ca.pem:
source: !Sub "https://${pCertBucket}.s3.${AWS::Region}.amazonaws.com/${pRootCaCert}"
mode: '000600'
owner: root
group: root
authentication: "S3BucketAccessCredential"
/etc/strongswan/ipsec.d/cacerts/subordinate-ca.pem:
source: !Sub "https://${pCertBucket}.s3.${AWS::Region}.amazonaws.com/${pSubordinateCaCert}"
mode: '000600'
owner: root
group: root
authentication: "S3BucketAccessCredential"
/etc/strongswan/ipsec.d/certs/client-public-cert.pem:
source: !Sub "https://${pCertBucket}.s3.${AWS::Region}.amazonaws.com/${pCgwCert}"
mode: '000600'
owner: root
group: root
authentication: "S3BucketAccessCredential"
/etc/strongswan/ipsec.d/private/client-private-key.pem:
source: !Sub "https://${pCertBucket}.s3.${AWS::Region}.amazonaws.com/${pCgwPrivateKey}"
mode: '000600'
owner: root
group: root
authentication: "S3BucketAccessCredential"
/etc/strongswan/ipsec.secrets:
content: |
: RSA client-private-key.pem {PASSPHRASE}
mode: '000600'
owner: root
group: root
/tmp/set-passphrase.sh:
content: !Sub |
#!/bin/bash
PASSPHRASE=$(aws secretsmanager get-secret-value --secret-id ${pCgwPrivateKeyPassphraseSecretName} --region ${AWS::Region} | jq -r '.SecretString' | jq -r '.passphrase') &&
if test -z "$PASSPHRASE"
then
echo "\$PASSPHRASE is empty"
exit 1
else
echo "\$PASSPHRASE is NOT empty"
sed -i -e "s/{PASSPHRASE}/${!PASSPHRASE}/" /etc/strongswan/ipsec.secrets
fi
mode: '000700'
owner: root
group: root
commands:
00-set-private-key-passphrase:
command: >-
/tmp/set-passphrase.sh
06-config-vpn-gateway-commands:
commands:
00-sed-instance-specific-settings:
command: >-
ipaddr=$(curl 169.254.169.254/latest/meta-data/local-ipv4) &&
sed -i -e "s/{PRIVATE_IP}/${ipaddr}/" /etc/quagga/zebra.conf &&
sed -i -e "s/{PRIVATE_IP}/${ipaddr}/" /etc/quagga/bgpd.conf &&
hostname=$(curl 169.254.169.254/latest/meta-data/local-hostname) &&
sed -i -e "s/{HOSTNAME}/${hostname}/" /etc/quagga/zebra.conf
01-load-sysctl-changes:
command: sysctl -p /etc/sysctl.conf
02-enable-ip-forwarding:
command: >-
sysctl -w net.ipv4.ip_forward=1 &&
sysctl -w net.ipv4.conf.eth0.disable_xfrm=1 &&
sysctl -w net.ipv4.conf.eth0.disable_policy=1
03-enable-start-ntpd:
command: >-
systemctl enable ntpd &&
systemctl start ntpd
04-enable-start-strongswan:
command: >-
systemctl enable strongswan &&
systemctl start strongswan
05-enable-start-zebra:
command: >-
systemctl enable zebra &&
systemctl start zebra
06-enable-start-bgpd:
command: >-
systemctl enable bgpd &&
systemctl start bgpd
rVpnGatewayEipAssociation:
Type: AWS::EC2::EIPAssociation
Condition: cUseElasticIp
Properties:
AllocationId: !Ref pEipAllocationId
InstanceId: !Ref rVpnGateway
rVpnGateway:
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId:
Ref: rLaunchTemplate
Version:
Fn::GetAtt:
[ rLaunchTemplate, LatestVersionNumber ]
NetworkInterfaces:
- DeviceIndex: '0'
SubnetId: !Ref pSubnetId
SourceDestCheck: false
Tags:
- Key: Name
Value: !Sub '${pSystem}-${pApp}-${pEnvPurpose}'
rVpnGatewayWaitHandle:
Type: AWS::CloudFormation::WaitConditionHandle
rVpnGatewayWaitCondition1:
Type: AWS::CloudFormation::WaitCondition
DependsOn: rVpnGateway
Properties:
Handle:
Ref: rVpnGatewayWaitHandle
Timeout: '300'
Count: 1
rRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${pOrg}-${pSystem}-${pApp}-${pEnvPurpose}-svc-cloud-watch-ssm'
Path: !Sub '/${pOrg}/${pSystem}/${pApp}/'
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
-
Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
rPolicyS3:
Type: AWS::IAM::Policy
Condition: cUseCertAuth
Properties:
PolicyName: !Sub '${pOrg}-${pSystem}-${pApp}-${pEnvPurpose}-s3-read-only'
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- s3:GetObject
Resource: !Sub 'arn:aws:s3:::${pCertBucket}/*'
Roles:
- !Ref rRole
rPolicySecretsManagerCertAuth:
Type: AWS::IAM::Policy
Condition: cUseCertAuth
Properties:
PolicyName: !Sub '${pOrg}-${pSystem}-${pApp}-${pEnvPurpose}-secrets-manager-read-only'
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
- secretsmanager:DescribeSecret
Resource: !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${pCgwPrivateKeyPassphraseSecretName}-*'
Roles:
- !Ref rRole
rPolicySecretsManagerPskAuth:
Type: AWS::IAM::Policy
Condition: cUsePskAuth
Properties:
PolicyName: !Sub '${pOrg}-${pSystem}-${pApp}-${pEnvPurpose}-secrets-manager-read-only'
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
- secretsmanager:DescribeSecret
Resource:
- !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${pTunnel1PskSecretName}-*'
- !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${pTunnel2PskSecretName}-*'
Roles:
- !Ref rRole
rInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: !Sub '${pSystem}-${pApp}-${pEnvPurpose}'
Path: !Sub '/${pOrg}/${pSystem}/${pApp}/'
Roles:
- !Ref rRole
rCloudWatchLogsAgentGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub '/${pSystem}/${pApp}/ec2/${pEnvPurpose}'
RetentionInDays: 30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment