├── .github └── workflows │ └── main.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── images ├── cert-based-authentication-aws-environment.png ├── cert-based-authentication-simulated-on-premises-environment.png ├── cert-based-authentication.drawio ├── featured-image.pptx ├── site-to-site-vpn-console-config-tgw.png ├── site-to-site-vpn-console-config-tunnel-status.png ├── site-to-site-vpn-console-config-vpc-routes.png ├── site-to-site-vpn-scenarios-diy.png ├── site-to-site-vpn-scenarios-end-to-end test.png ├── site-to-site-vpn-scenarios-tgw.png ├── site-to-site-vpn-scenarios-vgw.png ├── site-to-site-vpn-scenarios-vpn-config-screenshots-cgw-asn.png ├── site-to-site-vpn-scenarios-vpn-config-screenshots-inside-cgw.png ├── site-to-site-vpn-scenarios-vpn-config-screenshots-inside-vgw.png ├── site-to-site-vpn-scenarios-vpn-config-screenshots-neighbor-ip.png ├── site-to-site-vpn-scenarios-vpn-config-screenshots-outside-vgw.png ├── site-to-site-vpn-scenarios-vpn-config-screenshots-psk.png ├── site-to-site-vpn-scenarios-vpn-config-screenshots-vgw-asn.png └── site-to-site-vpn-scenarios.drawio ├── manage-stack ├── template-parameters-certificate-auth.json ├── template-parameters-psk-auth.json └── vpn-gateway-strongswan.yml /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Lint CloudFormation Templates 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | cloudformation-linter: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | 18 | - name: cfn-lint 19 | uses: scottbrenner/cfn-lint-action@master 20 | with: 21 | args: "**/*.yml" 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VPN Gateway Stack Using strongSwan 2 | 3 | An [AWS CloudFormation](https://aws.amazon.com/cloudformation/) template that can be used to automate deployment of the open source [strongSwan VPN solution](https://www.strongswan.org/) as a VPN gateway in support of several different [site-to-site VPN](https://docs.aws.amazon.com/vpn/latest/s2svpn/VPC_VPN.html) topologies. The open source [Quagga](https://en.wikipedia.org/wiki/Quagga_(software) ) software suite complements the role of strongSwan by providing [Border Gateway Protocol (BGP)](https://searchnetworking.techtarget.com/definition/BGP-Border-Gateway-Protocol) support to automatically propagate routing information across site-to-site VPN connections. 4 | 5 | Even if you don’t have a need to demonstrate integration with AWS site-to-site VPN capabilities, you might find value in reviewing the Infrastructure as Code (IaC) techniques demonstrated by the example AWS CloudFormation template including its built-in integrations with other AWS services to support logging, resource monitoring, and secure remote terminal access. 6 | 7 | * [Use Cases and Topologies](#use-cases-and-topologies) 8 | * [Integration with AWS Services](#cloudformation-features-demonstrated) 9 | * [Usage](#usage) 10 | * [CloudFormation Template Parameters](#cloudformation-template-parameters) 11 | * [Troubleshooting](#troubleshooting) 12 | * [Inspecting the strongSwan VPN Gateway EC2 Instance](#inspecting-the-strongswan-vpn-gateway-ec2-instance) 13 | * [Advanced Usage](#advanced-usage) 14 | * [Contributing](#contributing) 15 | * [License](#license) 16 | 17 | ## Use Cases and Topologies 18 | 19 | The example template can be useful for experimenting, testing, and demonstrating integration scenarios with the AWS Site-to-Site VPN feature and more formally implementing site-to-site VPN connections where use of managed AWS VPN services might not apply. 20 | 21 | ### Demonstration and Lab Environments 22 | 23 | When you don’t have ready access to either real on-premises VPN hardware or software appliances, this example can be useful in demonstrating how to integrate an on-premises network with AWS networks via AWS site-to-site VPN connections and either AWS Virtual Private Gateways (VGWs) or AWS Transit Gateways (TGWs). 24 | 25 | **Site-to-Site VPN with AWS Transit Gateway** 26 | 27 | See [Transit Gateway Example: Centralized Router](https://docs.aws.amazon.com/vpc/latest/tgw/transit-gateway-centralized-router.html) for an overview of this topology. 28 | 29 | In the following diagram, an EC2 instance deployed to a VPC that is emulating a customer’s on-premises network is running the strongSwan VPN stack and is acting as a VPN Customer Gateway in a site-to-site VPN configuration with an AWS Transit Gateway on the other end of the connection. 30 | 31 | Site-to-Site VPN with AWS Transit Gateway 32 | 33 | **Site-to-Site VPN with AWS Virtual Private Gateway** 34 | 35 | See [AWS Site-to-Site VPN](https://docs.aws.amazon.com/vpn/latest/s2svpn/SetUpVPNConnections.html) for details on this configuration. 36 | 37 | In the following diagram, an EC2 instance deployed to a VPC that is emulating a customer’s on-premises network is running the strongSwan VPN stack and is acting as a VPN Customer Gateway in a site-to-site VPN configuration with an AWS Virtual Private Gateway (VGW) on the other end of the connection. 38 | 39 | Site-to-Site VPN with AWS Transit Gateway 40 | 41 | ### Both Ends of a DIY Site-to-Site VPN Connection 42 | 43 | The example template can also be used to establish a VPN Gateway on both ends of a site-to-site VPN connection in scenarios where VGWs and TGWs are not applicable. Normally, you would use either VPC Peering or AWS Transit Gateway when you control the environments on both ends of a site-to-site VPN connection, but there may be circumstances in which you want to manage the VPN gateway on both ends. 44 | 45 | Site-to-Site VPN with AWS Transit Gateway 46 | 47 | ## Integration with AWS Services 48 | 49 | The example AWS CloudFormation template automatically builds a stack that demonstrates use of the following AWS services, features, and best practices: 50 | 51 | * AWS CloudFormation features including the [`AWS::CloudFormation::Init`](https://docs.aws.amazon.com/en_pv/AWSCloudFormation/latest/UserGuide/aws-resource-init.html) feature to completely automate the build out of the VPN gateway stack and BGP support upon first boot and the [`AWS::CloudFormation::WaitCondition`](https://docs.aws.amazon.com/en_pv/AWSCloudFormation/latest/UserGuide/aws-properties-waitcondition.html) feature to force the stack creation process to wait until the first boot build out is complete. 52 | 53 | * [Amazon EC2](https://aws.amazon.com/ec2/) provides the compute platform in which to deploy the strongSwan VPN gateway. 54 | 55 | * [Amazon CloudWatch Logs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html) integration via the [CloudWatch Logs Agent](https://docs.aws.amazon.com/en_pv/AmazonCloudWatch/latest/logs/CWL_GettingStarted.html) in which OS, VPN gateway, and BGP log files are written to a series of log streams in a CloudWatch Logs log group. 56 | 57 | * [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) integration for [monitoring EC2 memory and disk metrics](https://docs.aws.amazon.com/en_pv/AWSEC2/latest/UserGuide/mon-scripts.html). 58 | 59 | * [AWS Systems Manager Session Manager](https://docs.aws.amazon.com/en_pv/systems-manager/latest/userguide/session-manager.html) to enable secure terminal access to the OS instance without the need to establish Internet accessible bastion hosts and port 22 access to the VPN gateway. 60 | 61 | * [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) to support secure storage and retrieval of secrets used when authenticating your site-to-site VPN connection. The tunnel-specific private shared key (PSK) values for PSK-based authentication and the private key passphrase for certificate-based authentication are retrieved from AWS Secrets Manager. 62 | 63 | * [Systems Manager Parameter Store](https://aws.amazon.com/blogs/compute/query-for-the-latest-amazon-linux-ami-ids-using-aws-systems-manager-parameter-store/) to query for latest Amazon Linux 2 Amazon Machine Image (AMI) images. 64 | 65 | * Standardized naming of cloud resources to help distinguish from other resources, identify ownership, and potentially aid in access control. 66 | 67 | ## Usage 68 | 69 | The following instructions are primarily oriented toward the first use case and two deployment topologies described above: Site-to-Site VPN with AWS Transit Gateway and Site-to-Site VPN with Virtual Private Gateway. If you're interested in demonstrating a DIY solution for both ends of a site-to-site VPN connection, you should be able to easily extend these instructions. 70 | 71 | ### 1. Determine authentication approach 72 | 73 | This template supports pre-shared key- and certificate-based authentication. 74 | 75 | ### 1a. Pre-Shared Key-Based Authentication 76 | 77 | You'll obtain the the pre-shared keys (PSKs) for the two tunnels after you've configured the site-to-site VPN connection. 78 | 79 | You’ll need to create two secrets in AWS Secrets Manager in your simulated on-premises environment to store the PSKs so that your VPN gateway can retrieve them upon first boot when the strongSwan stack is configured. 80 | 81 | ### 1b. Certificate-Based Authentication 82 | 83 | The following diagram represents the private CAs and the customer gateway private certificate that you’ll need to create in your AWS environment. It also shows the tunnel-specific private certificates that will be automatically generated when you configure the site-to-site VPN connection. 84 | 85 | Certificate and key data required 86 | 87 | #### Create private certificate authorities (CAs) 88 | When using certificate-based authentication, you’ll need to use the AWS Certificate Manager private CA feature to create root and subordinate private CAs. The root CA is used to sign the subordinate CA while the subordinate CA is used to sign private certificates used to support your site-to-site VPN connections. 89 | 90 | #### Create customer gateway private certificate 91 | Once you’ve created the necessary CAs, you’ll use AWS Certificate Manager to create a private certificate to represent your customer gateway and to be used to authenticate your on-premises VPN gateway when it initiates the VPN connection. 92 | 93 | The customer gateway private certificate is signed by the subordinate CA. 94 | 95 | When you configure a customer gateway in your AWS environment, you’ll specify certificate-based authentication and associate your customer gateway private certificate with the customer gateway. 96 | 97 | Later, when your VPN connection and tunnels are established, this association helps to ensure that only a customer gateway that has this customer gateway private certificate can connect to your AWS environment. 98 | 99 | #### Export certificates and customer gateway private key 100 | Once you’ve created the private CAs and the customer gateway private certificate, you’ll need to save copies of the associated certificates to your desktop copies. 101 | 102 | The certificates are needed in your simulated on-premises environment so that the strongSwan VPN tool can validate the authenticity of both the customer gateway private certificate and tunnel-specific private certificates that are sent to the client when the VPN connection is established. 103 | 104 | You’ll also need to save a copy of customer gateway private key so that the strongSwan VPN tool can decrypt the content of the customer gateway private key. 105 | 106 | Since the customer gateway private key is sensitive data, you’ll need to specify a passphrase to be used to encrypt the private key file. 107 | 108 | #### Note the domain name of tunnel-specific private certificates 109 | 110 | The tunnel-specific private certificates are automatically generated by AWS when you either create a transit gateway VPN attachment or create a site-to-site connection. These private certificates contain a domain name that you’ll need to take note of and supply when you deploy the strongSwan VPN gateway stack in your simulated on-premises environment. 111 | 112 | When the tunnels are being established, the srongSwan tool will use the domain names to help validate the tunnel-specific private certificates exchanged when the tunnels are established. 113 | 114 | #### Prepare your simulated on-premises environment 115 | 116 | Before you can create the CloudFormation stack for your strongSwan VPN gateway in your simulated on-premises environment, you’ll need to perform the following steps. 117 | 118 | First, you’ll need to upload the certificates and customer gateway private key to an S3 bucket that is accessible from your simulated on-premises environment. 119 | 120 | Next, you’ll need to create a secret in AWS Secrets Manager and store the passphrase to decrypt the customer gateway private key in that secret. 121 | 122 | The following diagram shows the certificates and the customer gateway private key stored in an S3 bucket. The passphrase for the customer gateway private key is stored in a secret in AWS secrets manager. 123 | 124 | Certificate and key data required 125 | 126 | See [How do I create a certificate-based VPN using AWS Site-to-Site VPN?](https://aws.amazon.com/premiumsupport/knowledge-center/vpn-certificate-based-site-to-site/) for more details. 127 | 128 | ### 2. Determine Deployment Location: Public or Private Subnet 129 | 130 | Since VPN connections typically occur over the public Internet, you'll need to have at least one public IP address to represent the local side of the VPN tunnels. You have several options to associate a public IP address. In either case, decoupling the creation and management of the public IP address from the creation and management of the VPN gateway enables you to replace the VPN gateway stack including the associated strongSwan EC2 instance without needing to reconfigure the remote end of the site-to-site VPN connection. 131 | 132 | #### 2a. Deploy VPN Gateway in Public Subnet and Use Elastic IP Address 133 | 134 | Before deploying this stack, create an Elastic IP (EIP) address and obtain its allocation ID so that you can pass it as a parameter to the CloudFormation stack through which the VPN gateway will be created. When deploying this stack, you set the parameter `pUseElasticIp` to `true` and supply a value for the `pEipAllocationId` parameter. 135 | 136 | #### 2b. Deploy VPN gateway in Private Subnet and Use a NAT Gateway 137 | 138 | In this case, you discover the public IP address of the NAT Gateway and use it when configuring the remote side of the VPN connection. When deploying this stack, you accept the default `false` setting for the `pUseElasticIp` parameter. Since the local side of the site-to-site VPN initiates the connection, the local strongSwan VPN gateway will initiate the connection through the NAT Gateways public IP address. 139 | 140 | ### 3. Determine VPN Tunnel Configuration Settings 141 | 142 | When using either AWS VGWs or TGWs for the remote end of the site-to-site VPN connection, a site-to-site VPN connection resource will be established in AWS on the remote site. Within the site-to-site VPN connection resource on the remote site, you can download a VPN configuration file that will provide you with much of the data required to deploy the local VPN gateway. In the AWS management console, see `VPC -> Site-to-Site VPN Connections`, select the connection of interest, click `Download` and select the `Generic` option for `Vendor` and download the configuration file. 143 | 144 | Review the data in this file in preparation for passing it as parameters to the CloudFormation stack in the next step. 145 | 146 | #### Using PSK-based authentication 147 | 148 | If you're using PSK-based authentication, you'll need to create two secrets in AWS Secrets Manager in your simulated on-premises environment. You can find PSK values in the VPN tunnel configuration file under the "IPSec Tunnel #1" and "IPSec Tunnel #2" sections and "Pre-Shared Key" value. 149 | 150 | Each of the AWS Secrets Manager secrets for the PSK values must be in the form of `psk:` where `psk` is the key and `` is the private shared key value. 151 | 152 | ### 4. Deploy VPN Gateway Stack 153 | 154 | In this step you'll create a CloudFormation stack using the [`vpn-gateway-strongswan.yml`](vpn-gateway-strongswan.yml) template and configuration data obtained from the remote site's Site-to-Site VPN Connection resource. 155 | 156 | You can use either the AWS management console or an included helper script and the AWS CLI to create the stack. Given the number of parameters involved, you will probably find it easier to use the CLI so that you can specify the parameter values once in a JSON file as opposed to entering them via the AWS management console. Using the CLI approach also makes it easier to spin up new stack instances both in cases where failures occur and you want to change settings to experiment with features. 157 | 158 | #### Use AWS Management Console 159 | 160 | Use the CloudFormation template to deploy a VPN gateway stack in an appropriate subnet based on the [CloudFormation Template Parameters](#cloudformation-template-parameters) described below. 161 | 162 | 1. Use the [AWS Management Console](https://console.aws.amazon.com/cloudformation/home) to access the CloudFormation service. 163 | 1. Ensure that the desired AWS region is selected. 164 | 1. Select "Create Stack" and select "With new resources". 165 | 1. Select "Upload a template file" 166 | 167 | 1. Use your browser to download the [`vpn-gateway-strongswan.yml`](vpn-gateway-strongswan.yml) CloudFormation template file to your local computer. 168 | 1. Select "Choose file" to select the CloudFormation template file that you downloaded. 169 | 1. Select "Next" to "Specify stack details". 170 | 1. Enter a name for your new CloudFormation stack. For example, "vpn-gateway". 171 | 1. Override and/or fill in the required parameters. See [CloudFormation Template Parameters](#cloudformation-template-parameters) for details. 172 | 1. Select "Next" to "Configure stack options". 173 | 1. Select "Next" to review your stack settings. 174 | 1. Select "Create stack". 175 | 176 | #### Use AWS CLI 177 | 178 | If you have the AWS CLI installed, you might find it easier to use the included shell script `manage-stack` to create the stack. 179 | 180 | 1. Clone this repository to your local system on which you have the AWS CLI installed. 181 | 2. Customize one of the `template-parameters-*.json` files containing example sets of parameters for your stack. 182 | 3. Execute the `manage-stack` wrapper script to create the stack. Here are the option arguments that are commonly used with this script: 183 | 184 | |Option Argument|Required?|Description|Default| 185 | |---------|--------|-----------|-------| 186 | |`-s` or `--stack-name`| Required|Specifies the name to assign to the newly created stack.|None| 187 | |`-r` or `--region`|Optional|AWS region. Since the `aws` CLI is used, the standard environment variables are honored.|The `aws` CLI will use the standard `AWS_DEFAULT_REGION` environment variable if set.| 188 | |`-p` or `--profile`|Optional|AWS profile. Since the `aws` CLI is used, the standard environment variables are honored.|The `aws` CLI will use the standard `AWS_PROFILE` environment variable if set.| 189 | 190 | An example execution: 191 | 192 | ``` 193 | $ ./manage-stack -s vpn-gateway-1 --region us-east-1 template-parameters-certificate-auth.json 194 | ``` 195 | Execution of this command would result in an attempt to create a new stack of the name `vpn-gateway-1`. 196 | 197 | Monitor the progress of stack creation via the AWS management console. 198 | 199 | #### After Starting the Create Stack Process 200 | 201 | * Wait for creation of the stack to complete. Since the template uses a wait condition, the stack won't complete until strongSwan and other components have been configured and started. 202 | * Wait for several minutes after stack creation completes. Then monitor the Site-to-Site VPN Connection on the remote site to confirm that the two VPN tunnels have progressed from the `DOWN` state to the `UP` state. If the VPN gateway configuration is correct, Tunnel 1 will come up first followed several minutes later by Tunnel 2. 203 | 204 | If the tunnels have not come up 3-5 minutes after creation of the VPN gateway stack completed, then see the [Troubleshooting](#troubleshooting) section below. 205 | 206 | ### 4. Ensure Routing Tables and EC2 Security Groups Are in Place 207 | 208 | On both sides of the site-to-site VPN connection, ensure that the appropriate routing and security group configurations are in place to enable proper routing of traffic. For example: 209 | 210 | * In support of testing, ensure that testing EC2 instances can receive ICMP or ping traffic. 211 | * Ensure VPC route tables associated with subnets route traffic destined for the other site to the local VPN gateway instance. 212 | * If using Transit Gateway on the remote site, ensure that VPC route tables are configured to route traffic destined for the other site to the Transit Gateway. (Although the built-in BGP support in this stack will help ensure that both the local VPN gateway's route information and the remote Transit Gateway's route table will be automatically configured, you still need to ensure that the VPC route tables in both sites are properly configured). 213 | 214 | ### 5. Test 215 | 216 | * Deploy an Amazon Linux EC2 instance to one of the local subnets. 217 | * Ensure ICMP is allowed as inbound traffic. 218 | * Set it up for SSH access in one of two ways: 219 | * Systems Manager Session Manager: No SSH and publicly accessible IP address required. Instead, create an IAM role for EC2 that includes the `AmazonSSMManagedInstanceCore` policy and attach it to the EC2 instance via the `Actions -> Instance Settings -> Attach/Replace IAM Role`. 220 | * SSH: Ensure that the security group allows for SSH inbound access and that the instance has a publicly accessible IP address. 221 | * Deploy another EC2 instance in the remote site with the same configuration as above. 222 | * Validate that route tables and security groups are properly configured. 223 | * Use `ping` on one of the two ends to validate routing and connectivity between the instances. 224 | * Use `# tcpdump -eni any icmp` to on the target instance to monitor traffic. 225 | 226 | ## CloudFormation Template Parameters 227 | 228 | |Parameter|Required|Description|Default| 229 | |---------|--------|-----------|-------| 230 | |**System Classification and Environment**| | | | 231 | |`pOrg`|Optional|As an example of using resource naming standards, include the business organization in the names of resources including, for example, IAM roles.|`example`| 232 | |`pSystem`|Optional|As an example of using resource naming standards, include a system identifier in the names of resources including, for example, IAM roles..|`infra`| 233 | |`pApp`|Optional|As an example of using resource naming standards, include an application identifier in the names of resources including, for example, IAM roles.|`vpngw`| 234 | |`pEnvPurpose`|Required|As an example of using resource naming standards, include a purpose for this particulart instance of the stack in the names of resources including, for example, IAM roles.. For example, "dev1", "test", "1", etc.|None| 235 | |**Authentication Type**| | | | 236 | |`pAuthType`|Optional|The type of authentication. Either `psk` or `pubkey`. Use `pubkey` for certificate-based authentication and `psk` for private shared key-based authentication.|`psk`| 237 | |**Certificate-Based Authentication**| | | | 238 | |`pCertBucket`|Required when using certificate-based authentication.|Name of S3 bucket containing the following certificate files in `.pem` format.|None| 239 | |`pCgwCert`|Required when using certificate-based authentication.|Name of customer gateway certificate file residing in S3.|None| 240 | |`pCgwPrivateKey`|Required when using certificate-based authentication.|Name of customer gateway private key file residing in S3.|None| 241 | |`pCgwPrivateKeyPassphraseSecretName`|Required when using certificate-based authentication.|Name of secret in AWS Secrets Manager containing the passphrase for the customer gateway private key file residing in S3.

AWS Secrets Manager secret must be in the form of `passphrase:` where `passphrase` is the key and `` is the passphrase value.|None| 242 | |`pRootCaCert`|Required when using certificate-based authentication.|Name of root CA certificate file residing in S3. Required when using certificate-based authentication.|None| 243 | |`pSubordinateCaCert`|Required when using certificate-based authentication.|Name of subordinate CA certificate file residing in S3. Required when using certificate-based authentication.|None| 244 | |**VPN Tunnel 1**| | | | 245 | |`pTunnel1PskSecretName`|Required when using PSK-based authentication.|Name of secret in AWS Secrets Manager containing the private shared key for tunnel 1.

AWS Secrets Manager secret must be in the form of `psk:` where `psk` is the key and `` is the private shared key value.

See the remote site's configuration for the "IPSec Tunnel #1" section and "Pre-Shared Key" value.|None| 246 | |`pTunnel1VgwCertDomainName`|Required when using certificate-based authentication.|The domain name of the private certificate associated with tunnel 1. Required when using certificate-based authentication.

You can obtain this value from accessing your site-to-site VPN connection in your AWS environment, selecting the "Tunnel Details" tab, and selecting the "Certificate ARN".|None| 247 | |`pTunnel1VgwOutsideIpAddress`|Required|See the remote site's configuration for the "IPSec Tunnel #1" section, "Outside IP Addresses" section and "Virtual Private Gateway" value.|None| 248 | |`pTunnel1CgwInsideCidr`|Required|See the remote site's configuration for the "IPSec Tunnel #1" section, "Inside IP Addresses" section and "Customer Gateway" value.|None| 249 | |`pTunnel1VgwInsideCidr`|Required|See the remote site's configuration for the "IPSec Tunnel #1" section, "Inside IP Addresses" section and "Virtual Private Gateway" value.|None| 250 | |`pTunnel1VgwBgpAsn`|Optional|See the remote site's configuration for the "BGP Configuration Options" and the "Virtual Private Gateway ASN" value.|`64512`| 251 | |`pTunnel1BgpNeighborIpAddress`|Required|See the remote site's configuration for the "BGP Configuration Options" and the "Neighbor IP Address" value.|None| 252 | |**VPN Tunnel 2**| | | | 253 | |`pTunnel2PskSecretName`|Required when using PSK-based authentication.|Name of secret in AWS Secrets Manager containing the private shared key for tunnel 2.

AWS Secrets Manager secret must be in the form of `psk:` where `psk` is the key and `` is the private shared key value.

See the remote site's configuration for the "IPSec Tunnel #2" section and "Pre-Shared Key" value.|None| 254 | |`pTunnel2VgwCertDomainName`|Required when using certificate-based authentication.|The domain name of the certificate associated with tunnel 2. Required when using certificate-based authentication.|None| 255 | |`pTunnel2VgwOutsideIpAddress`|Required|See Tunnel 1.|None| 256 | |`pTunnel2CgwInsideCidr`|Required|See Tunnel 1.|None| 257 | |`pTunnel2VgwInsideCidr`|Required|See Tunnel 1.|None| 258 | |`pTunnel2VgwBgpAsn`|Optional|See Tunnel 1.|`64512`| 259 | |`pTunnel2BgpNeighborIpAddress`|Required|See Tunnel 1.|None| 260 | |**Local Network Configuration**| | | | 261 | |`pVpcId`|Required|The VPC in which the VPN gateway is to be deployed.|None| 262 | |`pVpcCidr`|Required|The CIDR block of the local VPC. Used to advertise via BGP routing information to the remote site.|None| 263 | |`pSubnetId`|Required|The subnet in which the VPN gateway is to be deployed.|None| 264 | |`pUseElasticIp`|Optional|Use elastic IP address?|`true`| 265 | |`pEipAllocationId`|Required when `pUseElasticIP` = `true`|The allocation ID of the Elastic IP address that is to be associated with the VPN gateway.|None| 266 | |`pLocalBgpAsn`|Optional|The BGP Autonomous System Number (ASN) used to represent the local end of the site-to-site VPN connection.|`65000`| 267 | |**EC2 Instance**| | | | 268 | |`pAmiId`|Optional|The ID of the AMI to use for the VPN gateway. By default this Systems Manager Parameter Store key is used to lookup the latest version of the referenced AMI for use in the current region.|`/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-ebs`| 269 | |`pInstanceType`|Optional|The EC2 instance type to use for the VPN gateway.|`t3a.micro`| 270 | 271 | ## Troubleshooting 272 | 273 | ### Stack creation fails quickly 274 | 275 | Verify your parameter settings against both your local network configuration and the configuration of the site-to-site tunnels. If you're using an Elastic IP address, ensure that the allocation ID is correct. 276 | 277 | ### Stack creation fails after a long period of time 278 | 279 | You may find that the stack creation fails after multiple minutes and resources are rolled back. In this case, it's best to delete the stack and use the CLI approach described above in an attempt to create the stack again. However, this time, you'll use CloudWatch logs to inspect the progress of the first boot configuration steps during stack creation. 280 | 281 | Similar to the previous circumstance, verify your parameter settings against both your local network configuration and the configuration of the site-to-site tunnels. If you're using an Elastic IP address, ensure that the allocation ID is correct. 282 | 283 | If no obvious issues are identified based on a review of the template parameters, delete the failed stack and use the CLI approach in an attempt to create the stack again. This time, during stack creation, inspect the CloudWatch logs group to gain insight into failures that might be occurring during the first boot configuration process. For example, if the S3 bucket name for certificate key files is incorrect, the first boot configuration process will fail. 284 | 285 | Specifically, access the `cfn-init.log` log stream to review the first boot configuration for any errors. By default, the log group for you EC2 instance will be named `/infra/vpngw/ec2/`. 286 | 287 | If the `cfn-init.log` log stream looks clean, then review the `charon.log` log stream for errors. If you're using certificate-based authentication and your certificates and key files are incorrect, then you'll typically see errors in this log stream. 288 | 289 | ### Tunnels Don't Come Up 290 | 291 | Ensure that you've waited 5 minutes or so to give the tunnels time to establish. 292 | 293 | It's likely that one or more of the tunnel related stack parameters is incorrect. Double check the settings. You can delete and recreate the VPN gateway stack without needing to delete and recreate the remote site's VPN resources. 294 | 295 | You can also inspect the VPN gateway's logs via CloudWatch Logs. In CloudWatch Logs, look for a log group that is named based on the system classification parameters described above. For example: `/infra/vpngw/ec2/...`. 296 | 297 | If any of the following log files are not present: `charon.log`, `zebra.log`, `bgpd.log`, start a terminal session with the gateway instance and use the `systemctl status ` command to understand why a service did not start. 298 | 299 | Log files in order of importance are: 300 | 301 | * `cfn-init.log` - Look for successful execution of the configuration sets from the `AWS::CloudFormation::Init` section of the CloudFormation template. 302 | * `charon.log` - If initialization looks ok, check the content of this log file to monitor the establishment of the VPN tunnels. 303 | 304 | ### Can't Ping Across the VPN Connection 305 | 306 | Verify correctness of the following configurations on both sides of the site-to-site VPN connection: 307 | * EC2 instance security groups. 308 | * Route tables. 309 | 310 | Consider using `tcpdump` on the VPN gateway EC2 instance to see if traffic is being routed through the gateway. 311 | 312 | ## Inspecting the strongSwan VPN Gateway EC2 Instance 313 | 314 | If any of the following log files are not present in CloudWatch Logs: `charon.log`, `zebra.log`, `bgpd.log`, start a terminal session with the VPN gateway instance and execute a command to display error messages associated with services starting up on the strongSwan EC2 instance. 315 | 316 | ### Accessing a Terminal Session 317 | 318 | Since the CloudFormation stack configures the VPN gateway EC2 instance to support terminal access through AWS Systems Manager Session Manager, you can easily connect to the strongSwan EC2 instance via the EC2 portion of the AWS management console. 319 | 320 | 1. Access the EC2 service of the AWS Management Console 321 | 1. Choose the strongSwan EC2 instance. For example, infra-vpngw-test 322 | 1. Choose "Connect" in the upper portion of the console 323 | 1. Choose the "Session Manager" option 324 | 1. Choose "Connect" 325 | 326 | You should be presented with a terminal session of the EC2 instance. 327 | 328 | ### Inspecting strongSwan 329 | 330 | Use the following commands to display errors associated with starting the following services: 331 | 332 | ``` 333 | $ systemctl status strongswan 334 | 335 | $ systemctl status zebra 336 | 337 | $ systemctl status bgpd 338 | ``` 339 | 340 | You can review the status of the strongSwan application via sudo strongswan status command. Execution of this command should show that both tunnels are connected: 341 | 342 | ``` 343 | $ sudo strongswan status 344 | 345 | Security Associations (2 up, 0 connecting): 346 | AWS-VPC-TUNNEL-1[135]: ESTABLISHED 2 hours ago, 10.0.0.221[10.0.0.221]...18.222.98.126[18.222.98.126] 347 | AWS-VPC-TUNNEL-1{1358}: REKEYED, TUNNEL, reqid 1, expires in 6 minutes 348 | AWS-VPC-TUNNEL-1{1358}: 0.0.0.0/0 === 0.0.0.0/0 349 | AWS-VPC-TUNNEL-1{1360}: INSTALLED, TUNNEL, reqid 1, ESP in UDP SPIs: c2217636_i c2fc4ee3_o 350 | AWS-VPC-TUNNEL-1{1360}: 0.0.0.0/0 === 0.0.0.0/0 351 | AWS-VPC-TUNNEL-2[134]: ESTABLISHED 6 hours ago, 10.0.0.221[10.0.0.221]...52.15.138.189[52.15.138.189] 352 | AWS-VPC-TUNNEL-2{1357}: REKEYED, TUNNEL, reqid 8, expires in 4 minutes 353 | AWS-VPC-TUNNEL-2{1357}: 0.0.0.0/0 === 0.0.0.0/0 354 | AWS-VPC-TUNNEL-2{1359}: INSTALLED, TUNNEL, reqid 8, ESP in UDP SPIs: cff85483_i 87052d38_o 355 | AWS-VPC-TUNNEL-2{1359}: 0.0.0.0/0 === 0.0.0.0/0 356 | ``` 357 | 358 | If you're using certificated-based authentication, you can inspect the certificates loaded by strongSwan: 359 | 360 | ``` 361 | # strongswan listcerts # list the public certificates 362 | 363 | # strongswan listcacerts # list the CA certificates 364 | ``` 365 | 366 | You can inspect the BGP routes that Quagga knows about by executing the `sudo vtysh` command followed by the `show ip bgp summary` subcommand. In the following example, the BGP tunnel neighbors are listed: 367 | 368 | ``` 369 | $ sudo vtysh 370 | 371 | Hello, this is Quagga (version 0.99.22.4). 372 | Copyright 1996-2005 Kunihiro Ishiguro, et al. 373 | 374 | ip-10-0-0-221.corp.ckamps-acme.com# show ip bgp summary 375 | 376 | BGP router identifier 10.0.0.221, local AS number 65000 377 | RIB entries 3, using 336 bytes of memory 378 | Peers 2, using 9120 bytes of memory 379 | 380 | Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 381 | 169.254.54.17 4 64512 182713 182714 0 0 0 03w0d03h 1 382 | 169.254.227.237 4 64512 182593 182632 0 0 0 14:36:47 1 383 | 384 | Total number of neighbors 2 385 | ``` 386 | 387 | Next, you can inspect the routes by executing the `show ip route` subcommand. In the following example, 10.4.0.0/19 represents the route advertised by the transit gateway via BGP. 388 | 389 | ``` 390 | # show ip route 391 | 392 | Codes: K - kernel route, C - connected, S - static, R - RIP, 393 | O - OSPF, I - IS-IS, B - BGP, A - Babel, 394 | > - selected route, * - FIB route 395 | 396 | K>* 0.0.0.0/0 via 10.0.0.1, eth0 397 | C>* 10.0.0.0/24 is directly connected, eth0 398 | B>* 10.4.0.0/19 [20/100] via 169.254.54.17, vti1, src 10.0.0.221, 03w0d03h 399 | C>* 127.0.0.0/8 is directly connected, lo 400 | C>* 169.254.54.16/30 is directly connected, vti1 401 | K>* 169.254.169.254/32 is directly connected, eth0 402 | C>* 169.254.227.236/30 is directly connected, vti2 403 | ``` 404 | 405 | ## Advanced Usage 406 | 407 | ### Updating a VPN Gateway Stack 408 | 409 | If you need to change resources that are configured outside of the `UserData` and `Metadata` sections of the `AWS::EC2::LaunchTemplate`, you should be able to update either the template or stack parameters and update the stack in place. 410 | 411 | Until the `AWS::EC2::LaunchTemplate` is modified to support stack updates, any changes in the `UserData` and `Metadata` sections of that resource require replacement of the stack. 412 | 413 | ### Replacing a VPN Gateway Stack 414 | 415 | Since the Elastic IP Address resource is managed via a distinct CloudFormation stack, you can delete a VPN gateway stack without also deleting the associated EIP address. If you are using the VPN gateway stack to set up a site-to-site VPN with AWS VPG or TGW resources, you can simply delete the existing VPN gateway stack and create a new stack with the same parameters. The remote side of the site-to-site VPN connection will automatically reconnect once the new VPN gateway has been established. 416 | 417 | After deploying the new VPN gateway stack, you will need to ensure that any local routing table entries are updated to point to the new VPN gateway EC2 instance. 418 | 419 | ### Masking Source IP Addresses 420 | 421 | If you'd like the VPC in which the strongSwan VPN gateway is running to forward traffic from the VPN connection to either other VPCs via VPC Peering or onward via gateways such an Internet Gateway to NAT Gateway, you'll need to configure the VPN gateway to mask the original source IP address by using the VPN gateway's IP address. 422 | 423 | You can implement source network IP masking via an `iptables` command. For example, the following command when run on the strongSwan VPN gateway will mask the source IP address only for traffic whose destination IP address does not match the specified network. e.g. It will mask traffic destined for the Internet, but not for the local network. Presence of the `!` argument prior to the `-d` argument ensures that the all destinations other than the stated network will be subject to the masking rule. 424 | 425 | ``` 426 | $ sudo /sbin/iptables -t nat -A POSTROUTING -o eth0 ! -d 10.0.0.0/16 -j MASQUERADE 427 | ``` 428 | Alternatively, you can choose to mask all traffic: 429 | 430 | ``` 431 | $ sudo /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE 432 | ``` 433 | 434 | Other useful `iptables` commands include: 435 | 436 | ``` 437 | # List the current rules: 438 | 439 | # With packet counts: 440 | 441 | $ sudo iptables -t nat -L -v 442 | 443 | Chain PREROUTING (policy ACCEPT 12 packets, 1001 bytes) 444 | pkts bytes target prot opt in out source destination 445 | 446 | Chain INPUT (policy ACCEPT 1 packets, 93 bytes) 447 | pkts bytes target prot opt in out source destination 448 | 449 | Chain OUTPUT (policy ACCEPT 234 packets, 16318 bytes) 450 | pkts bytes target prot opt in out source destination 451 | 452 | Chain POSTROUTING (policy ACCEPT 152 packets, 11245 bytes) 453 | pkts bytes target prot opt in out source destination 454 | 93 5981 MASQUERADE all -- any eth0 anywhere !10.0.0.0/16 455 | 456 | # With line numbers: 457 | 458 | $ sudo iptables -t nat -L --line-numbers 459 | 460 | Chain PREROUTING (policy ACCEPT) 461 | num target prot opt source destination 462 | 463 | Chain INPUT (policy ACCEPT) 464 | num target prot opt source destination 465 | 466 | Chain OUTPUT (policy ACCEPT) 467 | num target prot opt source destination 468 | 469 | Chain POSTROUTING (policy ACCEPT) 470 | num target prot opt source destination 471 | 1 MASQUERADE all -- anywhere !10.0.0.0/16 472 | 473 | # Delete a specific rule based on line number: 474 | 475 | $ sudo iptables -t nat -D POSTROUTING 1 476 | ``` 477 | 478 | ## Contributing 479 | 480 | See [CONTRIBUTING.md](./CONTRIBUTING.md) for the contribution process. 481 | 482 | File an issue in GitHub, ensure your changes pass `cfn-lint` tests and functionally work, before submitting a Pull Request (PR) for consideration. 483 | 484 | ## License 485 | 486 | This project is licensed under the [Apache-2.0 License](./LICENSE). 487 | -------------------------------------------------------------------------------- /images/cert-based-authentication-aws-environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/cert-based-authentication-aws-environment.png -------------------------------------------------------------------------------- /images/cert-based-authentication-simulated-on-premises-environment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/cert-based-authentication-simulated-on-premises-environment.png -------------------------------------------------------------------------------- /images/cert-based-authentication.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /images/featured-image.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/featured-image.pptx -------------------------------------------------------------------------------- /images/site-to-site-vpn-console-config-tgw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-console-config-tgw.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-console-config-tunnel-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-console-config-tunnel-status.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-console-config-vpc-routes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-console-config-vpc-routes.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-diy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-diy.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-end-to-end test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-end-to-end test.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-tgw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-tgw.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-vgw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-vgw.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-vpn-config-screenshots-cgw-asn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-vpn-config-screenshots-cgw-asn.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-vpn-config-screenshots-inside-cgw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-vpn-config-screenshots-inside-cgw.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-vpn-config-screenshots-inside-vgw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-vpn-config-screenshots-inside-vgw.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-vpn-config-screenshots-neighbor-ip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-vpn-config-screenshots-neighbor-ip.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-vpn-config-screenshots-outside-vgw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-vpn-config-screenshots-outside-vgw.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-vpn-config-screenshots-psk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-vpn-config-screenshots-psk.png -------------------------------------------------------------------------------- /images/site-to-site-vpn-scenarios-vpn-config-screenshots-vgw-asn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/vpn-gateway-strongswan/6c1caab6cb53c383ace6e4cc834d2c1e27ef924a/images/site-to-site-vpn-scenarios-vpn-config-screenshots-vgw-asn.png -------------------------------------------------------------------------------- /manage-stack: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #set -x 4 | 5 | PARAMS="" 6 | while (( "$#" )); do 7 | case "$1" in 8 | -u|--update) 9 | UPDATE=1 10 | shift 1 11 | ;; 12 | -s|--stack-name) 13 | STACK_NAME_ARG=$2 14 | shift 2 15 | ;; 16 | -t|--template) 17 | TEMPLATE_ARG=$2 18 | shift 2 19 | ;; 20 | -p|--profile) 21 | PROFILE_ARG=$2 22 | shift 2 23 | ;; 24 | -r|--region) 25 | REGION_ARG=$2 26 | shift 2 27 | ;; 28 | --) 29 | shift 30 | break 31 | ;; 32 | -*|--*=) 33 | echo "Error: Unsupported flag $1" >&2 34 | exit 1 35 | ;; 36 | *) 37 | PARAMS="$PARAMS $1" 38 | shift 39 | ;; 40 | esac 41 | done 42 | 43 | eval set -- "$PARAMS" 44 | 45 | if [ -z $UPDATE ]; then 46 | CMD='create-stack --enable-termination-protection' 47 | else 48 | CMD='update-stack' 49 | fi 50 | 51 | if [ -z ${STACK_NAME_ARG+x} ]; then 52 | echo 'You must supply -s|--stack-name' 53 | exit 1 54 | else 55 | STACK_NAME=$STACK_NAME_ARG 56 | fi 57 | 58 | if [ -z ${TEMPLATE_ARG+x} ]; then 59 | TEMPLATE=vpn-gateway-strongswan.yml 60 | else 61 | TEMPLATE=$TEMPLATE_ARG 62 | fi 63 | 64 | if [ -z ${PROFILE_ARG+x} ]; then 65 | PROFILE= 66 | else 67 | PROFILE="--profile $PROFILE_ARG" 68 | fi 69 | 70 | if [ -z ${REGION_ARG+x} ]; then 71 | REGION= 72 | else 73 | REGION="--region $REGION_ARG" 74 | fi 75 | 76 | aws cloudformation ${CMD} \ 77 | --stack-name ${STACK_NAME} \ 78 | --template-body file://./${TEMPLATE} \ 79 | --parameters file://${1} \ 80 | --capabilities CAPABILITY_NAMED_IAM \ 81 | ${REGION} \ 82 | ${PROFILE} 83 | 84 | #aws cloudformation wait stack-create-complete --stack-name ${STACK_NAME} --region ${AWS_REGION} --profile ${AWS_PROFILE} 85 | -------------------------------------------------------------------------------- /template-parameters-certificate-auth.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrg", 4 | "ParameterValue": "example" 5 | }, 6 | { 7 | "ParameterKey": "pSystem", 8 | "ParameterValue": "infra" 9 | }, 10 | { 11 | "ParameterKey": "pApp", 12 | "ParameterValue": "vpngw" 13 | }, 14 | { 15 | "ParameterKey": "pEnvPurpose", 16 | "ParameterValue": "test14" 17 | }, 18 | { 19 | "ParameterKey": "pAuthType", 20 | "ParameterValue": "pubkey" 21 | }, 22 | { 23 | "ParameterKey": "pCertBucket", 24 | "ParameterValue": "example-certs" 25 | }, 26 | { 27 | "ParameterKey": "pCgwCert", 28 | "ParameterValue": "example-cloud-vpn-cert.pem" 29 | }, 30 | { 31 | "ParameterKey": "pCgwPrivateKey", 32 | "ParameterValue": "example-cloud-vpn-private-key.pem" 33 | }, 34 | { 35 | "ParameterKey": "pCgwPrivateKeyPassphraseSecretName", 36 | "ParameterValue": "..." 37 | }, 38 | { 39 | "ParameterKey": "pRootCaCert", 40 | "ParameterValue": "example-cloud-root-ca.pem" 41 | }, 42 | { 43 | "ParameterKey": "pSubordinateCaCert", 44 | "ParameterValue": "example-cloud-subordinate-ca.pem" 45 | }, 46 | { 47 | "ParameterKey": "pTunnel1VgwCertDomainName", 48 | "ParameterValue": "vpn-0nnn.endpoint-0" 49 | }, 50 | { 51 | "ParameterKey": "pTunnel1VgwOutsideIpAddress", 52 | "ParameterValue": "n.n.n.n" 53 | }, 54 | { 55 | "ParameterKey": "pTunnel1CgwInsideIpAddress", 56 | "ParameterValue": "n.n.n.n/30" 57 | }, 58 | { 59 | "ParameterKey": "pTunnel1VgwInsideIpAddress", 60 | "ParameterValue": "n.n.n.n/30" 61 | }, 62 | { 63 | "ParameterKey": "pTunnel1VgwBgpAsn", 64 | "ParameterValue": "64512" 65 | }, 66 | { 67 | "ParameterKey": "pTunnel1BgpNeighborIpAddress", 68 | "ParameterValue": "n.n.n.n" 69 | }, 70 | { 71 | "ParameterKey": "pTunnel2VgwCertDomainName", 72 | "ParameterValue": "vpn-0nnn.endpoint-1" 73 | }, 74 | { 75 | "ParameterKey": "pTunnel2VgwOutsideIpAddress", 76 | "ParameterValue": "n.n.n.n" 77 | }, 78 | { 79 | "ParameterKey": "pTunnel2CgwInsideIpAddress", 80 | "ParameterValue": "n.n.n.n/30" 81 | }, 82 | { 83 | "ParameterKey": "pTunnel2VgwInsideIpAddress", 84 | "ParameterValue": "n.n.n.n/30" 85 | }, 86 | { 87 | "ParameterKey": "pTunnel2VgwBgpAsn", 88 | "ParameterValue": "64512" 89 | }, 90 | { 91 | "ParameterKey": "pTunnel2BgpNeighborIpAddress", 92 | "ParameterValue": "n.n.n.n" 93 | }, 94 | { 95 | "ParameterKey": "pVpcId", 96 | "ParameterValue": "vpc-0nnn" 97 | }, 98 | { 99 | "ParameterKey": "pVpcCidr", 100 | "ParameterValue": "10.0.0.0/16" 101 | }, 102 | { 103 | "ParameterKey": "pSubnetId", 104 | "ParameterValue": "subnet-0nnn" 105 | }, 106 | { 107 | "ParameterKey": "pUseElasticIp", 108 | "ParameterValue": "true" 109 | }, 110 | { 111 | "ParameterKey": "pEipAllocationId", 112 | "ParameterValue": "eipalloc-0nnn" 113 | }, 114 | { 115 | "ParameterKey": "pLocalBgpAsn", 116 | "ParameterValue": "65000" 117 | }, 118 | { 119 | "ParameterKey": "pInstanceType", 120 | "ParameterValue": "t3a.micro" 121 | } 122 | ] -------------------------------------------------------------------------------- /template-parameters-psk-auth.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ParameterKey": "pOrg", 4 | "ParameterValue": "example" 5 | }, 6 | { 7 | "ParameterKey": "pSystem", 8 | "ParameterValue": "infra" 9 | }, 10 | { 11 | "ParameterKey": "pApp", 12 | "ParameterValue": "vpngw" 13 | }, 14 | { 15 | "ParameterKey": "pEnvPurpose", 16 | "ParameterValue": "test15" 17 | }, 18 | { 19 | "ParameterKey": "pAuthType", 20 | "ParameterValue": "psk" 21 | }, 22 | { 23 | "ParameterKey": "pTunnel1PskSecretName", 24 | "ParameterValue": "..." 25 | }, 26 | { 27 | "ParameterKey": "pTunnel1VgwOutsideIpAddress", 28 | "ParameterValue": "n.n.n.n" 29 | }, 30 | { 31 | "ParameterKey": "pTunnel1CgwInsideIpAddress", 32 | "ParameterValue": "n.n.n.n/30" 33 | }, 34 | { 35 | "ParameterKey": "pTunnel1VgwInsideIpAddress", 36 | "ParameterValue": "n.n.n.n/30" 37 | }, 38 | { 39 | "ParameterKey": "pTunnel1VgwBgpAsn", 40 | "ParameterValue": "64512" 41 | }, 42 | { 43 | "ParameterKey": "pTunnel1BgpNeighborIpAddress", 44 | "ParameterValue": "n.n.n.n" 45 | }, 46 | { 47 | "ParameterKey": "pTunnel2PskSecretName", 48 | "ParameterValue": "..." 49 | }, 50 | { 51 | "ParameterKey": "pTunnel2VgwOutsideIpAddress", 52 | "ParameterValue": "n.n.n.n" 53 | }, 54 | { 55 | "ParameterKey": "pTunnel2CgwInsideIpAddress", 56 | "ParameterValue": "n.n.n.n/30" 57 | }, 58 | { 59 | "ParameterKey": "pTunnel2VgwInsideIpAddress", 60 | "ParameterValue": "n.n.n.n/30" 61 | }, 62 | { 63 | "ParameterKey": "pTunnel2VgwBgpAsn", 64 | "ParameterValue": "64512" 65 | }, 66 | { 67 | "ParameterKey": "pTunnel2BgpNeighborIpAddress", 68 | "ParameterValue": "n.n.n.n" 69 | }, 70 | { 71 | "ParameterKey": "pVpcId", 72 | "ParameterValue": "vpc-0..." 73 | }, 74 | { 75 | "ParameterKey": "pVpcCidr", 76 | "ParameterValue": "10.0.0.0/16" 77 | }, 78 | { 79 | "ParameterKey": "pSubnetId", 80 | "ParameterValue": "subnet-0..." 81 | }, 82 | { 83 | "ParameterKey": "pUseElasticIp", 84 | "ParameterValue": "true" 85 | }, 86 | { 87 | "ParameterKey": "pEipAllocationId", 88 | "ParameterValue": "eipalloc-0..." 89 | }, 90 | { 91 | "ParameterKey": "pLocalBgpAsn", 92 | "ParameterValue": "65000" 93 | }, 94 | { 95 | "ParameterKey": "pInstanceType", 96 | "ParameterValue": "t3a.micro" 97 | } 98 | ] -------------------------------------------------------------------------------- /vpn-gateway-strongswan.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | AWSTemplateFormatVersion: '2010-09-09' 4 | 5 | Description: strongSwan VPN Gateway as an EC2 Instance 6 | 7 | Metadata: 8 | AWS::CloudFormation::Interface: 9 | ParameterGroups: 10 | - Label: 11 | default: System Classification 12 | Parameters: 13 | - pOrg 14 | - pSystem 15 | - pApp 16 | - Label: 17 | default: System Environment 18 | Parameters: 19 | - pEnvPurpose 20 | - Label: 21 | default: Authentication Type 22 | Parameters: 23 | - pAuthType 24 | - Label: 25 | default: Common Parameters for Certificate-Based Authentication 26 | Parameters: 27 | - pCertBucket 28 | - pCgwCert 29 | - pCgwPrivateKey 30 | - pCgwPrivateKeyPassphraseSecretName 31 | - pRootCaCert 32 | - pSubordinateCaCert 33 | - Label: 34 | default: VPN Tunnel 1 35 | Parameters: 36 | - pTunnel1PskSecretName 37 | - pTunnel1VgwCertDomainName 38 | - pTunnel1VgwOutsideIpAddress 39 | - pTunnel1CgwInsideIpAddress 40 | - pTunnel1VgwInsideIpAddress 41 | - pTunnel1VgwBgpAsn 42 | - pTunnel1BgpNeighborIpAddress 43 | - Label: 44 | default: VPN Tunnel 2 45 | Parameters: 46 | - pTunnel2PskSecretName 47 | - pTunnel2VgwCertDomainName 48 | - pTunnel2VgwOutsideIpAddress 49 | - pTunnel2CgwInsideIpAddress 50 | - pTunnel2VgwInsideIpAddress 51 | - pTunnel2VgwBgpAsn 52 | - pTunnel2BgpNeighborIpAddress 53 | - Label: 54 | default: Local Network Configuration 55 | Parameters: 56 | - pVpcId 57 | - pVpcCidr 58 | - pSubnetId 59 | - pUseElasticIp 60 | - pEipAllocationId 61 | - pLocalBgpAsn 62 | - Label: 63 | default: EC2 64 | Parameters: 65 | - pAmiId 66 | - pInstanceType 67 | 68 | ParameterLabels: 69 | pOrg: 70 | default: Organization Identifier 71 | pSystem: 72 | default: System Identifier 73 | pApp: 74 | default: Application Identifier 75 | pEnvPurpose: 76 | default: Environment Purpose 77 | 78 | pAuthType: 79 | default: "Authentication type: 'psk' - Pre-shared key or 'pubkey' - Certificate" 80 | pCertBucket: 81 | default: S3 Bucket Containing Certificates and Client Private Key 82 | pCgwCert: 83 | default: Customer Gateway Certificate (S3 key) 84 | pCgwPrivateKey: 85 | default: Customer Gateway Private Key (S3 key) 86 | pCgwPrivateKeyPassphraseSecretName: 87 | default: Name of secret in AWS Secrets Manager for Customer Gateway Private Key Passphrase 88 | pRootCaCert: 89 | default: Root CA Certificate (S3 key) 90 | pSubordinateCaCert: 91 | default: Subordinate CA Certificate (S3 key) 92 | 93 | pTunnel1PskSecretName: 94 | default: Name of secret in AWS Secrets Manager for VPN Tunnel 1 Pre-Shared Key 95 | pTunnel1VgwCertDomainName: 96 | default: VPN Tunnel 1 Virtual Private Gateway Domain Name - Certificate Authentication. e.g vpn-07..78.endpoint-0 97 | pTunnel1VgwOutsideIpAddress: 98 | default: VPN Tunnel 1 Virtual Private Gateway Outside IP Address 99 | pTunnel1CgwInsideIpAddress: 100 | default: VPN Tunnel 1 Customer Gateway Inside IP Address 101 | pTunnel1VgwInsideIpAddress: 102 | default: VPN Tunnel 1 Virtual Private Gateway Inside IP Address 103 | pTunnel1VgwBgpAsn: 104 | default: VPN Tunnel 1 Virtual Private Gateway BGP ASN 105 | pTunnel1BgpNeighborIpAddress: 106 | default: VPN Tunnel 1 BGP Neighbor IP Address 107 | 108 | pTunnel2PskSecretName: 109 | default: Name of secret in AWS Secrets Manager for VPN Tunnel 2 Pre-Shared Key 110 | pTunnel2VgwCertDomainName: 111 | default: VPN Tunnel 2 Virtual Private Gateway Domain Name - Certificate Authentication. e.g vpn-07..78.endpoint-1 112 | pTunnel2VgwOutsideIpAddress: 113 | default: VPN Tunnel 2 Virtual Private Gateway Outside IP Address 114 | pTunnel2CgwInsideIpAddress: 115 | default: VPN Tunnel 2 Customer Gateway Inside IP Address 116 | pTunnel2VgwInsideIpAddress: 117 | default: VPN Tunnel 2 Virtual Private Gateway Inside IP Address 118 | pTunnel2VgwBgpAsn: 119 | default: VPN Tunnel 2 Virtual Private Gateway BGP ASN 120 | pTunnel2BgpNeighborIpAddress: 121 | default: VPN Tunnel 2 BGP Neighbor IP Address 122 | 123 | pUseElasticIp: 124 | default: Use Elastic IP Address? (true/false) 125 | pEipAllocationId: 126 | default: Elastic IP Address Allocation ID 127 | pLocalBgpAsn: 128 | default: Local VPN Gateway's BGP ASN 129 | pVpcId: 130 | default: VPC ID 131 | pVpcCidr: 132 | default: VPC CIDR Block 133 | pSubnetId: 134 | default: Subnet ID for VPN Gateway 135 | 136 | pInstanceType: 137 | default: EC2 Instance Type 138 | pAmiId: 139 | default: EC2 AMI ID 140 | 141 | Parameters: 142 | pOrg: 143 | Type: String 144 | Description: Used to qualify resource names 145 | Default: example 146 | 147 | pSystem: 148 | Type: String 149 | Description: Used to qualify resource names 150 | Default: infra 151 | 152 | pApp: 153 | Type: String 154 | Description: Used to qualify resource names 155 | Default: vpngw 156 | 157 | pEnvPurpose: 158 | Type: String 159 | Description: Used to qualify resource names. 10 characters max. 160 | AllowedPattern: '^[a-zA-Z0-9-_]{1,10}$' 161 | Default: test 162 | 163 | pAuthType: 164 | Type: String 165 | Description: "Authentication type: 'psk' - Pre-shared key or 'pubkey' - Certificate" 166 | Default: psk 167 | AllowedValues: 168 | - psk 169 | - pubkey 170 | 171 | pCertBucket: 172 | Description: S3 Bucket Containing Certificates and Customer Gateway Private Key. Required for certificate-based authentication. 173 | Type: String 174 | Default: '' 175 | 176 | pCgwCert: 177 | Description: Customer Gateway Certificate (S3 key). Required for certificate-based authentication. 178 | Type: String 179 | Default: '' 180 | 181 | pCgwPrivateKey: 182 | Description: Customer Gateway Private Key (S3 key). Required for certificate-based authentication. 183 | Type: String 184 | Default: '' 185 | 186 | pCgwPrivateKeyPassphraseSecretName: 187 | Description: Name of secret in AWS Secrets Manager for Customer Gateway Private Key Passphrase. Required for certificate-based authentication. 188 | Type: String 189 | Default: '' 190 | 191 | pRootCaCert: 192 | Description: Root CA Certificate (S3 key). Required for certificate-based authentication. 193 | Type: String 194 | Default: '' 195 | 196 | pSubordinateCaCert: 197 | Description: Subordinate CA Certificate (S3 key). Required for certificate-based authentication. 198 | Type: String 199 | Default: '' 200 | 201 | pTunnel1PskSecretName: 202 | Description: Name of secret in AWS Secrets Manager for VPN Tunnel 1 Pre-Shared Key. Required for PSK-based authentication. 203 | Type: String 204 | Default: '' 205 | 206 | pTunnel1VgwCertDomainName: 207 | Description: VPN Tunnel 1 Virtual Private Gateway Domain Name. Required for certificate-based authentication. e.g vpn-07..78.endpoint-1 208 | Type: String 209 | Default: '' 210 | 211 | pTunnel1VgwOutsideIpAddress: 212 | Description: VPN Tunnel 1 Virtual Private Gateway Outside IP Address 213 | Type: String 214 | 215 | pTunnel1CgwInsideIpAddress: 216 | Description: VPN Tunnel 1 Customer Gateway Inside IP Address 217 | Type: String 218 | 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]))$ 219 | 220 | pTunnel1VgwInsideIpAddress: 221 | Description: VPN Tunnel 1 Virtual Private Gateway Inside IP Address 222 | Type: String 223 | 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]))$ 224 | 225 | pTunnel1VgwBgpAsn: 226 | Description: VPN Tunnel 1 Virtual Private Gateway BGP ASN 227 | Type: Number 228 | Default: 64512 229 | 230 | pTunnel1BgpNeighborIpAddress: 231 | Description: VPN Tunnel 1 BGP Neighbor IP Address 232 | Type: String 233 | 234 | pTunnel2PskSecretName: 235 | Description: Name of secret in AWS Secrets Manager for VPN Tunnel 2 Pre-Shared Key. Required for PSK-based authentication. 236 | Type: String 237 | Default: '' 238 | 239 | pTunnel2VgwCertDomainName: 240 | Description: VPN Tunnel 2 Virtual Private Gateway Domain Name. Required for certificate-based authentication. e.g vpn-07..78.endpoint-1 241 | Type: String 242 | Default: '' 243 | 244 | pTunnel2VgwOutsideIpAddress: 245 | Description: VPN Tunnel 2 Virtual Private Gateway Outside IP Address 246 | Type: String 247 | 248 | pTunnel2CgwInsideIpAddress: 249 | Description: VPN Tunnel 2 Customer Gateway Inside IP Address 250 | Type: String 251 | 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]))$ 252 | 253 | pTunnel2VgwInsideIpAddress: 254 | Description: VPN Tunnel 2 Virtual Private Gateway Inside IP Address 255 | Type: String 256 | 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]))$ 257 | 258 | pTunnel2VgwBgpAsn: 259 | Description: VPN Tunnel 2 Virtual Private Gateway BGP ASN 260 | Type: Number 261 | Default: 64512 262 | 263 | pUseElasticIp: 264 | Type: String 265 | Description: Whether Elastic IP address is to be used. 266 | Default: true 267 | AllowedValues: [true, false] 268 | 269 | pEipAllocationId: 270 | Description: Elastic IP Address Allocation ID 271 | Type: String 272 | Default: '' 273 | 274 | pLocalBgpAsn: 275 | Description: Local VPN Gateway's BGP ASN 276 | Type: Number 277 | Default: 65000 278 | 279 | pTunnel2BgpNeighborIpAddress: 280 | Description: VPN Tunnel 2 BGP Neighbor IP Address 281 | Type: String 282 | 283 | pVpcId: 284 | Description: VPC ID 285 | Type: AWS::EC2::VPC::Id 286 | 287 | pVpcCidr: 288 | Description: VPC CIDR Block 289 | Type: String 290 | 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]))$ 291 | 292 | pSubnetId: 293 | Description: Subnet ID for VPN Gateway 294 | Type: AWS::EC2::Subnet::Id 295 | 296 | pInstanceType: 297 | Description: EC2 Instance Type 298 | Type: String 299 | Default: t3a.micro 300 | AllowedValues: 301 | - t3a.micro 302 | - t3a.small 303 | - t3a.medium 304 | ConstraintDescription: must be a valid EC2 instance type. 305 | 306 | pAmiId: 307 | Description: EC2 AMI ID 308 | Type: 'AWS::SSM::Parameter::Value' 309 | Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-ebs' 310 | 311 | Rules: 312 | SubnetsInVPC: 313 | Assertions: 314 | - Assert: 315 | 'Fn::EachMemberIn': 316 | - 'Fn::ValueOfAll': 317 | - 'AWS::EC2::Subnet::Id' 318 | - VpcId 319 | - 'Fn::RefAll': 'AWS::EC2::VPC::Id' 320 | AssertDescription: All subnets must in the VPC 321 | 322 | Conditions: 323 | cUseCertAuth: !Equals [ !Ref 'pAuthType', 'pubkey' ] 324 | cUsePskAuth: !Equals [ !Ref 'pAuthType', 'psk' ] 325 | cUseElasticIp: !Equals [ !Ref 'pUseElasticIp', true ] 326 | 327 | Resources: 328 | rInstanceSecurityGroup: 329 | Type: AWS::EC2::SecurityGroup 330 | Properties: 331 | GroupName: !Sub '${pSystem}-${pApp}-ec2-${pEnvPurpose}' 332 | VpcId: !Ref pVpcId 333 | GroupDescription: Allow traffic from other VPN gateway and all locally sourced traffic 334 | SecurityGroupIngress: 335 | - IpProtocol: udp 336 | FromPort: 500 337 | ToPort: 500 338 | CidrIp: !Sub '${pTunnel1VgwOutsideIpAddress}/32' 339 | - IpProtocol: udp 340 | FromPort: 500 341 | ToPort: 500 342 | CidrIp: !Sub '${pTunnel2VgwOutsideIpAddress}/32' 343 | - IpProtocol: udp 344 | FromPort: 4500 345 | ToPort: 4500 346 | CidrIp: !Sub '${pTunnel1VgwOutsideIpAddress}/32' 347 | - IpProtocol: udp 348 | FromPort: 4500 349 | ToPort: 4500 350 | CidrIp: !Sub '${pTunnel2VgwOutsideIpAddress}/32' 351 | - IpProtocol: '50' 352 | CidrIp: !Sub '${pTunnel1VgwOutsideIpAddress}/32' 353 | - IpProtocol: '50' 354 | CidrIp: !Sub '${pTunnel2VgwOutsideIpAddress}/32' 355 | - IpProtocol: '51' 356 | CidrIp: !Sub '${pTunnel1VgwOutsideIpAddress}/32' 357 | - IpProtocol: '51' 358 | CidrIp: !Sub '${pTunnel2VgwOutsideIpAddress}/32' 359 | - IpProtocol: '-1' 360 | FromPort: 0 361 | ToPort: 65535 362 | CidrIp: !Ref pVpcCidr 363 | 364 | rLaunchTemplate: 365 | Type: AWS::EC2::LaunchTemplate 366 | Properties: 367 | LaunchTemplateName: !Sub '${pSystem}-${pApp}-${pEnvPurpose}' 368 | LaunchTemplateData: 369 | InstanceType: !Ref pInstanceType 370 | ImageId: !Ref pAmiId 371 | IamInstanceProfile: 372 | Arn: !GetAtt rInstanceProfile.Arn 373 | NetworkInterfaces: 374 | - DeviceIndex: 0 375 | DeleteOnTermination: true 376 | Description: !Sub '${pSystem}-${pApp}-${pEnvPurpose}' 377 | Groups: 378 | - !Ref rInstanceSecurityGroup 379 | AssociatePublicIpAddress: !Ref pUseElasticIp 380 | UserData: 381 | Fn::Base64: !Sub | 382 | #!/bin/bash -x 383 | 384 | yum install -y amazon-cloudwatch-agent 385 | 386 | /opt/aws/bin/cfn-init \ 387 | --verbose \ 388 | --stack ${AWS::StackName} \ 389 | --resource rLaunchTemplate \ 390 | --configsets ${pAuthType} \ 391 | --region ${AWS::Region} 392 | 393 | /opt/aws/bin/cfn-signal \ 394 | --exit-code $? \ 395 | '${rVpnGatewayWaitHandle}' 396 | Metadata: 397 | AWS::CloudFormation::Authentication: 398 | S3BucketAccessCredential: 399 | type: "S3" 400 | roleName: !Ref rRole 401 | AWS::CloudFormation::Init: 402 | configSets: 403 | psk: 404 | - 01-config-cloudwatch-agent 405 | - 02-restart-cloudwatch-agent 406 | - 03-install-epel 407 | - 04-config-vpn-gateway-config 408 | - 05-config-vpn-gateway-secrets-psk 409 | - 06-config-vpn-gateway-commands 410 | pubkey: 411 | - 01-config-cloudwatch-agent 412 | - 02-restart-cloudwatch-agent 413 | - 03-install-epel 414 | - 04-config-vpn-gateway-config 415 | - 05-config-vpn-gateway-cert-files 416 | - 06-config-vpn-gateway-commands 417 | 01-config-cloudwatch-agent: 418 | files: 419 | /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json: 420 | content: !Sub | 421 | { 422 | "metrics": { 423 | "metrics_collected": { 424 | "cpu": { 425 | "resources": [ 426 | "*" 427 | ], 428 | "measurement": [ 429 | "usage_idle", 430 | "usage_nice", 431 | "usage_guest" 432 | ], 433 | "totalcpu": false, 434 | "metrics_collection_interval": 10 435 | }, 436 | "mem": { 437 | "measurement": [ 438 | "total", 439 | "used", 440 | "used_percent" 441 | ] 442 | }, 443 | "swap": { 444 | "measurement": [ 445 | "free", 446 | "used", 447 | "used_percent" 448 | ] 449 | }, 450 | "netstat": { 451 | "measurement": [ 452 | "tcp_established", 453 | "tcp_syn_sent", 454 | "tcp_close" 455 | ], 456 | "metrics_collection_interval": 60 457 | }, 458 | "disk": { 459 | "measurement": [ 460 | "total", 461 | "free", 462 | "used", 463 | "used_percent" 464 | ], 465 | "resources": [ 466 | "*" 467 | ], 468 | "drop_device": true 469 | }, 470 | "processes": { 471 | "measurement": [ 472 | "running", 473 | "sleeping", 474 | "dead" 475 | ] 476 | } 477 | }, 478 | "append_dimensions": { 479 | "ImageId": "${!aws:ImageId}", 480 | "InstanceId": "${!aws:InstanceId}", 481 | "InstanceType": "${!aws:InstanceType}" 482 | }, 483 | "aggregation_dimensions" : [["InstanceId", "InstanceType"],[]] 484 | }, 485 | "logs": { 486 | "logs_collected": { 487 | "files": { 488 | "collect_list": [ 489 | { 490 | "file_path": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log", 491 | "log_group_name": "amazon-cloudwatch-agent.log", 492 | "log_stream_name": "amazon-cloudwatch-agent.log", 493 | "timezone": "UTC" 494 | }, 495 | { 496 | "file_path": "/var/log/cloud-init.log", 497 | "log_group_name": "${rCloudWatchLogsAgentGroup}", 498 | "log_stream_name": "{instance_id}/cloud-init.log", 499 | "timezone": "UTC" 500 | }, 501 | { 502 | "file_path": "/var/log/cloud-init-output.log", 503 | "log_group_name": "${rCloudWatchLogsAgentGroup}", 504 | "log_stream_name": "{instance_id}/cloud-init-output.log", 505 | "timezone": "UTC" 506 | }, 507 | { 508 | "file_path": "/var/log/cfn-init.log", 509 | "log_group_name": "${rCloudWatchLogsAgentGroup}", 510 | "log_stream_name": "{instance_id}/cfn-init.log", 511 | "timezone": "UTC" 512 | }, 513 | { 514 | "file_path": "/var/log/cfn-wire.log", 515 | "log_group_name": "${rCloudWatchLogsAgentGroup}", 516 | "log_stream_name": "{instance_id}/cfn-wire.log", 517 | "timezone": "UTC" 518 | }, 519 | { 520 | "file_path": "/var/log/charon.log", 521 | "log_group_name": "${rCloudWatchLogsAgentGroup}", 522 | "log_stream_name": "{instance_id}/charon.log", 523 | "timezone": "UTC" 524 | }, 525 | { 526 | "file_path": "/var/log/quagga/zebra.log", 527 | "log_group_name": "${rCloudWatchLogsAgentGroup}", 528 | "log_stream_name": "{instance_id}/zebra.log", 529 | "timezone": "UTC" 530 | }, 531 | { 532 | "file_path": "/var/log/quagga/bgpd.log", 533 | "log_group_name": "${rCloudWatchLogsAgentGroup}", 534 | "log_stream_name": "{instance_id}/bgpd.log", 535 | "timezone": "UTC" 536 | } 537 | ] 538 | } 539 | }, 540 | "log_stream_name": "${rCloudWatchLogsAgentGroup}", 541 | "force_flush_interval" : 15 542 | } 543 | } 544 | mode: '000444' 545 | owner: root 546 | group: root 547 | 02-restart-cloudwatch-agent: 548 | commands: 549 | 01-stop-service: 550 | command: /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a stop 551 | 02-start-service: 552 | 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 553 | 03-install-epel: 554 | commands: 555 | 01-install-epel: 556 | command: amazon-linux-extras install epel -y 557 | 04-config-vpn-gateway-config: 558 | packages: 559 | yum: 560 | strongswan: [] 561 | quagga: [] 562 | jq: [] 563 | files: 564 | /etc/strongswan/strongswan.conf: 565 | content: | 566 | # strongswan.conf - strongSwan configuration file 567 | # 568 | # Refer to the strongswan.conf(5) manpage for details 569 | # 570 | # Configuration changes should be made in the included files 571 | charon { 572 | plugins { 573 | include strongswan.d/charon/*.conf 574 | } 575 | load_modular = yes 576 | filelog { 577 | charon { 578 | path = /var/log/charon.log 579 | time_format = %b %e %T 580 | ike_name = yes 581 | append = yes 582 | } 583 | } 584 | } 585 | mode: '000600' 586 | owner: root 587 | group: root 588 | /etc/strongswan/ipsec.conf: 589 | content: !Join 590 | - '' 591 | - 592 | - !Sub | 593 | conn %default 594 | leftauth=${pAuthType} 595 | rightauth=${pAuthType} 596 | ike=aes256-sha256-modp2048s256,aes128-sha1-modp1024! 597 | ikelifetime=28800s 598 | aggressive=no 599 | esp=aes128-sha256-modp2048s256,aes128-sha1-modp1024! 600 | lifetime=3600s 601 | type=tunnel 602 | dpddelay=10s 603 | dpdtimeout=30s 604 | keyexchange=ikev1 605 | rekey=yes 606 | reauth=no 607 | dpdaction=restart 608 | closeaction=restart 609 | left=%defaultroute 610 | leftsubnet=0.0.0.0/0,::/0 611 | rightsubnet=0.0.0.0/0,::/0 612 | leftupdown=/etc/strongswan/ipsec-vti.sh 613 | installpolicy=yes 614 | compress=no 615 | mobike=no 616 | 617 | conn AWS-VPC-TUNNEL-1 618 | left=%any 619 | right=${pTunnel1VgwOutsideIpAddress} 620 | auto=start 621 | mark=100 622 | - !If 623 | - cUseCertAuth 624 | - !Sub |2 625 | leftcert=client-public-cert.pem 626 | rightid="CN=${pTunnel1VgwCertDomainName}" 627 | - '' 628 | - !Sub | 629 | 630 | conn AWS-VPC-TUNNEL-2 631 | left=%any 632 | right=${pTunnel2VgwOutsideIpAddress} 633 | auto=start 634 | mark=200 635 | - !If 636 | - cUseCertAuth 637 | - !Sub |2 638 | leftcert=client-public-cert.pem 639 | rightid="CN=${pTunnel2VgwCertDomainName}" 640 | - '' 641 | mode: '000600' 642 | owner: root 643 | group: root 644 | /etc/strongswan/ipsec-vti.sh: 645 | content: !Sub | 646 | #!/bin/bash 647 | 648 | #@ /etc/strongswan/ipsec-vti.sh (Centos) or /etc/strongswan.d/ipsec-vti.sh (Ubuntu) 649 | 650 | # AWS VPC Hardware VPN Strongswan updown Script 651 | 652 | # Usage Instructions: 653 | # Add "install_routes = no" to /etc/strongswan/strongswan.d/charon.conf or /etc/strongswan.d/charon.conf 654 | # Add "install_virtual_ip = no" to /etc/strongswan/strongswan.d/charon.conf or /etc/strongswan.d/charon.conf 655 | # For Ubuntu: Add "leftupdown=/etc/strongswan.d/ipsec-vti.sh" to /etc/ipsec.conf 656 | # For RHEL/Centos: Add "leftupdown=/etc/strongswan/ipsec-vti.sh" to /etc/strongswan/ipsec.conf 657 | # 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 658 | 659 | # Adjust the below according to the Generic Gateway Configuration file provided to you by AWS. 660 | # Sample: http://docs.aws.amazon.com/AmazonVPC/latest/NetworkAdminGuide/GenericConfig.html 661 | 662 | IP=$(which ip) 663 | IPTABLES=$(which iptables) 664 | 665 | PLUTO_MARK_OUT_ARR=(${!PLUTO_MARK_OUT//// }) 666 | PLUTO_MARK_IN_ARR=(${!PLUTO_MARK_IN//// }) 667 | case "$PLUTO_CONNECTION" in 668 | AWS-VPC-TUNNEL-1) 669 | VTI_INTERFACE=vti1 670 | VTI_LOCALADDR=${pTunnel1CgwInsideIpAddress} 671 | VTI_REMOTEADDR=${pTunnel1VgwInsideIpAddress} 672 | ;; 673 | AWS-VPC-TUNNEL-2) 674 | VTI_INTERFACE=vti2 675 | VTI_LOCALADDR=${pTunnel2CgwInsideIpAddress} 676 | VTI_REMOTEADDR=${pTunnel2VgwInsideIpAddress} 677 | ;; 678 | esac 679 | 680 | case "${!PLUTO_VERB}" in 681 | up-client) 682 | #$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]} 683 | $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]} 684 | sysctl -w net.ipv4.conf.${!VTI_INTERFACE}.disable_policy=1 685 | sysctl -w net.ipv4.conf.${!VTI_INTERFACE}.rp_filter=2 || sysctl -w net.ipv4.conf.${!VTI_INTERFACE}.rp_filter=0 686 | $IP addr add ${!VTI_LOCALADDR} remote ${!VTI_REMOTEADDR} dev ${!VTI_INTERFACE} 687 | $IP link set ${!VTI_INTERFACE} up mtu 1436 688 | $IPTABLES -t mangle -I FORWARD -o ${!VTI_INTERFACE} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu 689 | $IPTABLES -t mangle -I INPUT -p esp -s ${!PLUTO_PEER} -d ${!PLUTO_ME} -j MARK --set-xmark ${!PLUTO_MARK_IN} 690 | $IP route flush table 220 691 | #/etc/init.d/bgpd reload || /etc/init.d/quagga force-reload bgpd 692 | ;; 693 | down-client) 694 | #$IP tunnel del ${!VTI_INTERFACE} 695 | $IP link del ${!VTI_INTERFACE} 696 | $IPTABLES -t mangle -D FORWARD -o ${!VTI_INTERFACE} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu 697 | $IPTABLES -t mangle -D INPUT -p esp -s ${!PLUTO_PEER} -d ${!PLUTO_ME} -j MARK --set-xmark ${!PLUTO_MARK_IN} 698 | ;; 699 | esac 700 | mode: '000700' 701 | owner: root 702 | group: root 703 | /etc/quagga/zebra.conf: 704 | content: | 705 | hostname {HOSTNAME} 706 | password zebra 707 | enable password zebra 708 | ! 709 | log file /var/log/quagga/zebra.log 710 | ! 711 | ! Configure interfaces 712 | interface lo 713 | ! Change preferred source ip address of received routes 714 | route-map RM_SET_SRC permit 10 715 | set src {PRIVATE_IP} 716 | ip protocol bgp route-map RM_SET_SRC 717 | ! 718 | line vty 719 | mode: '000600' 720 | owner: quagga 721 | group: quagga 722 | /etc/quagga/bgpd.conf: 723 | content: !Sub | 724 | hostname bgpd 725 | password zebra 726 | enable password zebra 727 | ! 728 | log file /var/log/quagga/bgpd.log 729 | ! 730 | debug bgp events 731 | debug bgp filters 732 | debug bgp fsm 733 | debug bgp keepalives 734 | debug bgp updates 735 | ! 736 | router bgp ${pLocalBgpAsn} 737 | bgp router-id {PRIVATE_IP} 738 | network ${pVpcCidr} 739 | neighbor ${pTunnel1BgpNeighborIpAddress} remote-as ${pTunnel1VgwBgpAsn} 740 | neighbor ${pTunnel2BgpNeighborIpAddress} remote-as ${pTunnel2VgwBgpAsn} 741 | neighbor ${pTunnel2BgpNeighborIpAddress} route-map RM_LOWER_PRIORITY out 742 | ! 743 | route-map RM_LOWER_PRIORITY permit 10 744 | set as-path prepend ${pLocalBgpAsn} ${pLocalBgpAsn} ${pLocalBgpAsn} 745 | ! 746 | line vty 747 | mode: '000600' 748 | owner: quagga 749 | group: quagga 750 | /etc/sysctl.conf: 751 | content: | 752 | # sysctl settings are defined through files in 753 | # /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/. 754 | # 755 | # Vendors settings live in /usr/lib/sysctl.d/. 756 | # To override a whole file, create a new file with the same in 757 | # /etc/sysctl.d/ and put new settings there. To override 758 | # only specific settings, add a file with a lexically later 759 | # name in /etc/sysctl.d/ and put new settings there. 760 | # 761 | # For more information, see sysctl.conf(5) and sysctl.d(5). 762 | 763 | net.ipv4.ip_forward = 1 764 | net.ipv4.conf.all.send_redirects = 0 765 | net.ipv4.conf.default.send_redirects = 0 766 | net.ipv4.tcp_max_syn_backlog = 1280 767 | net.ipv4.icmp_echo_ignore_broadcasts = 1 768 | net.ipv4.conf.all.accept_source_route = 0 769 | net.ipv4.conf.all.accept_redirects = 0 770 | net.ipv4.conf.all.secure_redirects = 0 771 | net.ipv4.conf.all.log_martians = 1 772 | net.ipv4.conf.default.accept_source_route = 0 773 | net.ipv4.conf.default.accept_redirects = 0 774 | net.ipv4.conf.default.secure_redirects = 0 775 | net.ipv4.icmp_echo_ignore_broadcasts = 1 776 | net.ipv4.icmp_ignore_bogus_error_responses = 1 777 | net.ipv4.tcp_syncookies = 1 778 | net.ipv4.conf.all.rp_filter = 1 779 | net.ipv4.conf.default.rp_filter = 1 780 | net.ipv4.tcp_mtu_probing = 1 781 | mode: '000600' 782 | owner: root 783 | group: root 784 | 05-config-vpn-gateway-secrets-psk: 785 | files: 786 | /etc/strongswan/ipsec.secrets: 787 | content: !Sub | 788 | ${pTunnel1VgwOutsideIpAddress} : PSK "{TUNNEL_1_PSK}" 789 | ${pTunnel2VgwOutsideIpAddress} : PSK "{TUNNEL_2_PSK}" 790 | mode: '000600' 791 | owner: root 792 | group: root 793 | /tmp/set-psk.sh: 794 | content: !Sub | 795 | #!/bin/bash 796 | 797 | for (( i=0; i<2; ++i)); do 798 | TUNNEL_NUM=$((${!i} + 1)) 799 | 800 | if (( $TUNNEL_NUM == 1 )) ; then 801 | SECRET_NAME=${pTunnel1PskSecretName} 802 | else 803 | SECRET_NAME=${pTunnel2PskSecretName} 804 | fi 805 | 806 | PSK=$(aws secretsmanager get-secret-value --secret-id ${!SECRET_NAME} --region ${AWS::Region} | jq -r '.SecretString' | jq -r '.psk') && 807 | 808 | if test -z "$PSK" 809 | then 810 | echo "\$PSK is empty" 811 | exit 1 812 | else 813 | echo "\$PSK is NOT empty" 814 | sed -i -e "s/{TUNNEL_${!TUNNEL_NUM}_PSK}/${!PSK}/" /etc/strongswan/ipsec.secrets 815 | fi 816 | done 817 | mode: '000700' 818 | owner: root 819 | group: root 820 | commands: 821 | 00-set-psk: 822 | command: >- 823 | /tmp/set-psk.sh 824 | 05-config-vpn-gateway-cert-files: 825 | files: 826 | /etc/strongswan/ipsec.d/cacerts/root-ca.pem: 827 | source: !Sub "https://${pCertBucket}.s3.${AWS::Region}.amazonaws.com/${pRootCaCert}" 828 | mode: '000600' 829 | owner: root 830 | group: root 831 | authentication: "S3BucketAccessCredential" 832 | /etc/strongswan/ipsec.d/cacerts/subordinate-ca.pem: 833 | source: !Sub "https://${pCertBucket}.s3.${AWS::Region}.amazonaws.com/${pSubordinateCaCert}" 834 | mode: '000600' 835 | owner: root 836 | group: root 837 | authentication: "S3BucketAccessCredential" 838 | /etc/strongswan/ipsec.d/certs/client-public-cert.pem: 839 | source: !Sub "https://${pCertBucket}.s3.${AWS::Region}.amazonaws.com/${pCgwCert}" 840 | mode: '000600' 841 | owner: root 842 | group: root 843 | authentication: "S3BucketAccessCredential" 844 | /etc/strongswan/ipsec.d/private/client-private-key.pem: 845 | source: !Sub "https://${pCertBucket}.s3.${AWS::Region}.amazonaws.com/${pCgwPrivateKey}" 846 | mode: '000600' 847 | owner: root 848 | group: root 849 | authentication: "S3BucketAccessCredential" 850 | /etc/strongswan/ipsec.secrets: 851 | content: | 852 | : RSA client-private-key.pem {PASSPHRASE} 853 | mode: '000600' 854 | owner: root 855 | group: root 856 | /tmp/set-passphrase.sh: 857 | content: !Sub | 858 | #!/bin/bash 859 | 860 | PASSPHRASE=$(aws secretsmanager get-secret-value --secret-id ${pCgwPrivateKeyPassphraseSecretName} --region ${AWS::Region} | jq -r '.SecretString' | jq -r '.passphrase') && 861 | 862 | if test -z "$PASSPHRASE" 863 | then 864 | echo "\$PASSPHRASE is empty" 865 | exit 1 866 | else 867 | echo "\$PASSPHRASE is NOT empty" 868 | sed -i -e "s/{PASSPHRASE}/${!PASSPHRASE}/" /etc/strongswan/ipsec.secrets 869 | fi 870 | mode: '000700' 871 | owner: root 872 | group: root 873 | commands: 874 | 00-set-private-key-passphrase: 875 | command: >- 876 | /tmp/set-passphrase.sh 877 | 06-config-vpn-gateway-commands: 878 | commands: 879 | 00-sed-instance-specific-settings: 880 | command: >- 881 | ipaddr=$(curl 169.254.169.254/latest/meta-data/local-ipv4) && 882 | sed -i -e "s/{PRIVATE_IP}/${ipaddr}/" /etc/quagga/zebra.conf && 883 | sed -i -e "s/{PRIVATE_IP}/${ipaddr}/" /etc/quagga/bgpd.conf && 884 | hostname=$(curl 169.254.169.254/latest/meta-data/local-hostname) && 885 | sed -i -e "s/{HOSTNAME}/${hostname}/" /etc/quagga/zebra.conf 886 | 01-load-sysctl-changes: 887 | command: sysctl -p /etc/sysctl.conf 888 | 02-enable-ip-forwarding: 889 | command: >- 890 | sysctl -w net.ipv4.ip_forward=1 && 891 | sysctl -w net.ipv4.conf.eth0.disable_xfrm=1 && 892 | sysctl -w net.ipv4.conf.eth0.disable_policy=1 893 | 03-enable-start-strongswan: 894 | command: >- 895 | systemctl enable strongswan && 896 | systemctl start strongswan 897 | 04-enable-start-zebra: 898 | command: >- 899 | systemctl enable zebra && 900 | systemctl start zebra 901 | 05-enable-start-bgpd: 902 | command: >- 903 | systemctl enable bgpd && 904 | systemctl start bgpd 905 | 906 | rVpnGatewayEipAssociation: 907 | Type: AWS::EC2::EIPAssociation 908 | Condition: cUseElasticIp 909 | Properties: 910 | AllocationId: !Ref pEipAllocationId 911 | InstanceId: !Ref rVpnGateway 912 | 913 | rVpnGateway: 914 | Type: AWS::EC2::Instance 915 | Properties: 916 | LaunchTemplate: 917 | LaunchTemplateId: 918 | Ref: rLaunchTemplate 919 | Version: 920 | Fn::GetAtt: 921 | [ rLaunchTemplate, LatestVersionNumber ] 922 | NetworkInterfaces: 923 | - DeviceIndex: '0' 924 | SubnetId: !Ref pSubnetId 925 | SourceDestCheck: false 926 | Tags: 927 | - Key: Name 928 | Value: !Sub '${pSystem}-${pApp}-${pEnvPurpose}' 929 | 930 | rVpnGatewayWaitHandle: 931 | Type: AWS::CloudFormation::WaitConditionHandle 932 | 933 | rVpnGatewayWaitCondition1: 934 | Type: AWS::CloudFormation::WaitCondition 935 | DependsOn: rVpnGateway 936 | Properties: 937 | Handle: 938 | Ref: rVpnGatewayWaitHandle 939 | Timeout: '600' 940 | Count: 1 941 | 942 | rRole: 943 | Type: AWS::IAM::Role 944 | Properties: 945 | RoleName: !Sub '${pOrg}-${pSystem}-${pApp}-${pEnvPurpose}-${AWS::Region}-svc-cloud-watch-ssm' 946 | Path: !Sub '/${pOrg}/${pSystem}/${pApp}/' 947 | AssumeRolePolicyDocument: 948 | Version: 2012-10-17 949 | Statement: 950 | - 951 | Effect: Allow 952 | Principal: 953 | Service: ec2.amazonaws.com 954 | Action: sts:AssumeRole 955 | ManagedPolicyArns: 956 | - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore 957 | - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy 958 | 959 | rPolicyS3: 960 | Type: AWS::IAM::Policy 961 | Condition: cUseCertAuth 962 | Properties: 963 | PolicyName: !Sub '${pOrg}-${pSystem}-${pApp}-${pEnvPurpose}-s3-read-only' 964 | PolicyDocument: 965 | Version: 2012-10-17 966 | Statement: 967 | - Effect: Allow 968 | Action: 969 | - s3:GetObject 970 | Resource: !Sub 'arn:aws:s3:::${pCertBucket}/*' 971 | Roles: 972 | - !Ref rRole 973 | 974 | rPolicySecretsManagerCertAuth: 975 | Type: AWS::IAM::Policy 976 | Condition: cUseCertAuth 977 | Properties: 978 | PolicyName: !Sub '${pOrg}-${pSystem}-${pApp}-${pEnvPurpose}-secrets-manager-read-only' 979 | PolicyDocument: 980 | Version: 2012-10-17 981 | Statement: 982 | - Effect: Allow 983 | Action: 984 | - secretsmanager:GetSecretValue 985 | - secretsmanager:DescribeSecret 986 | Resource: !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${pCgwPrivateKeyPassphraseSecretName}-*' 987 | Roles: 988 | - !Ref rRole 989 | 990 | rPolicySecretsManagerPskAuth: 991 | Type: AWS::IAM::Policy 992 | Condition: cUsePskAuth 993 | Properties: 994 | PolicyName: !Sub '${pOrg}-${pSystem}-${pApp}-${pEnvPurpose}-secrets-manager-read-only' 995 | PolicyDocument: 996 | Version: 2012-10-17 997 | Statement: 998 | - Effect: Allow 999 | Action: 1000 | - secretsmanager:GetSecretValue 1001 | - secretsmanager:DescribeSecret 1002 | Resource: 1003 | - !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${pTunnel1PskSecretName}-*' 1004 | - !Sub 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${pTunnel2PskSecretName}-*' 1005 | Roles: 1006 | - !Ref rRole 1007 | 1008 | rInstanceProfile: 1009 | Type: AWS::IAM::InstanceProfile 1010 | Properties: 1011 | InstanceProfileName: !Sub '${pSystem}-${pApp}-${pEnvPurpose}-${AWS::Region}' 1012 | Path: !Sub '/${pOrg}/${pSystem}/${pApp}/' 1013 | Roles: 1014 | - !Ref rRole 1015 | 1016 | rCloudWatchLogsAgentGroup: 1017 | Type: AWS::Logs::LogGroup 1018 | Properties: 1019 | LogGroupName: !Sub '/${pSystem}/${pApp}/ec2/${pEnvPurpose}' 1020 | RetentionInDays: 30 --------------------------------------------------------------------------------