# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 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 Type Parameters: - pAuthType - Label: default: Common Parameters for Certificate-Based Authentication Parameters: - 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: t3a.micro AllowedValues: - t3a.micro - t3a.small - t3a.medium ConstraintDescription: must be a valid EC2 instance type. pAmiId: Description: EC2 AMI ID Type: 'AWS::SSM::Parameter::Value' 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: [] 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-strongswan: command: >- systemctl enable strongswan && systemctl start strongswan 04-enable-start-zebra: command: >- systemctl enable zebra && systemctl start zebra 05-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: '600' Count: 1 rRole: Type: AWS::IAM::Role Properties: RoleName: !Sub '${pOrg}-${pSystem}-${pApp}-${pEnvPurpose}-${AWS::Region}-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}-${AWS::Region}' Path: !Sub '/${pOrg}/${pSystem}/${pApp}/' Roles: - !Ref rRole rCloudWatchLogsAgentGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub '/${pSystem}/${pApp}/ec2/${pEnvPurpose}' RetentionInDays: 30