Browse Source

Archives the Cisco VPN Module; Unarchives the AWS VPN Module for Another Look

Fred Damstra [afs macbook] 3 years ago
parent
commit
5d16b37ade
31 changed files with 2846 additions and 26 deletions
  1. 0 0
      base/_archive/cisco_vpn/files/userdata.tpl
  2. 24 26
      base/_archive/cisco_vpn/main.tf
  3. 0 0
      base/_archive/cisco_vpn/outputs.tf
  4. 4 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/.gitignore
  5. 4 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/.gitmodules
  6. 24 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/.taskcat.yml
  7. 6 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/CHANGELOG.XDR.md
  8. 201 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/LICENSE.txt
  9. 7 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/NOTICE.txt
  10. 7 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/README.XDR.md
  11. 37 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/README.md
  12. 2 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/SOURCE
  13. BIN
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/functions/packages/lambda.zip
  14. 49 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/functions/source/lambda_function.py
  15. 314 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/copy-lambdas.yaml
  16. 110 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/quickstart-cisco-asav-ravpn-common.yaml
  17. 468 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/quickstart-cisco-asav-ravpn-instance.yaml
  18. 879 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/quickstart-cisco-asav-ravpn-main.yaml
  19. 710 0
      base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/quickstart-cisco-asav-ravpn-tgw.yaml
  20. 0 0
      base/_archive/cisco_vpn/security-groups.tf
  21. 0 0
      base/_archive/cisco_vpn/vars.tf
  22. 0 0
      base/aws_client_vpn/README.md
  23. 0 0
      base/aws_client_vpn/auth.tf
  24. 0 0
      base/aws_client_vpn/certificate.tf
  25. 0 0
      base/aws_client_vpn/cloudwatch.tf
  26. 0 0
      base/aws_client_vpn/files/saml-metadata-okta-test.xml
  27. 0 0
      base/aws_client_vpn/saml.tf
  28. 0 0
      base/aws_client_vpn/security-groups.tf
  29. 0 0
      base/aws_client_vpn/terragrunt.hcl.example
  30. 0 0
      base/aws_client_vpn/vars.tf
  31. 0 0
      base/aws_client_vpn/vpn.tf

+ 0 - 0
base/cisco_vpn/files/userdata.tpl → base/_archive/cisco_vpn/files/userdata.tpl


+ 24 - 26
base/cisco_vpn/main.tf → base/_archive/cisco_vpn/main.tf

@@ -121,29 +121,27 @@ resource "aws_instance" "instance" {
   volume_tags = merge( var.standard_tags, var.tags, { Name = var.instance_name })
 }
 
-# TODO: How to get the private IP addresses?
-#module "private_dns_record" {
-#  source = "../../submodules/dns/private_A_record"
-#
-#  name = var.instance_name
-#  ip_addresses = [ aws_instance.instance.private_ip ]
-#  dns_info = var.dns_info
-#  reverse_enabled = var.reverse_enabled
-#
-#  providers = {
-#    aws.c2 = aws.c2
-#  }
-#}
-#
-#module "public_dns_record" {
-#  source = "../../submodules/dns/public_A_record"
-#
-#  name = var.instance_name
-#  ip_addresses = [ aws_eip.instance.public_ip ]
-#  dns_info = var.dns_info
-#
-#  providers = {
-#    aws.mdr-common-services-commercial = aws.mdr-common-services-commercial
-#  }
-#}
-#
+module "private_dns_record" {
+  source = "../../submodules/dns/private_A_record"
+
+  name = var.instance_name
+  ip_addresses = [ aws_network_interface.management.private_ip ]
+  dns_info = var.dns_info
+  reverse_enabled = true
+
+  providers = {
+    aws.c2 = aws.c2
+  }
+}
+
+module "public_dns_record" {
+  source = "../../submodules/dns/public_A_record"
+
+  name = var.instance_name
+  ip_addresses = [ aws_eip.outside.public_ip ]
+  dns_info = var.dns_info
+
+  providers = {
+    aws.mdr-common-services-commercial = aws.mdr-common-services-commercial
+  }
+}

+ 0 - 0
base/cisco_vpn/outputs.tf → base/_archive/cisco_vpn/outputs.tf


+ 4 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/.gitignore

@@ -0,0 +1,4 @@
+.taskcat
+taskcat_outputs/
+taskcat_outputs/index.html
+cfn-lint.txt

+ 4 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/.gitmodules

@@ -0,0 +1,4 @@
+[submodule "submodules/quickstart-aws-vpc"]
+	path = submodules/quickstart-aws-vpc
+	url = git@github.com:aws-quickstart/quickstart-aws-vpc.git
+	branch = main

+ 24 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/.taskcat.yml

@@ -0,0 +1,24 @@
+project:
+  name: quickstart-cisco-asav-ravpn
+  regions:
+   - us-east-1
+  package_lambda: false
+tests:
+  2AZ-test:
+    template: ./templates/quickstart-cisco-asav-ravpn-main.yaml
+    # s3_bucket: maq-cisco-ravpn-quickstart
+    parameters:
+      NumberOfAZs: 2
+      NumberOfASAv: 2
+      KeyPair: sshvans
+      AvailabilityZones: $[taskcat_getaz_2] #to be used with 1 or 2 ASAv
+      #AvailabilityZones: $[taskcat_getaz_3] #to be used with 3 ASAv
+      # AvailabilityZones: $[taskcat_getaz_4] #to be used with 4 ASAv
+      QSS3BucketName: $[taskcat_autobucket]
+      QSS3BucketRegion: $[taskcat_current_region]
+      VPNUser: muffadal
+      VPNPassword: "" # provide your own password
+      OnPremFirewallPublicIP: 4.4.4.4
+      OnPremCIDR: 192.168.128.0/24
+      DnsName: example4.com
+      SSHLockDownCIDR: 0.0.0.0/0

+ 6 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/CHANGELOG.XDR.md

@@ -0,0 +1,6 @@
+Original source: https://github.com/aws-quickstart/quickstart-cisco-asav-ravpn
+
+With lots of changes because the original is intended to do ... just about everything, from create a VPC to standing up a route 53 zone to adding a transit gateway. Way more than we want.
+
+* Added this file
+

+ 201 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/LICENSE.txt

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 7 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/NOTICE.txt

@@ -0,0 +1,7 @@
+Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with the License. A copy of the License is located at
+
+    http://aws.amazon.com/apache2.0/
+
+or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

+ 7 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/README.XDR.md

@@ -0,0 +1,7 @@
+# What this is
+
+This is the source for the cloudformation template from Cisco for the Cisco ASAv Remote Access VPN.
+
+Unfortunately, it does far more than we need.. It sets up VPCs, transit gateways, direct connect VPNs, etc...
+
+Kept here for reference.

+ 37 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/README.md

@@ -0,0 +1,37 @@
+# quickstart-cisco-asav-ravpn
+## Cisco Systems on the AWS Cloud
+
+This Quick Start reference deployment guide provides step-by-step instructions for deploying a scalable Cisco Remote Access Virtual Private Network (RA-VPN) on the AWS Cloud. This Quick Start is for users who want to deploy or learn about Cisco AnyConnect RA-VPN services on Cisco Adaptive Security Virtual Appliance (ASAv) firewalls using the AWS Cloud architecture.
+
+### Cisco scalable RA-VPN on AWS
+As companies address the ever-increasing demand for secure remote connectivity, the need for a stable and scalable RA-VPN has increased. For many organizations, investing in additional hardware appliances to scale up a network’s infrastructure may not meet timeline objectives and available budgets. But, cloud-based architectures provide computing environments that are highly scalable and flexible in terms of both costs and resources.
+
+**Note:** This deployment can be integrated with both multi-factor authentication (MFA) and authentication, authorization, and accounting (AAA), such as Cisco Duo. For more information, see Duo MFA on AWS.
+
+Please know that we may share who uses AWS Quick Starts with the AWS Partner that collaborated with AWS on the content of the Quick Start.
+
+### Cost and licenses
+You are responsible for the cost of the AWS services used while running this Quick Start reference deployment. There is no additional cost for using the Quick Start.
+
+The AWS CloudFormation template for this Quick Start includes configuration parameters that you can customize. Some of these settings, such as instance type, affect the cost of deployment. For cost estimates, see the pricing pages for each AWS service you use. Prices are subject to change.
+
+This Quick Start requires an RA-VPN license from Cisco. The Cisco ASAv virtual firewall provides the following licensing options:
+
+- **Option 1:** Use AWS pay-as-you-go licensing, which is based on hourly billing. This is the default option for this Quick Start.
+- **Option 2:** Use Amazon’s Bring Your Own License (BYOL) model in conjunction with Cisco’s Smart Licensing.
+
+To use this Quick Start in a production environment, see [Cisco Adaptive Security Virtual Appliance (ASAv) — Standard Package](https://aws.amazon.com/marketplace/pp/Cisco-Systems-Inc-Cisco-Adaptive-Security-Virtual-/B00WH2LGM0). Ensure that you subscribe to the image using the correct Region. If you want to use option 2, you must use the correct Amazon Machine Image (AMI). For more information, see how to [Deploy the ASAv on the AWS Cloud](https://www.cisco.com/c/en/us/td/docs/security/asa/asa913/asav/getting-started/asav-913-gsg/asav_aws.html).
+
+**Note:** If you don’t have your own license, the ASAv uses a trial license with reduced capacity. It provides 90 days of free usage and up to two AnyConnect VPN sessions within a nonproduction environment where firewall throughput is limited to 100 Kbps. To upgrade to a production license, see the [Cisco documentation](https://www.cisco.com/c/en/us/td/docs/security/asa/asa913/configuration/general/asa-913-general-config/intro-license-smart.html#task_03242D29B58D4DB9B95F4F844973CE2E).
+
+This Quick Start requires a subscription to the Amazon Machine Image (AMI) for Cisco RA VPN, which is available from [AWS Marketplace](https://aws.amazon.com/marketplace/pp/Cisco-Systems-Inc-Cisco-Adaptive-Security-Virtual-/B00WH2LGM0). Additional pricing, terms, and conditions may apply. For more information, see the [deployment guide](https://fwd.aws/Ebm5R).
+
+### Architecture
+Deploying this Quick Start with **default parameters** builds the following environment in a specific account and Region in the AWS Cloud.
+![quickstart-sumo-logic-security-integrations](https://d0.awsstatic.com/partner-network/QuickStart/datasheets/cisco-asav-ravpn-architecture-diagram.png)
+
+For architectural details, best practices, step-by-step instructions, and customization options, see the [deployment guide](https://fwd.aws/Ebm5R).
+
+To post feedback, submit feature ideas, or report bugs, use the **Issues** section of this GitHub repo.
+
+If you want to submit code for this Quick Start, see the [AWS Quick Start Contributor's Guide](https://aws-quickstart.github.io/).

+ 2 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/SOURCE

@@ -0,0 +1,2 @@
+origin	https://github.com/aws-quickstart/quickstart-cisco-asav-ravpn.git (fetch)
+origin	https://github.com/aws-quickstart/quickstart-cisco-asav-ravpn.git (push)

BIN
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/functions/packages/lambda.zip


+ 49 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/functions/source/lambda_function.py

@@ -0,0 +1,49 @@
+import json
+import logging
+import boto3
+import cfnresponse
+
+logger = logging.getLogger()
+logger.setLevel(logging.INFO)
+
+def get_vpn_attachment_ids(vpn_id, stackName):
+    try:
+      myDict = {}
+      client = boto3.client('ec2')
+      vpn = client.describe_vpn_connections(VpnConnectionIds=[vpn_id])['VpnConnections']
+      tgw = client.describe_transit_gateway_attachments()['TransitGatewayAttachments']
+      rtb = client.describe_transit_gateway_route_tables()["TransitGatewayRouteTables"]
+      logger.info(vpn)
+      for index in range(len(vpn)):
+        mylist = []
+        for vgwTelemetry in vpn[index]['VgwTelemetry']:
+          mylist.append(vgwTelemetry['OutsideIpAddress'])
+        myDict['vpn'+str(index)+'OutsideIps']=mylist
+      #Get vpn tgw attachment ids
+      for dictionary in tgw:
+        if dictionary["ResourceId"] == vpn_id:
+          myDict["vpn1_tgw_attachment_id"] = dictionary['TransitGatewayAttachmentId']
+      #Get rtb ids
+      for dictionary in rtb:
+        if dictionary["Tags"]:
+          for tagsdictionary in dictionary["Tags"]:
+            if stackName+"-Securityrtb" in tagsdictionary['Value']:
+              myDict["security_tgw_rtb_id"] = dictionary['TransitGatewayRouteTableId']
+    except Exception as e:
+      logger.info('get vpn tgw attachment id failure: {}'.format(e))
+
+    return myDict
+
+def lambda_handler(event, context):
+    logger.info('got event {}'.format(event))
+    responseData = {}
+    
+    if event['RequestType'] == 'Create':
+      responseData = get_vpn_attachment_ids(event['ResourceProperties']['vpn_id'],event['ResourceProperties']['stackName'])
+    
+    else: # delete / update
+      rs = event['PhysicalResourceId'] 
+      responseData['TransitGatewayAttributes'] = rs
+    
+    logger.info('responseData {}'.format(responseData))
+    cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)

+ 314 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/copy-lambdas.yaml

@@ -0,0 +1,314 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Description: This template creates an S3 bucket in the same region where the stack is launched and copy the Lambda functions code from original bucket to the new bucket. (qs-1qp7e9tkk)
+Parameters:
+  QSS3BucketName:
+    AllowedPattern: "^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$"
+    ConstraintDescription: S3 bucket name can include numbers, lowercase letters,uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
+    Default: ravpn-quickstart-test
+    Description: Alphanumeric string which identifies the S3 bucket name for the QuickStart assets. It's the bucket to store the copy of the Quick Start assets if you decided to customize or extend them for your own use.
+    Type: String
+  QSS3KeyPrefix:
+    AllowedPattern: "^[0-9a-zA-Z-/._]*$"
+    ConstraintDescription: S3 key prefix can include numbers, lowercase letters, uppercaseletters, hyphens (-), and forward slash (/).
+    Default: quickstart-cisco-asav-ravpn/
+    Description: Alphanumeric string which identifies the S3 key prefix used to simulate a folder for your copy of the Quick Start assets if you decided to customize or extend them for your own use.
+    Type: String
+Resources:
+  CopyObjects:
+    Properties:
+      ServiceToken:
+        Fn::GetAtt:
+        - CopyObjectsFunction
+        - Arn
+      DestBucket:
+        Ref: LambdaZipsBucket
+      Objects:
+      - functions/packages/lambda.zip
+      SourceBucket:
+        Ref: QSS3BucketName
+      Prefix:
+        Ref: QSS3KeyPrefix
+    Type: AWS::CloudFormation::CustomResource
+  CopyObjectsFunction:
+    Properties:
+      Code:
+        ZipFile:
+          Fn::Join:
+          - "\n"
+          - - import json
+            - import logging
+            - import threading
+            - import boto3
+            - import cfnresponse
+            - ''
+            - ''
+            - 'def copy_objects(source_bucket, dest_bucket, prefix, objects):'
+            - "    s3 = boto3.client('s3')"
+            - "    for o in objects:"
+            - "        key = prefix + o"
+            - "        copy_source = {"
+            - "            'Bucket': source_bucket,"
+            - "            'Key': key"
+            - "        }"
+            - "        s3.copy_object(CopySource=copy_source, Bucket=dest_bucket,
+              Key=key)"
+            - ''
+            - ''
+            - 'def delete_objects(bucket):'
+            - "    client = boto3.client('s3')"
+            - '    print(("Collecting data from" + bucket))'
+            - "    paginator = client.get_paginator('list_object_versions')"
+            - "    result = paginator.paginate(Bucket=bucket)"
+            - "    objects = []"
+            - "    for page in result:"
+            - "        try:"
+            - "            for k in page['Versions']:"
+            - "                objects.append({'Key':k['Key'],'VersionId': k['VersionId']})"
+            - "            try:"
+            - "                for k in page['DeleteMarkers']:"
+            - "                    version = k['VersionId']"
+            - "                    key = k['Key']"
+            - "                    objects.append({'Key': key,'VersionId': version})"
+            - "            except:"
+            - "                pass"
+            - '            print("deleting objects")'
+            - "            client.delete_objects(Bucket=bucket,     Delete={'Objects':
+              objects})"
+            - "           # objects = []"
+            - "        except:"
+            - "            pass"
+            - '    print("bucket already empty")'
+            - ''
+            - ''
+            - ''
+            - 'def timeout(event, context):'
+            - "    logging.error('Execution is about to time out, sending failure
+              response to CloudFormation')"
+            - "    cfnresponse.send(event, context, cfnresponse.FAILED, {}, None)"
+            - ''
+            - ''
+            - 'def handler(event, context):'
+            - "    # make sure we send a failure to CloudFormation if the function
+              is going to timeout"
+            - "    timer = threading.Timer((context.get_remaining_time_in_millis()
+              / 1000.00) - 0.5, timeout, args=[event, context])"
+            - "    timer.start()"
+            - ''
+            - "    print(('Received event: %s' % json.dumps(event)))"
+            - "    status = cfnresponse.SUCCESS"
+            - "    try:"
+            - "        source_bucket = event['ResourceProperties']['SourceBucket']"
+            - "        dest_bucket = event['ResourceProperties']['DestBucket']"
+            - "        prefix = event['ResourceProperties']['Prefix']"
+            - "        objects = event['ResourceProperties']['Objects']"
+            - "        if event['RequestType'] == 'Delete':"
+            - "            delete_objects(dest_bucket)"
+            - "        else:"
+            - "            copy_objects(source_bucket, dest_bucket, prefix, objects)"
+            - "    except Exception as e:"
+            - "        logging.error('Exception: %s' % e, exc_info=True)"
+            - "        status = cfnresponse.FAILED"
+            - "    finally:"
+            - "        timer.cancel()"
+            - "        cfnresponse.send(event, context, status, {}, None)"
+            - ''
+      Description: Copies objects from a source S3 bucket to a destination S3 bucket
+      Handler: index.handler
+      Role:
+        Fn::GetAtt:
+        - CopyObjectsRole
+        - Arn
+      Runtime: python3.7
+      Timeout: 240
+    Type: AWS::Lambda::Function
+  CopyObjectsRole:
+    Properties:
+      AssumeRolePolicyDocument:
+        Statement:
+        - Action: sts:AssumeRole
+          Effect: Allow
+          Principal:
+            Service: lambda.amazonaws.com
+        Version: '2012-10-17'
+      ManagedPolicyArns:
+      - !Sub arn:${AWS::Partition}:iam::${AWS::Partition}:policy/service-role/AWSLambdaBasicExecutionRole
+      Path: "/"
+      Policies:
+      - PolicyDocument:
+          Statement:
+          - Action:
+            - s3:GetObject
+            Effect: Allow
+            Resource:
+            - Fn::Sub: arn:${AWS::Partition}:s3:::${QSS3BucketName}/${QSS3KeyPrefix}*
+          - Action:
+            - s3:PutObject
+            - s3:DeleteObject
+            - s3:GetObject
+            - s3:ListBucket
+            - s3:ListBucketVersions
+            - s3:DeleteObjectVersion
+            - s3:GetObjectVersion
+            - s3:GetBucketVersioning
+            Effect: Allow
+            Resource:
+            - Fn::Sub: arn:${AWS::Partition}:s3:::${LambdaZipsBucket}/${QSS3KeyPrefix}*
+            - Fn::Sub: arn:${AWS::Partition}:s3:::${LambdaZipsBucket}
+          Version: '2012-10-17'
+        PolicyName: object-copier
+    Type: AWS::IAM::Role
+  LambdaZipsBucket:
+    Properties:
+      Tags: []
+      VersioningConfiguration:
+        Status: Enabled
+    Type: AWS::S3::Bucket
+  CleanUpS3Bucket:
+    Properties:
+      DestBucket:
+        Ref: LambdaZipsBucket
+      ServiceToken:
+        Fn::GetAtt:
+        - CleanUpS3BucketFunction
+        - Arn
+    Type: AWS::CloudFormation::CustomResource
+  CleanUpS3BucketFunction:
+    Properties:
+      Code:
+        ZipFile:
+          Fn::Join:
+          - "\n"
+          - - import json
+            - import logging
+            - import threading
+            - import boto3
+            - import cfnresponse
+            - client = boto3.client('s3')
+            - ''
+            - ''
+            - 'def delete_NonVersionedobjects(bucket):'
+            - '    print(("Collecting data from" + bucket))'
+            - "    paginator =     client.get_paginator('list_objects_v2')"
+            - "    result = paginator.paginate(Bucket=bucket)"
+            - "    objects = []"
+            - "    for page in result:"
+            - "        try:"
+            - "            for k in page['Contents']:"
+            - "                objects.append({'Key': k['Key']})"
+            - '                print("deleting objects")'
+            - "                client.delete_objects(Bucket=bucket, Delete={'Objects':
+              objects})"
+            - "                objects = []"
+            - "        except:"
+            - "            pass"
+            - '            print("bucket is already empty")'
+            - ''
+            - 'def delete_versionedobjects(bucket):'
+            - '    print(("Collecting data from" + bucket))'
+            - "    paginator = client.get_paginator('list_object_versions')"
+            - "    result = paginator.paginate(Bucket=bucket)"
+            - "    objects = []"
+            - "    for page in result:"
+            - "        try:"
+            - "            for k in page['Versions']:"
+            - "                objects.append({'Key':k['Key'],'VersionId': k['VersionId']})"
+            - "            try:"
+            - "                for k in page['DeleteMarkers']:"
+            - "                    version = k['VersionId']"
+            - "                    key = k['Key']"
+            - "                    objects.append({'Key': key,'VersionId': version})"
+            - "            except:"
+            - "                pass"
+            - '            print("deleting objects")'
+            - "            client.delete_objects(Bucket=bucket, Delete={'Objects':
+              objects})"
+            - "           # objects = []"
+            - "        except:"
+            - "            pass"
+            - '    print("bucket already empty")'
+            - ''
+            - ''
+            - ''
+            - 'def timeout(event, context):'
+            - "    logging.error('Execution is about to time out, sending failure
+              response to CloudFormation')"
+            - "    cfnresponse.send(event, context, cfnresponse.FAILED, {}, None)"
+            - ''
+            - ''
+            - 'def handler(event, context):'
+            - "    # make sure we send a failure to CloudFormation if the function
+              is going to timeout"
+            - "    timer = threading.Timer((context.get_remaining_time_in_millis()
+              / 1000.00) - 0.5, timeout, args=[event, context])"
+            - "    timer.start()"
+            - ''
+            - "    print(('Received event: %s' % json.dumps(event)))"
+            - "    status = cfnresponse.SUCCESS"
+            - "    try:"
+            - "        dest_bucket = event['ResourceProperties']['DestBucket']"
+            - "        if event['RequestType'] == 'Delete':"
+            - "            CheckifVersioned = client.get_bucket_versioning(Bucket=dest_bucket)"
+            - "            print(CheckifVersioned)"
+            - "            if 'Status' in CheckifVersioned:"
+            - "                print(CheckifVersioned['Status'])"
+            - '                print ("This is a versioned Bucket")'
+            - "                delete_versionedobjects(dest_bucket)"
+            - "            else:"
+            - '                print("This is not a versioned bucket")'
+            - "                delete_NonVersionedobjects(dest_bucket)"
+            - "        else:"
+            - '            print("Nothing to do")'
+            - "    except Exception as e:"
+            - "        logging.error('Exception: %s' % e, exc_info=True)"
+            - "        status = cfnresponse.FAILED"
+            - "    finally:"
+            - "        timer.cancel()"
+            - "        cfnresponse.send(event, context, status, {}, None)"
+            - ''
+      Description: Empty the S3 Bucket
+      Handler: index.handler
+      Role:
+        Fn::GetAtt:
+        - S3CleanUpRole
+        - Arn
+      Runtime: python3.7
+      Timeout: 240
+    Type: AWS::Lambda::Function
+  S3CleanUpRole:
+    Properties:
+      AssumeRolePolicyDocument:
+        Statement:
+        - Action: sts:AssumeRole
+          Effect: Allow
+          Principal:
+            Service: lambda.amazonaws.com
+        Version: '2012-10-17'
+      ManagedPolicyArns:
+      - !Sub arn:${AWS::Partition}:iam::${AWS::Partition}:policy/service-role/AWSLambdaBasicExecutionRole
+      Path: "/"
+      Policies:
+      - PolicyDocument:
+          Statement:
+          - Action:
+            - s3:PutObject
+            - s3:DeleteObject
+            - s3:GetObject
+            - s3:ListBucket
+            - s3:ListBucketVersions
+            - s3:DeleteObjectVersion
+            - s3:GetObjectVersion
+            - s3:GetBucketVersioning
+            Effect: Allow
+            Resource:
+            - Fn::GetAtt:
+              - LambdaZipsBucket
+              - Arn
+            - Fn::Sub: arn:${AWS::Partition}:s3:::*
+          Version: '2012-10-17'
+        PolicyName: Empty-bucket
+    Type: AWS::IAM::Role
+Outputs:
+  LambdaZipsBucket:
+    Description: S3 Bucket for the Lambda Function Code
+    Value:
+      Ref: LambdaZipsBucket

+ 110 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/quickstart-cisco-asav-ravpn-common.yaml

@@ -0,0 +1,110 @@
+AWSTemplateFormatVersion: 2010-09-09
+Description: >-
+  Cisco Systems - Creates hostedzone, Mgmt route table, and SG. (qs-1qp7e9tna)
+Metadata:
+  ParameterLabels:
+    VPCID:
+      default: VPC ID
+    DnsName:
+      default: Dns name
+    SSHLockDownCIDR:
+      default: SSH Lockdown CIDR
+Parameters:
+  DnsName:
+    Type: String
+    Description: DNS name of PublicHostedZone
+  VPCID:
+    Type: AWS::EC2::VPC::Id
+    Description: Select VPC which ASAv will be deployed in
+  SSHLockDownCIDR:
+    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])(\/([0-9]|1[6-9]|2[0-8]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/0-28
+    Description: CIDR block for locking down the SSH access on the outside interface
+    Type: String
+  
+Resources:
+  PublicHostedZone: 
+    Type: "AWS::Route53::HostedZone"
+    Properties: 
+      HostedZoneConfig: 
+        Comment: 'Hosted zone'
+      Name: !Ref DnsName
+      HostedZoneTags: 
+        - 
+          Key: 'Name'
+          Value: 'ASAvHostedZone'
+  MgmtRouteTable:
+    Type: AWS::EC2::RouteTable
+    Properties:
+      VpcId: !Ref VPCID
+      Tags:
+        - Key: Name
+          Value: MGMT subnet Route Table
+  ASAvInstanceSGMGMT:
+    Type: AWS::EC2::SecurityGroup
+    Properties:
+        GroupDescription: Security Group for ASAv Instances
+        VpcId: !Ref VPCID
+        Tags:
+        - Key: Name
+          Value: "ASAvSecurityGroup"
+        SecurityGroupIngress:
+        - IpProtocol: "TCP"
+          FromPort: 443
+          ToPort: 443
+          CidrIp: 0.0.0.0/0
+        - IpProtocol: "TCP"
+          FromPort: 22
+          ToPort: 22
+          CidrIp: 0.0.0.0/0
+        - IpProtocol: "TCP"
+          FromPort: 80
+          ToPort: 80
+          CidrIp: 0.0.0.0/0
+  ASAvInstanceSGINSIDE:
+    Type: AWS::EC2::SecurityGroup
+    Properties:
+        GroupDescription: Security Group for ASAv Instances
+        VpcId: !Ref VPCID
+        Tags:
+        - Key: Name
+          Value: "ASAvSecurityGroup"
+        SecurityGroupIngress:
+        - IpProtocol: "-1"
+          FromPort: 0
+          ToPort: 65535
+          CidrIp: 0.0.0.0/0
+  ASAvInstanceSGOUTSIDE:
+    Type: AWS::EC2::SecurityGroup
+    Properties:
+        GroupDescription: Security Group for ASAv Instances
+        VpcId: !Ref VPCID
+        Tags:
+        - Key: Name
+          Value: "ASAvSecurityGroup"
+        SecurityGroupIngress:
+        - IpProtocol: "TCP"
+          FromPort: 443
+          ToPort: 443
+          CidrIp: 0.0.0.0/0
+        - IpProtocol: "UDP"
+          FromPort: 443
+          ToPort: 443
+          CidrIp: 0.0.0.0/0
+        - IpProtocol: "TCP"
+          FromPort: 22
+          ToPort: 22
+          CidrIp: !Ref SSHLockDownCIDR
+
+Outputs:
+  PublicHostedZone:
+    Value: !Ref 'PublicHostedZone'
+  MgmtRouteTable:
+    Value: !Ref 'MgmtRouteTable'
+  ASAvInstanceSGMGMT:
+    Value: !Ref 'ASAvInstanceSGMGMT'
+  ASAvInstanceSGOUTSIDE:
+    Value: !Ref 'ASAvInstanceSGOUTSIDE'
+  ASAvInstanceSGINSIDE:
+    Value: !Ref 'ASAvInstanceSGINSIDE'

+ 468 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/quickstart-cisco-asav-ravpn-instance.yaml

@@ -0,0 +1,468 @@
+AWSTemplateFormatVersion: 2010-09-09
+Description: >-
+  Cisco Systems - Creates the necessary policies, roles, security group and
+  launches Cisco ASAv Instance(s). (qs-1qp7e9tnh)
+Metadata:
+  ParameterLabels:
+    InstanceTypeParam:
+      default: ASAv instance type
+    KeyPair:
+      default: keypair name
+    MgmtSubnet1CIDR:
+      default: Mgmt subnet 1
+    PrivateSubnet1ID:
+      default: Private subnet 1
+    PublicSubnet1ID:
+      default: Public subnet 1
+    VPCID:
+      default: VPC ID
+    DnsName:
+      default: Dns name
+    ASAv1HostName:
+      default: ASAv1 Hostname
+    VPNPoolFrom1:
+      default: VPN Pool Start
+    VPNPoolTo1:
+      default: VPN Pool Finish
+    VPNPoolCIDRMask1:
+      default: NETMASK of VPN Pool
+    VPCCIDRMASK:
+      default: netmask of VPCCIDR
+    VPCPOOL:
+      default: pool of VPC
+    VPNUser:
+      default: VPN User
+    VPNPassword:
+      default: VPN Password
+    OnPremCIDRMask:
+      default: onprem network MASK
+    OnPremPool:
+      default: onprem pool
+    PrivateSubnet1GW:
+      default: private subnet GW
+    PrivateSubnet1CIDR:
+      default: private subnet CIDR format
+    PrivateSubnet1Pool:
+      default: Private subnet pool
+    PrivateSubnet1CIDRMask:
+      default: Private subnet mask
+    PublicHostedZone:
+      default: Private hosted zone Id
+    MgmtRouteTable:
+      default: Management route table Id
+    ASAvInstanceSGMGMT:
+      default: ASAv Instance Management Security group Id
+    ASAvInstanceSGOUTSIDE:
+      default: ASAv Instance Outside Security group Id
+    ASAvInstanceSGINSIDE:
+      default: ASAv Instance Inside Security group Id
+Parameters:
+  InstanceTypeParam:
+    Type: String
+    Default: c5.large
+    AllowedValues:
+      - m4.large
+      - m4.xlarge
+      - m4.2xlarge
+      - c3.large
+      - c3.xlarge
+      - c3.2xlarge
+      - c4.large
+      - c4.xlarge
+      - c4.2xlarge
+      - c5.large
+      - c5.xlarge
+      - c5.2xlarge
+    Description: Select an instance size for the ASAv.
+  KeyPair:
+    Type: AWS::EC2::KeyPair::KeyName
+    Description: ASAv instances will launch with this keypair
+  VPCID:
+    Type: AWS::EC2::VPC::Id
+    Description: Select VPC which ASAv will be deployed in
+  VPNUser:
+    Type: String
+    Description: Test VPN Username
+  VPNPassword:
+    Type: String
+    Description: Test VPN Password
+    NoEcho: true
+  MgmtSubnet1CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Description: CIDR block for Mgmt subnet 1 in Availability Zone 1
+    Type: String
+  PrivateSubnet1ID:
+    Type: AWS::EC2::Subnet::Id
+    Description: Private Subnet 1 ID
+  PublicSubnet1ID:
+    Type: AWS::EC2::Subnet::Id
+    Description: Public Subnet 1 ID
+  DnsName:
+    Type: String
+    Description: DNS name of PublicHostedZone
+  ASAv1HostName:
+    Type: String
+    Description: ASAv1 Hostname
+  VPNPoolFrom1:
+    Type: String
+    Description: VPN Pool Start
+  VPNPoolTo1:
+    Type: String
+    Description: VPN Pool Finish
+  VPNPoolCIDRMask1:
+    Type: String
+    Description: NETMASK of VPN CIDR Pool
+  VPCCIDRMASK:
+    Type: String
+    Description: netmask of VPC
+  VPCPOOL:
+    Type: String
+    Description: pool of VPC
+  OnPremCIDRMask:
+    Type: String
+    Description: onprem network MASK
+  OnPremPool:
+    Type: String
+    Description: onprem pool
+  PrivateSubnet1GW:
+    Type: String
+    Description: private subnet GW
+  PrivateSubnet1CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Description: CIDR block for the On-prem network
+    Type: String
+  PrivateSubnet1Pool:
+    Type: String
+    Description: Private subnet pool
+  PrivateSubnet1CIDRMask:
+    Type: String
+    Description: Private subnet mask
+
+  PublicHostedZone:
+    Type: String
+    Description: Resource ID of the Public Hosted Zone
+  MgmtRouteTable:
+    Type: String
+    Description: Resource ID of the Management Route Table
+  ASAvInstanceSGMGMT:
+    Type: String
+    Description: Security Group ID for Management instance
+  ASAvInstanceSGOUTSIDE:
+    Type: String
+    Description: Security Group ID for Outside instance
+  ASAvInstanceSGINSIDE:
+    Type: String
+    Description: Security Group ID for Inside instance
+  InstanceIdentifier:
+    Type: Number
+    Description: RAVPN Instance No.
+Mappings:
+  AWSAMIRegionMap:
+    eu-north-1: 
+      HVM64: ami-005e678f521ec99d0
+    ap-south-1: 
+      HVM64: ami-024dc7bfa98b41ec6
+    eu-west-3: 
+      HVM64: ami-06c7b0231eb402d16
+    eu-west-2: 
+      HVM64: ami-0bec420a926af5be6
+    eu-west-1: 
+      HVM64: ami-09cc7f08a29818836
+    ap-northeast-2: 
+      HVM64: ami-08d0dad22fc46b6d9
+    ap-northeast-1: 
+      HVM64: ami-09bdeeb4666c0bb9d
+    sa-east-1: 
+      HVM64: ami-08e47d7858321f80c
+    ca-central-1: 
+      HVM64: ami-07f9b49973a350949
+    ap-southeast-1: 
+      HVM64: ami-0e397151d9d5c4e82
+    ap-southeast-2: 
+      HVM64: ami-07781517dd89226fb
+    eu-central-1: 
+      HVM64: ami-000b858ff24a0d33f
+    us-east-1: 
+      HVM64: ami-0408c1a8f87e2e0d4
+    us-east-2: 
+      HVM64: ami-06554acf8888fbe0d
+    us-west-1: 
+      HVM64: ami-0312fb96da1e1fe74
+    us-west-2: 
+      HVM64: ami-00a1cfa66bfdcfe76
+  CIDRtoSubnetmask:
+    '16':
+      mask: '255.255.0.0'
+    '17':
+      mask: '255.255.128.0'
+    '18':
+      mask: '255.255.192.0'
+    '19':
+      mask: '255.255.224.0'
+    '20':
+      mask: '255.255.240.0'
+    '21':
+      mask: '255.255.248.0'
+    '22':
+      mask: '255.255.252.0'
+    '23':
+      mask: '255.255.254.0'
+    '24':
+      mask: '255.255.255.0'
+    '25':
+      mask: '255.255.255.128'
+    '26':
+      mask: '255.255.255.192'
+    '27':
+      mask: '255.255.255.224'
+    '28':
+      mask: '255.255.255.240'
+Resources:
+  ASAvDNSRecord:
+    Type: AWS::Route53::RecordSet
+    Properties:
+      HostedZoneId: !Ref PublicHostedZone
+      Name: !Join
+        - '.'
+        - - 'vpn'
+          - !Ref DnsName
+      TTL: 5
+      Type: A
+      HealthCheckId: !Ref R53HealthCheck
+      SetIdentifier: !Sub 'Frontend-${InstanceIdentifier}'
+      Weight: 4
+      ResourceRecords:
+      - !Ref outsideIP
+  R53HealthCheck: 
+    Type: 'AWS::Route53::HealthCheck'
+    Properties: 
+      HealthCheckConfig: 
+        IPAddress: !Ref outsideIP
+        Port: 443
+        Type: HTTPS_STR_MATCH
+        ResourcePath: '/'
+        RequestInterval: 30
+        FailureThreshold: 5
+        MeasureLatency: true
+        SearchString: '+CSCOE+'
+      HealthCheckTags: 
+        - 
+          Key: Name
+          Value: ASAvHealthcheck
+  MgmtSubnet1:
+    Type: AWS::EC2::Subnet
+    Properties:
+      VpcId: !Ref VPCID
+      CidrBlock: !Ref 'MgmtSubnet1CIDR'
+      AvailabilityZone: 
+        Fn::Select: 
+          - !Ref InstanceIdentifier
+          - Fn::GetAZs: ""
+      Tags:
+        - Key: Name
+          Value: !Sub 'Mgmt subnet ${InstanceIdentifier}'
+  MGMTRouteTableAssociation:
+    Type: AWS::EC2::SubnetRouteTableAssociation
+    Properties:
+      SubnetId: !Ref 'MgmtSubnet1'
+      RouteTableId: !Ref 'MgmtRouteTable'
+  outsideIP:
+      Type: AWS::EC2::EIP
+      Properties:
+        Domain: vpc        
+  associateOutsideIP:
+      Type: AWS::EC2::EIPAssociation
+      Properties:
+        AllocationId: !GetAtt outsideIP.AllocationId 
+        NetworkInterfaceId: !Ref outsideENI
+  mgmtENI:
+      Type: AWS::EC2::NetworkInterface
+      Properties:
+         Tags:
+         - Key: Name
+           Value: MgmtEni
+         Description: A nice description.
+         SourceDestCheck: false
+         GroupSet:
+         - !Ref 'ASAvInstanceSGMGMT'
+         SubnetId: !Ref MgmtSubnet1
+  outsideENI:
+      Type: AWS::EC2::NetworkInterface
+      Properties:
+         Tags:
+         - Key: Name
+           Value: OutsideEni
+         Description: A nice description.
+         SourceDestCheck: false
+         GroupSet:
+         - !Ref 'ASAvInstanceSGOUTSIDE'
+         SubnetId: !Ref PublicSubnet1ID
+  InsideENI:
+      Type: AWS::EC2::NetworkInterface
+      Properties:
+         Tags:
+         - Key: Name
+           Value: InsideEni
+         Description: A nice description.
+         SourceDestCheck: false
+         GroupSet:
+         - !Ref 'ASAvInstanceSGINSIDE'
+         SubnetId: !Ref PrivateSubnet1ID
+  ASAvInstance:
+    Type: 'AWS::EC2::Instance'
+    Properties:
+      Tags:
+        - Key: Name
+          Value: !Ref ASAv1HostName
+      InstanceType: !Ref InstanceTypeParam
+      KeyName: !Ref KeyPair
+      ImageId: !FindInMap 
+        - AWSAMIRegionMap
+        - !Ref 'AWS::Region'
+        - HVM64
+      NetworkInterfaces:
+       - NetworkInterfaceId: !Ref 'mgmtENI'
+         DeviceIndex: '0'
+       - NetworkInterfaceId: !Ref 'outsideENI'
+         DeviceIndex: '1'
+       - NetworkInterfaceId: !Ref 'InsideENI'
+         DeviceIndex: '2'
+      UserData:
+        Fn::Base64: !Sub  
+        - |
+          ! ASA Version
+          hostname ${ASAv1HostName}
+          !
+          ip local pool VPN-POOL ${VPNPoolFrom1}-${VPNPoolTo1} mask ${VPNPoolMask1}
+          access-list split standard permit ${VPCPOOL} ${VPCMASK}
+          access-list split standard permit ${OnPremPool} ${OnPremMask} 
+          !
+          username ${VPNUser} password ${VPNPassword}
+          username ${VPNUser} attributes
+          service-type remote-access
+          !
+          int tengi 0/0
+          nameif outside
+          security-level 0
+          ip address dhcp setroute
+          no shut
+          int tengi 0/1
+          nameif inside
+          security-level 100
+          ip address dhcp
+          no shut 
+          interface management0/0
+          nameif management
+          security-level 100
+          ip address dhcp
+          no shut
+          !
+          !
+          webvpn
+          enable outside
+          anyconnect image disk0:/anyconnect-macos-4.8.02045-webdeploy-k9.pkg 1
+          anyconnect enable
+          tunnel-group-list enable
+          group-policy LAB internal
+          group-policy LAB attributes
+          vpn-tunnel-protocol ssl-client ssl-clientless
+          address-pools value VPN-POOL
+          split-tunnel-policy tunnelspecified
+          split-tunnel-network-list value split
+          dynamic-access-policy-record DfltAccessPolicy
+          username admin nopassword privilege 15
+          tunnel-group LAB type remote-access
+          tunnel-group LAB general-attributes
+          default-group-policy LAB
+          address-pool VPN-POOL
+          tunnel-group LAB webvpn-attributes
+          group-alias LAB-VPN enable
+          !
+          dns domain-lookup outside
+          dns server-group DefaultDNS
+          name-server 208.67.222.222
+          name-server 208.67.220.220
+          !
+          same-security-traffic permit inter-interface
+          same-security-traffic permit intra-interface
+          !
+          route inside ${OnPremPool} ${OnPremMask} ${PrivateSubnet1GW}
+          !
+          policy-map global_policy
+          class inspection_default
+            inspect icmp
+          !
+          access-list 101 extended permit ip any any 
+          access-group 101 in interface outside
+          access-group 101 in interface inside
+          !
+          object network NET-${PrivateSubnet1CIDR}
+          subnet ${PrivateSubnet1Pool} ${PrivateSubnet1Mask}
+          nat (inside,outside) dynamic interface
+          !
+          crypto key generate rsa modulus 2048
+          ssh 0 0 inside
+          ssh 0 0 outside
+          ssh 0 0 management
+          ssh timeout 30
+          aaa authentication ssh console LOCAL
+          username admin nopassword privilege 15
+          username admin attributes
+          service-type admin
+          !
+          name 129.6.15.28 time-a.nist.gov
+          name 129.6.15.29 time-b.nist.gov
+          name 129.6.15.30 time-c.nist.gov
+          ntp server time-c.nist.gov
+          ntp server time-b.nist.gov
+          ntp server time-a.nist.gov
+          icmp permit any outside
+          icmp permit any inside
+          icmp permit any management
+          !
+        - VPCMASK: !FindInMap
+          - CIDRtoSubnetmask
+          - !Ref VPCCIDRMASK
+          - mask
+          VPNPoolMask1: !FindInMap
+          - CIDRtoSubnetmask
+          - !Ref VPNPoolCIDRMask1
+          - mask
+          OnPremMask: !FindInMap
+          - CIDRtoSubnetmask
+          - !Ref OnPremCIDRMask
+          - mask
+          PrivateSubnet1Mask: !FindInMap
+          - CIDRtoSubnetmask
+          - !Ref PrivateSubnet1CIDRMask
+          - mask  
+Outputs:
+  AccountId:
+    Description: Amazon Account ID
+    Value: !Ref 'AWS::AccountId'
+  MgmtSubnet1CIDR:
+    Description: Mgmt subnet CIDR
+    Value: !Ref 'MgmtSubnet1CIDR'
+  MgmtSubnet1ID:
+    Description: Mgmt subnet ID
+    Value: !Ref 'MgmtSubnet1'
+  InsideENI:
+    Description: ASAv Instance Inside Network Interface ID
+    Value: !Ref 'InsideENI'
+  ASAv1MGMTIP:
+    Description: ASAv Instance Management IP
+    Value: !GetAtt mgmtENI.PrimaryPrivateIpAddress
+  ASAv1PublicIP:
+    Description: ASAv Instance Public IP
+    Value: !Ref outsideIP
+  VPNPoolFrom1:
+    Description: ASAv Instance VPN Pool From
+    Value: !Ref VPNPoolFrom1
+  VPNPoolTo1:
+    Description: ASAv Instance VPN Pool To
+    Value: !Ref VPNPoolTo1
+  VPNPoolCIDRMask1:
+    Description: ASAv Instance VPN Pool Mask
+    Value: !Ref VPNPoolCIDRMask1

+ 879 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/quickstart-cisco-asav-ravpn-main.yaml

@@ -0,0 +1,879 @@
+AWSTemplateFormatVersion: 2010-09-09
+Description: >-
+  Cisco Systems - Main Stack - Creates VPC and the necessary policies, roles,
+  security group and launches the Cisco ASAv RAVPN instances. **WARNING** You
+  will be billed for the AWS resources used if you create a stack from this
+  template. (qs-1qp7e9tnp)
+Metadata:
+  'AWS::CloudFormation::Interface':
+    ParameterGroups:
+      - Label:
+          default: Availability Zone Configuration
+        Parameters:
+          - AvailabilityZones
+          - NumberOfAZs
+      - Label:
+          default: VPC Network Configuration
+        Parameters:
+          - VPCCIDR
+          - PublicSubnet1CIDR
+          - PublicSubnet2CIDR
+          - PublicSubnet3CIDR
+          - PublicSubnet4CIDR
+          - PrivateSubnet1CIDR
+          - PrivateSubnet2CIDR
+          - PrivateSubnet3CIDR        
+          - PrivateSubnet4CIDR       
+      - Label:
+          default: ASAv Configuration
+        Parameters:
+          - NumberOfASAv
+          - ASAv1HostName
+          - ASAv2HostName
+          - ASAv3HostName
+          - ASAv4HostName
+          - DnsName
+          - InstanceTypeParam
+          - KeyPair
+          - VPNUser
+          - VPNPassword
+          - SSHLockDownCIDR
+          - MgmtSubnet1CIDR
+          - MgmtSubnet2CIDR
+          - MgmtSubnet3CIDR
+          - MgmtSubnet4CIDR
+          - VPNPoolCIDR1
+          - VPNPoolCIDR2
+          - VPNPoolCIDR3
+          - VPNPoolCIDR4
+      - Label:
+          default: AWS Transit Gateway configuration
+        Parameters:
+          - TGWSubnet1CIDR
+          - TGWSubnet2CIDR
+          - TGWSubnet3CIDR
+          - TGWSubnet4CIDR
+          - AmazonSideAsn
+      - Label:
+          default: On-Premises Gateway Configuration
+        Parameters:
+          - OnPremFirewallPublicIP
+          - OnPremFirewallASN
+          - PreSharedKeyForVPNAttachment
+          - VPNTunnelCIDRs
+          - OnPremCIDR
+      - Label:
+          default: AWS Quick Start Configuration
+        Parameters:
+          - QSS3BucketName
+          - QSS3BucketRegion
+          - QSS3KeyPrefix
+    ParameterLabels: 
+      AvailabilityZones:
+        default: Availability Zones
+      NumberOfAZs:
+        default: Number of Availability Zones 
+      VPCCIDR:
+        default: VPC CIDR
+      PublicSubnet1CIDR:
+        default: Public subnet 1 CIDR
+      PublicSubnet2CIDR:
+        default: Public subnet 2 CIDR
+      PublicSubnet3CIDR:
+        default: Public subnet 3 CIDR
+      PublicSubnet4CIDR:
+        default: Public subnet 4 CIDR
+      PrivateSubnet1CIDR:
+        default: Private subnet 1 CIDR
+      PrivateSubnet2CIDR:
+        default: Private subnet 2 CIDR
+      PrivateSubnet3CIDR:
+        default: Private subnet 3 CIDR
+      PrivateSubnet4CIDR:
+        default: Private subnet 4 CIDR
+      NumberOfASAv:
+        default: Number of ASAv instances
+      ASAv1HostName:
+        default: ASAv1 hostname
+      ASAv2HostName:
+        default: ASAv2 hostname
+      ASAv3HostName:
+        default: ASAv3 hostname
+      ASAv4HostName:
+        default: ASAv4 hostname
+      DnsName:
+        default: DNS name
+      InstanceTypeParam:
+        default: Instance type of ASAv
+      VPNUser:
+        default: VPN user
+      VPNPassword:
+        default: VPN password
+      KeyPair:
+        default: ASAv instance key pair
+      SSHLockDownCIDR:
+        default: SSH lockdown CIDR
+      MgmtSubnet1CIDR:
+        default: Management subnet 1 CIDR
+      MgmtSubnet2CIDR:
+        default: Management subnet 2 CIDR
+      MgmtSubnet3CIDR:
+        default: Management subnet 3 CIDR
+      MgmtSubnet4CIDR:
+        default: Management subnet 4 CIDR
+      VPNPoolCIDR1:
+        default: VPN pool for ASAv1
+      VPNPoolCIDR2:
+        default: VPN pool for ASAv2
+      VPNPoolCIDR3:
+        default: VPN pool for ASAv3
+      VPNPoolCIDR4:
+        default: VPN pool for ASAv4
+      QSS3BucketName:
+        default: Quick Start S3 bucket name
+      QSS3BucketRegion:
+        default: Quick Start S3 bucket region
+      QSS3KeyPrefix:
+        default: Quick Start S3 key prefix
+      TGWSubnet1CIDR:
+        default: TGW subnet 1 CIDR
+      TGWSubnet2CIDR:
+        default: TGW subnet 2 CIDR
+      TGWSubnet3CIDR:
+        default: TGW subnet 3 CIDR
+      TGWSubnet4CIDR:
+        default: TGW subnet 4 CIDR
+      AmazonSideAsn: 
+        default: ASN for TGW S2S VPN attachment
+      OnPremFirewallPublicIP:
+        default: Public IP for customer on-premises gateway
+      OnPremFirewallASN:
+        default: ASN for customer gateway
+      PreSharedKeyForVPNAttachment:
+        default: Pre shared key for VPN attachement
+      VPNTunnelCIDRs:
+        default: On-premises gateway to TGW S2S VPN tunnel CIDR blocks
+      OnPremCIDR:
+        default: On-premises network CIDR
+Parameters:
+  AvailabilityZones:
+    Description: >-
+      List of Availability Zones to use for the subnets in the VPC. Note: The
+      logical order is preserved and up to 4 Availability Zoness are used for 
+      this deployment.
+    Type: 'List<AWS::EC2::AvailabilityZone::Name>'
+  NumberOfAZs:
+    AllowedValues:
+      - '1'
+      - '2'
+      - '3'
+      - '4'
+    Default: '2'
+    Description: >-
+      Number of Availability Zones to use in the VPC. This must match the number
+      of selections in the list of Availability Zones.
+    Type: String
+  VPCCIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.0.0/16
+    Description: CIDR block for the VPC.
+    Type: String
+  PublicSubnet1CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.0.0/21
+    Description: CIDR block for public subnet 1 located in Availability Zone 1, for ASAv1.
+    Type: String
+  PublicSubnet2CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.8.0/21
+    Description: CIDR block for public subnet 2 located in Availability Zone 2, for ASAv2.
+    Type: String
+  PublicSubnet3CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.16.0/21
+    Description: CIDR block for public subnet 3 located in Availability Zone 3, for ASAv3.
+    Type: String
+  PublicSubnet4CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.24.0/21
+    Description: CIDR block for public subnet 4 located in Availability Zone 4, for ASAv4.
+    Type: String
+  PrivateSubnet1CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.32.0/21
+    Description: CIDR block for private subnet 1 located in Availability Zone 1, for ASAv1.
+    Type: String
+  PrivateSubnet2CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.40.0/21
+    Description: CIDR block for private subnet 2 located in Availability Zone 2, for ASAv2.
+    Type: String
+  PrivateSubnet3CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.48.0/21
+    Description: CIDR block for private subnet 3 located in Availability Zone 3, for ASAv3.
+    Type: String
+  PrivateSubnet4CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.56.0/21
+    Description: CIDR block for private subnet 4 located in Availability Zone 4, for ASAv4.
+    Type: String
+  NumberOfASAv:
+    AllowedValues:
+      - '1'
+      - '2'
+      - '3'
+      - '4'
+    Default: '2'
+    Description: >-
+      Number of ASAv instances to be initiated.
+    Type: String  
+  ASAv1HostName:
+    Type: String
+    Default: ASAv01RAVPN
+    Description: Enter ASAv1 hostname.
+  ASAv2HostName:
+    Type: String
+    Default: ASAv02RAVPN
+    Description: Enter ASAv2 hostname.
+  ASAv3HostName:
+    Type: String
+    Default: ASAv03RAVPN
+    Description: Enter ASAv3 hostname.
+  ASAv4HostName:
+    Type: String
+    Default: ASAv04RAVPN
+    Description: Enter ASAv4 hostname.
+  DnsName:
+    Type: String
+    Description: Domain name of PublicHostedZone registered in Route53. This is the domain name behind which the ASAv firewall instances will be load balanced.
+    Default: example.com
+  InstanceTypeParam:
+    Type: String
+    Default: c5.large
+    AllowedValues:
+      - m4.large
+      - m4.xlarge
+      - m4.2xlarge
+      - c3.large
+      - c3.xlarge
+      - c3.2xlarge
+      - c4.large
+      - c4.xlarge
+      - c4.2xlarge
+      - c5.large
+      - c5.xlarge
+      - c5.2xlarge
+    Description: Select an instance type for the ASAv instances.
+  VPNUser:
+    Type: String
+    Description: Test VPN username.
+  VPNPassword:
+    NoEcho: true
+    Type: String
+    Description: Test VPN password.
+  KeyPair:
+    Type: AWS::EC2::KeyPair::KeyName
+    Description: ASAv instances will launch with this key pair.
+  SSHLockDownCIDR:
+    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])(\/([0-9]|1[6-9]|2[0-8]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/0-28
+    Description: CIDR block for locking down SSH access on the outside interface.
+    Type: String
+  MgmtSubnet1CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.64.0/21
+    Description: CIDR block for management subnet 1 located in Availability Zone 1, for ASAv1.
+    Type: String
+  MgmtSubnet2CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.72.0/21
+    Description: CIDR block for management subnet 2 located in Availability Zone 2, for ASAv2.
+    Type: String
+  MgmtSubnet3CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.80.0/21
+    Description: CIDR block for management subnet 3 located in Availability Zone 3, for ASAv3.
+    Type: String
+  MgmtSubnet4CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.88.0/21
+    Description: CIDR block for management subnet 4 located in Availability Zone 4, for ASAv4.
+    Type: String
+  VPNPoolCIDR1:
+    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])(\/(19))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/19
+    Default: 172.16.0.0/19
+    Description: This is a /19 CIDR block for a ghost VPN pool for ASAv1. VPN clients connecting in will be assigned an IP from this subnet. This subnet should not overlap with the on-premises CIDR or VPC CIDR blocks. You can use the default value.
+    Type: String
+  VPNPoolCIDR2:
+    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])(\/(19))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/19
+    Default: 172.16.32.0/19
+    Description: This is a /19 CIDR block for a ghost VPN pool for ASAv2. VPN clients connecting in will be assigned an IP from this subnet. This subnet should not overlap with the on-premises CIDR or VPC CIDR blocks. You can use the default value.
+    Type: String
+  VPNPoolCIDR3:
+    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])(\/(19))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/19
+    Default: 172.16.64.0/19
+    Description: This is a /19 CIDR block for a ghost VPN pool for ASAv3. VPN clients connecting in will be assigned an IP from this subnet. This subnet should not overlap with the on-premises CIDR or VPC CIDR blocks. You can use the default value.
+    Type: String
+  VPNPoolCIDR4:
+    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])(\/(19))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/19
+    Default: 172.16.96.0/19
+    Description: This is a /19 CIDR block for a ghost VPN pool for ASAv4. VPN clients connecting in will be assigned an IP from this subnet. This subnet should not overlap with the on-premises CIDR or VPC CIDR blocks. You can use the default value.
+    Type: String
+  QSS3BucketName:
+    AllowedPattern: '^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$'
+    ConstraintDescription: >-
+      Quick Start bucket name can include numbers, lowercase letters, uppercase
+      letters, and hyphens (-). It cannot start or end with a hyphen (-).
+    Default: aws-quickstart
+    Description: >-
+      S3 bucket name for the Quick Start assets. Quick Start bucket name can
+      include numbers, lowercase letters, uppercase letters, and hyphens (-). It
+      cannot start or end with a hyphen (-).
+    Type: String
+  QSS3BucketRegion:
+    Default: us-east-1
+    Description: >-
+      The AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted.
+      When using your own bucket, you must specify this value.
+    Type: String
+  QSS3KeyPrefix:
+    AllowedPattern: '^[0-9a-zA-Z-/]*$'
+    ConstraintDescription: >-
+      Quick Start key prefix can include numbers, lowercase letters, uppercase
+      letters, hyphens (-), and forward slash (/).
+    Default: quickstart-cisco-asav-ravpn/
+    Description: >-
+      S3 key prefix for the Quick Start assets. Quick Start key prefix can
+      include numbers, lowercase letters, uppercase letters, hyphens (-), and
+      forward slash (/).
+    Type: String
+  TGWSubnet1CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.96.0/21
+    Description: CIDR block for AWS Transit Gateway subnet 1 located in Availability Zone 1.
+    Type: String
+  TGWSubnet2CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.104.0/21
+    Description: CIDR block for AWS Transit Gateway subnet 2 located in Availability Zone 2.
+    Type: String
+  TGWSubnet3CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.112.0/21
+    Description: CIDR block for AWS Transit Gateway subnet 3 located in Availability Zone 3.
+    Type: String
+  TGWSubnet4CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Default: 10.0.120.0/21
+    Description: CIDR block for AWS Transit Gateway subnet 4 located in Availability Zone 4.
+    Type: String
+  AmazonSideAsn:
+    Description: A private Autonomous System Number (ASN) for the Amazon side of a BGP session. The range is 64512 to 65534 for 16-bit ASNs and 4200000000 to 4294967294 for 32-bit ASNs.
+    Type: String
+    Default: 64513
+  OnPremFirewallPublicIP:
+    Description: Specify the public IP address of the on-premises gateway.
+    Type: String
+  OnPremFirewallASN:
+    Description: Specify the BGP ASN of the on-premises gateway.
+    Type: String
+    Default: 65001
+  PreSharedKeyForVPNAttachment:
+    Description: Specify the pre shared key of the customer gateway. Must be 15 characters in length and cannot start with zero (0).
+    NoEcho: true
+    Type: String
+    Default: casav1234567891
+    MinLength: 15
+    MaxLength: 15
+  OnPremCIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Description: CIDR block for the on-premises network.
+    Type: String
+  VPNTunnelCIDRs:
+    Description: Specify the tunnel inside CIDR blocks for the on-premises firewall. You can use the default pre-filled CIDR blocks as well.
+    Type: CommaDelimitedList
+    Default: "169.254.6.0/30, 169.254.7.0/30"
+Conditions:
+  UsingDefaultBucket: !Equals 
+    - !Ref QSS3BucketName
+    - aws-quickstart
+  3SubnetCondition: !Or
+    - !Equals
+      - !Ref 'NumberOfAZs'
+      - '3'
+    - !Condition 4SubnetCondition
+  4SubnetCondition: !Equals
+    - !Ref 'NumberOfAZs'
+    - '4'
+  1ASAvCondition: !Or
+    - !Equals
+      - !Ref 'NumberOfASAv'
+      - '1'
+    - !Condition '2ASAvCondition'
+  2ASAvCondition: !Or
+    - !Equals
+      - !Ref 'NumberOfASAv'
+      - '2'
+    - !Condition '3ASAvCondition'
+  3ASAvCondition: !Or
+    - !Equals
+      - !Ref 'NumberOfASAv'
+      - '3'
+    - !Condition '4ASAvCondition'
+  4ASAvCondition: !Equals
+    - !Ref 'NumberOfASAv'
+    - '4'
+Resources:
+  VPCStack:
+    Type: 'AWS::CloudFormation::Stack'
+    Properties:
+      TemplateURL: !Sub 
+        - >-
+          https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}submodules/quickstart-aws-vpc/templates/aws-vpc.template.yaml
+        - S3Region: !If 
+            - UsingDefaultBucket
+            - !Ref 'AWS::Region'
+            - !Ref QSS3BucketRegion
+          S3Bucket: !If 
+            - UsingDefaultBucket
+            - !Sub '${QSS3BucketName}-${AWS::Region}'
+            - !Ref QSS3BucketName
+      Parameters:
+        AvailabilityZones: !Join 
+          - ','
+          - !Ref AvailabilityZones
+        NumberOfAZs: !Ref NumberOfAZs
+        VPCCIDR: !Ref VPCCIDR
+        PrivateSubnet1ACIDR: !Ref PrivateSubnet1CIDR
+        PrivateSubnet2ACIDR: !Ref PrivateSubnet2CIDR
+        PrivateSubnet3ACIDR: !Ref PrivateSubnet3CIDR
+        PrivateSubnet4ACIDR: !Ref PrivateSubnet4CIDR
+        PublicSubnet1CIDR: !Ref PublicSubnet1CIDR
+        PublicSubnet2CIDR: !Ref PublicSubnet2CIDR
+        PublicSubnet3CIDR: !Ref PublicSubnet3CIDR
+        PublicSubnet4CIDR: !Ref PublicSubnet4CIDR
+  TGWStack:
+    Type: 'AWS::CloudFormation::Stack'
+    Properties:
+      TemplateURL: !Sub
+        - >-
+          https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/quickstart-cisco-asav-ravpn-tgw.yaml
+        - S3Region: !If 
+            - UsingDefaultBucket
+            - !Ref 'AWS::Region'
+            - !Ref QSS3BucketRegion
+          S3Bucket: !If 
+            - UsingDefaultBucket
+            - !Sub '${QSS3BucketName}-${AWS::Region}'
+            - !Ref QSS3BucketName
+      Parameters:
+        AvailabilityZones: !Join 
+          - ','
+          - !Ref AvailabilityZones
+        NumberOfAZs: !Ref NumberOfAZs
+        NumberOfASAv: !Ref NumberOfASAv
+        VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
+        NetworkInterfaceId1ASAv1: !If [1ASAvCondition, !GetAtt 'ASAvStack1.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        NetworkInterfaceId1ASAv2: !If [2ASAvCondition, !GetAtt 'ASAvStack1.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        NetworkInterfaceId2ASAv2: !If [2ASAvCondition, !GetAtt 'ASAvStack2.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        NetworkInterfaceId1ASAv3: !If [3ASAvCondition, !GetAtt 'ASAvStack1.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        NetworkInterfaceId2ASAv3: !If [3ASAvCondition, !GetAtt 'ASAvStack2.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        NetworkInterfaceId3ASAv3: !If [3ASAvCondition, !GetAtt 'ASAvStack3.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        NetworkInterfaceId1ASAv4: !If [4ASAvCondition, !GetAtt 'ASAvStack1.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        NetworkInterfaceId2ASAv4: !If [4ASAvCondition, !GetAtt 'ASAvStack2.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        NetworkInterfaceId3ASAv4: !If [4ASAvCondition, !GetAtt 'ASAvStack3.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        NetworkInterfaceId4ASAv4: !If [4ASAvCondition, !GetAtt 'ASAvStack4.Outputs.InsideENI', !Ref "AWS::NoValue"]
+        PrivateSubnet1ARouteTable: !GetAtt 'VPCStack.Outputs.PrivateSubnet1ARouteTable'
+        PrivateSubnet2ARouteTable: !GetAtt 'VPCStack.Outputs.PrivateSubnet2ARouteTable'
+        PrivateSubnet3ARouteTable: !If [3SubnetCondition, !GetAtt 'VPCStack.Outputs.PrivateSubnet3ARouteTable', !Ref "AWS::NoValue"]
+        PrivateSubnet4ARouteTable: !If [4SubnetCondition, !GetAtt 'VPCStack.Outputs.PrivateSubnet4ARouteTable', !Ref "AWS::NoValue"]
+        VPNPoolCIDR1: !Ref VPNPoolCIDR1
+        VPNPoolCIDR2: !Ref VPNPoolCIDR2
+        VPNPoolCIDR3: !Ref VPNPoolCIDR3
+        VPNPoolCIDR4: !Ref VPNPoolCIDR4
+        TGWSubnet1CIDR: !Ref TGWSubnet1CIDR
+        TGWSubnet2CIDR: !Ref TGWSubnet2CIDR
+        TGWSubnet3CIDR: !Ref TGWSubnet3CIDR
+        TGWSubnet4CIDR: !Ref TGWSubnet4CIDR
+        OnPremFirewallPublicIP: !Ref OnPremFirewallPublicIP
+        OnPremFirewallASN: !Ref OnPremFirewallASN
+        PreSharedKeyForVPNAttachment: !Ref PreSharedKeyForVPNAttachment
+        VPNTunnelCIDRs: !Join
+        - ","
+        - !Ref VPNTunnelCIDRs
+        AmazonSideAsn: !Ref AmazonSideAsn
+        OnPremCIDR: !Ref OnPremCIDR
+        QSS3BucketName: !Ref QSS3BucketName
+        QSS3KeyPrefix: !Ref QSS3KeyPrefix
+        QSS3BucketRegion: !Ref QSS3BucketRegion
+  CommonResourcesStack:
+    Type: 'AWS::CloudFormation::Stack'
+    Properties:
+      TemplateURL: !Sub 
+        - >-
+          https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/quickstart-cisco-asav-ravpn-common.yaml
+        - S3Region: !If 
+            - UsingDefaultBucket
+            - !Ref 'AWS::Region'
+            - !Ref QSS3BucketRegion
+          S3Bucket: !If 
+            - UsingDefaultBucket
+            - !Sub '${QSS3BucketName}-${AWS::Region}'
+            - !Ref QSS3BucketName
+      Parameters:
+        DnsName: !Ref DnsName
+        VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
+        SSHLockDownCIDR: !Ref SSHLockDownCIDR
+  ASAvStack1:
+    Condition: 1ASAvCondition
+    Type: 'AWS::CloudFormation::Stack'
+    Properties:
+      TemplateURL: !Sub 
+        - >-
+          https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/quickstart-cisco-asav-ravpn-instance.yaml
+        - S3Region: !If 
+            - UsingDefaultBucket
+            - !Ref 'AWS::Region'
+            - !Ref QSS3BucketRegion
+          S3Bucket: !If 
+            - UsingDefaultBucket
+            - !Sub '${QSS3BucketName}-${AWS::Region}'
+            - !Ref QSS3BucketName
+      Parameters:
+        InstanceTypeParam: !Ref InstanceTypeParam
+        KeyPair: !Ref KeyPair
+        VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
+        VPNUser: !Ref VPNUser
+        VPNPassword: !Ref VPNPassword
+        PrivateSubnet1ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet1AID'
+        PublicSubnet1ID:  !GetAtt 'VPCStack.Outputs.PublicSubnet1ID'
+        MgmtSubnet1CIDR: !Ref MgmtSubnet1CIDR
+        ASAv1HostName: !Ref ASAv1HostName
+        DnsName: !Ref DnsName
+        VPNPoolFrom1: !Sub
+        - ${a}.${b}.0.1
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR1 ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR1 ]]]]
+        VPNPoolTo1: !Sub
+        - ${a}.${b}.31.254
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR1 ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR1 ]]]]
+        VPNPoolCIDRMask1: !Select [1, !Split [ "/" , !Ref VPNPoolCIDR1 ]] 
+        VPCCIDRMASK: !Select [1, !Split [ "/" , !Ref VPCCIDR ]] 
+        VPCPOOL: !Select [0, !Split ["/", !Ref VPCCIDR]]
+        OnPremCIDRMask: !Select [1, !Split [ "/" , !Ref OnPremCIDR ]] 
+        OnPremPool: !Select [0, !Split ["/", !Ref OnPremCIDR]]
+        PrivateSubnet1GW: !Sub
+        - ${a}.${b}.${c}.1
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet1CIDR ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet1CIDR ]]]]
+          c: !Select [2, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet1CIDR ]]]]
+        PrivateSubnet1CIDR: !Ref PrivateSubnet1CIDR
+        PrivateSubnet1Pool: !Select [0, !Split ["/", !Ref PrivateSubnet1CIDR]]
+        PrivateSubnet1CIDRMask: !Select [1, !Split [ "/" , !Ref PrivateSubnet1CIDR ]]
+        PublicHostedZone: !GetAtt 'CommonResourcesStack.Outputs.PublicHostedZone'
+        MgmtRouteTable: !GetAtt 'CommonResourcesStack.Outputs.MgmtRouteTable'
+        ASAvInstanceSGMGMT: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGMGMT'
+        ASAvInstanceSGOUTSIDE: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGOUTSIDE'
+        ASAvInstanceSGINSIDE: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGINSIDE'
+        InstanceIdentifier: 0
+
+  ASAvStack2:
+    Condition: 2ASAvCondition
+    Type: 'AWS::CloudFormation::Stack'
+    Properties:
+      TemplateURL: !Sub 
+        - >-
+          https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/quickstart-cisco-asav-ravpn-instance.yaml
+        - S3Region: !If 
+            - UsingDefaultBucket
+            - !Ref 'AWS::Region'
+            - !Ref QSS3BucketRegion
+          S3Bucket: !If 
+            - UsingDefaultBucket
+            - !Sub '${QSS3BucketName}-${AWS::Region}'
+            - !Ref QSS3BucketName
+      Parameters:
+        InstanceTypeParam: !Ref InstanceTypeParam
+        KeyPair: !Ref KeyPair
+        VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
+        VPNUser: !Ref VPNUser
+        VPNPassword: !Ref VPNPassword
+        PrivateSubnet1ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet2AID'
+        PublicSubnet1ID:  !GetAtt 'VPCStack.Outputs.PublicSubnet2ID'
+        MgmtSubnet1CIDR: !Ref MgmtSubnet2CIDR
+        ASAv1HostName: !Ref ASAv2HostName
+        DnsName: !Ref DnsName
+        VPNPoolFrom1: !Sub
+        - ${a}.${b}.32.1
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR2 ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR2 ]]]]
+        VPNPoolTo1: !Sub
+        - ${a}.${b}.63.254
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR2 ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR2 ]]]]
+        VPNPoolCIDRMask1: !Select [1, !Split [ "/" , !Ref VPNPoolCIDR2 ]] 
+        VPCCIDRMASK: !Select [1, !Split [ "/" , !Ref VPCCIDR ]] 
+        VPCPOOL: !Select [0, !Split ["/", !Ref VPCCIDR]]
+        OnPremCIDRMask: !Select [1, !Split [ "/" , !Ref OnPremCIDR ]] 
+        OnPremPool: !Select [0, !Split ["/", !Ref OnPremCIDR]]
+        PrivateSubnet1GW: !Sub
+        - ${a}.${b}.${c}.1
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet2CIDR ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet2CIDR ]]]]
+          c: !Select [2, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet2CIDR ]]]]
+        PrivateSubnet1CIDR: !Ref PrivateSubnet2CIDR
+        PrivateSubnet1Pool: !Select [0, !Split ["/", !Ref PrivateSubnet2CIDR]]
+        PrivateSubnet1CIDRMask: !Select [1, !Split [ "/" , !Ref PrivateSubnet2CIDR ]]
+        PublicHostedZone: !GetAtt 'CommonResourcesStack.Outputs.PublicHostedZone'
+        MgmtRouteTable: !GetAtt 'CommonResourcesStack.Outputs.MgmtRouteTable'
+        ASAvInstanceSGMGMT: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGMGMT'
+        ASAvInstanceSGOUTSIDE: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGOUTSIDE'
+        ASAvInstanceSGINSIDE: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGINSIDE'
+        InstanceIdentifier: 1
+
+  ASAvStack3:
+    Condition: 3ASAvCondition
+    Type: 'AWS::CloudFormation::Stack'
+    Properties:
+      TemplateURL: !Sub 
+        - >-
+          https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/quickstart-cisco-asav-ravpn-instance.yaml
+        - S3Region: !If 
+            - UsingDefaultBucket
+            - !Ref 'AWS::Region'
+            - !Ref QSS3BucketRegion
+          S3Bucket: !If 
+            - UsingDefaultBucket
+            - !Sub '${QSS3BucketName}-${AWS::Region}'
+            - !Ref QSS3BucketName
+      Parameters:
+        InstanceTypeParam: !Ref InstanceTypeParam
+        KeyPair: !Ref KeyPair
+        VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
+        VPNUser: !Ref VPNUser
+        VPNPassword: !Ref VPNPassword
+        PrivateSubnet1ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet3AID'
+        PublicSubnet1ID:  !GetAtt 'VPCStack.Outputs.PublicSubnet3ID'
+        MgmtSubnet1CIDR: !Ref MgmtSubnet3CIDR
+        ASAv1HostName: !Ref ASAv3HostName
+        DnsName: !Ref DnsName
+        VPNPoolFrom1: !Sub
+        - ${a}.${b}.64.1
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR3 ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR3 ]]]]
+        VPNPoolTo1: !Sub
+        - ${a}.${b}.95.254
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR3 ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR3 ]]]]
+        VPNPoolCIDRMask1: !Select [1, !Split [ "/" , !Ref VPNPoolCIDR3 ]] 
+        VPCCIDRMASK: !Select [1, !Split [ "/" , !Ref VPCCIDR ]] 
+        VPCPOOL: !Select [0, !Split ["/", !Ref VPCCIDR]]
+        OnPremCIDRMask: !Select [1, !Split [ "/" , !Ref OnPremCIDR ]] 
+        OnPremPool: !Select [0, !Split ["/", !Ref OnPremCIDR]]
+        PrivateSubnet1GW: !Sub
+        - ${a}.${b}.${c}.1
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet3CIDR ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet3CIDR ]]]]
+          c: !Select [2, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet3CIDR ]]]]
+        PrivateSubnet1CIDR: !Ref PrivateSubnet3CIDR
+        PrivateSubnet1Pool: !Select [0, !Split ["/", !Ref PrivateSubnet3CIDR]]
+        PrivateSubnet1CIDRMask: !Select [1, !Split [ "/" , !Ref PrivateSubnet3CIDR ]]
+        PublicHostedZone: !GetAtt 'CommonResourcesStack.Outputs.PublicHostedZone'
+        MgmtRouteTable: !GetAtt 'CommonResourcesStack.Outputs.MgmtRouteTable'
+        ASAvInstanceSGMGMT: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGMGMT'
+        ASAvInstanceSGOUTSIDE: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGOUTSIDE'
+        ASAvInstanceSGINSIDE: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGINSIDE'
+        InstanceIdentifier: 2
+
+  ASAvStack4:
+    Condition: 4ASAvCondition
+    Type: 'AWS::CloudFormation::Stack'
+    Properties:
+      TemplateURL: !Sub 
+        - >-
+          https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/quickstart-cisco-asav-ravpn-instance.yaml
+        - S3Region: !If 
+            - UsingDefaultBucket
+            - !Ref 'AWS::Region'
+            - !Ref QSS3BucketRegion
+          S3Bucket: !If 
+            - UsingDefaultBucket
+            - !Sub '${QSS3BucketName}-${AWS::Region}'
+            - !Ref QSS3BucketName
+      Parameters:
+        InstanceTypeParam: !Ref InstanceTypeParam
+        KeyPair: !Ref KeyPair
+        VPCID: !GetAtt 'VPCStack.Outputs.VPCID'
+        VPNUser: !Ref VPNUser
+        VPNPassword: !Ref VPNPassword
+        PrivateSubnet1ID: !GetAtt 'VPCStack.Outputs.PrivateSubnet4AID'
+        PublicSubnet1ID:  !GetAtt 'VPCStack.Outputs.PublicSubnet4ID'
+        MgmtSubnet1CIDR: !Ref MgmtSubnet4CIDR
+        ASAv1HostName: !Ref ASAv4HostName
+        DnsName: !Ref DnsName
+        VPNPoolFrom1: !Sub
+        - ${a}.${b}.96.1
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR4 ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR4 ]]]]
+        VPNPoolTo1: !Sub
+        - ${a}.${b}.127.254
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR4 ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref VPNPoolCIDR4 ]]]]
+        VPNPoolCIDRMask1: !Select [1, !Split [ "/" , !Ref VPNPoolCIDR4 ]] 
+        VPCCIDRMASK: !Select [1, !Split [ "/" , !Ref VPCCIDR ]] 
+        VPCPOOL: !Select [0, !Split ["/", !Ref VPCCIDR]]
+        OnPremCIDRMask: !Select [1, !Split [ "/" , !Ref OnPremCIDR ]] 
+        OnPremPool: !Select [0, !Split ["/", !Ref OnPremCIDR]]
+        PrivateSubnet1GW: !Sub
+        - ${a}.${b}.${c}.1
+        - a: !Select [0, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet4CIDR ]]]]
+          b: !Select [1, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet4CIDR ]]]]
+          c: !Select [2, !Split ['.', !Select [0, !Split [ "/" , !Ref PrivateSubnet4CIDR ]]]]
+        PrivateSubnet1CIDR: !Ref PrivateSubnet4CIDR
+        PrivateSubnet1Pool: !Select [0, !Split ["/", !Ref PrivateSubnet4CIDR]]
+        PrivateSubnet1CIDRMask: !Select [1, !Split [ "/" , !Ref PrivateSubnet4CIDR ]]
+        PublicHostedZone: !GetAtt 'CommonResourcesStack.Outputs.PublicHostedZone'
+        MgmtRouteTable: !GetAtt 'CommonResourcesStack.Outputs.MgmtRouteTable'
+        ASAvInstanceSGMGMT: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGMGMT'
+        ASAvInstanceSGOUTSIDE: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGOUTSIDE'
+        ASAvInstanceSGINSIDE: !GetAtt 'CommonResourcesStack.Outputs.ASAvInstanceSGINSIDE'
+        InstanceIdentifier: 3
+
+Outputs:
+  AccountId:
+    Description: Amazon Account ID
+    Value: !Ref 'AWS::AccountId'
+#------------------------------- ASAvStack1-----------------  
+  ASAv1MGMTIPStack1:
+    Condition: 1ASAvCondition
+    Description: ASAv Instance 1 Management IP
+    Value: !GetAtt ASAvStack1.Outputs.ASAv1MGMTIP
+  ASAv1PublicIPStack1:
+    Condition: 1ASAvCondition  
+    Description: ASAv Instance 1 Public IP
+    Value: !GetAtt ASAvStack1.Outputs.ASAv1PublicIP
+  VPNPoolFrom1Stack1:
+    Condition: 1ASAvCondition  
+    Description: ASAv Instance 1 VPN Pool From
+    Value: !GetAtt ASAvStack1.Outputs.VPNPoolFrom1
+  VPNPoolTo1Stack1:
+    Condition: 1ASAvCondition  
+    Description: ASAv Instance 1 VPN Pool To
+    Value: !GetAtt ASAvStack1.Outputs.VPNPoolTo1
+  VPNPoolMask1Stack1:
+    Condition: 1ASAvCondition  
+    Description: ASAv Instance 1 VPN Pool Mask
+    Value: !GetAtt ASAvStack1.Outputs.VPNPoolCIDRMask1
+#------------------------------- ASAvStack2-----------------
+  ASAv2MGMTIPStack2:
+    Condition: 2ASAvCondition
+    Description: ASAv Instance 2 Management IP
+    Value: !GetAtt ASAvStack2.Outputs.ASAv1MGMTIP
+  ASAv2PublicIPStack2:
+    Condition: 2ASAvCondition  
+    Description: ASAv Instance 2 Public IP
+    Value: !GetAtt ASAvStack2.Outputs.ASAv1PublicIP
+  VPNPoolFrom2Stack2:
+    Condition: 2ASAvCondition  
+    Description: ASAv Instance 2 VPN Pool From
+    Value: !GetAtt ASAvStack2.Outputs.VPNPoolFrom1
+  VPNPoolTo2Stack2:
+    Condition: 2ASAvCondition  
+    Description: ASAv Instance 2 VPN Pool To
+    Value: !GetAtt ASAvStack2.Outputs.VPNPoolTo1
+  VPNPoolMask2Stack2:
+    Condition: 2ASAvCondition  
+    Description: ASAv Instance 2 VPN Pool Mask
+    Value: !GetAtt ASAvStack2.Outputs.VPNPoolCIDRMask1
+#------------------------------- ASAvStack3-----------------
+  ASAv3MGMTIPStack3:
+    Condition: 3ASAvCondition
+    Description: ASAv Instance 3 Management IP
+    Value: !GetAtt ASAvStack3.Outputs.ASAv1MGMTIP
+  ASAv3PublicIPStack3:
+    Condition: 3ASAvCondition  
+    Description: ASAv Instance 3 Public IP
+    Value: !GetAtt ASAvStack3.Outputs.ASAv1PublicIP
+  VPNPoolFrom3Stack3:
+    Condition: 3ASAvCondition  
+    Description: ASAv Instance 3 VPN Pool From
+    Value: !GetAtt ASAvStack3.Outputs.VPNPoolFrom1
+  VPNPoolTo3Stack3:
+    Condition: 3ASAvCondition  
+    Description: ASAv Instance 3 VPN Pool To
+    Value: !GetAtt ASAvStack3.Outputs.VPNPoolTo1
+  VPNPoolMask3Stack3:
+    Condition: 3ASAvCondition  
+    Description: ASAv Instance 3 VPN Pool Mask
+    Value: !GetAtt ASAvStack3.Outputs.VPNPoolCIDRMask1
+#------------------------------- ASAvStack4-----------------
+  ASAv4MGMTIPStack4:
+    Condition: 4ASAvCondition
+    Description: ASAv Instance 4 Management IP
+    Value: !GetAtt ASAvStack4.Outputs.ASAv1MGMTIP
+  ASAv4PublicIPStack4:
+    Condition: 4ASAvCondition  
+    Description: ASAv Instance 4 Public IP
+    Value: !GetAtt ASAvStack4.Outputs.ASAv1PublicIP
+  VPNPoolFrom4Stack4:
+    Condition: 4ASAvCondition  
+    Description: ASAv Instance 4 VPN Pool From
+    Value: !GetAtt ASAvStack4.Outputs.VPNPoolFrom1
+  VPNPoolTo4Stack4:
+    Condition: 4ASAvCondition  
+    Description: ASAv Instance 4 VPN Pool To
+    Value: !GetAtt ASAvStack4.Outputs.VPNPoolTo1
+  VPNPoolMask4Stack4:
+    Condition: 4ASAvCondition  
+    Description: ASAv Instance 4 VPN Pool Mask
+    Value: !GetAtt ASAvStack4.Outputs.VPNPoolCIDRMask1
+#--------------------------------------------------------------
+  VPNTunnelOutsideIPs:
+    Description: VPN Tunnel Outside IP
+    Value: !GetAtt TGWStack.Outputs.VPNTunnelOutsideIPs

+ 710 - 0
base/_archive/cisco_vpn/quickstart-cisco-asav-ravpn/templates/quickstart-cisco-asav-ravpn-tgw.yaml

@@ -0,0 +1,710 @@
+AWSTemplateFormatVersion: 2010-09-09
+Description: The template creates the TGW resource to connect on-premises firewall with cloud (qs-1qp7e9toe)
+Parameters:
+  PrivateSubnet1ARouteTable:
+    Type: String
+    Description: Public Subnet 1 Route Table ID
+  PrivateSubnet2ARouteTable:
+    Type: String
+    Description: Public Subnet 2 Route Table ID
+  PrivateSubnet3ARouteTable:
+    Type: String
+    Default: 'null'
+    Description: Public Subnet 3 Route Table ID
+  PrivateSubnet4ARouteTable:
+    Type: String
+    Default: 'null'
+    Description: Public Subnet 4 Route Table ID
+  OnPremFirewallPublicIP:
+    Description: Specify the Public IP of the on-premises ASAv/router
+    Type: String
+  OnPremFirewallASN:
+    Description: Specify the BGP ASN of the on-premisis ASAv/router
+    Type: String
+  PreSharedKeyForVPNAttachment:
+    Description: Specify the PreSharedKey of vEdgeCloud1. Must be 15 characters in length and cannot start with zero (0).
+    Type: String
+  AmazonSideAsn:
+    Description: A private Autonomous System Number (ASN) for the Amazon side of a BGP session. The range is 64512 to 65534 for 16-bit ASNs and 4200000000 to 4294967294 for 32-bit ASNs.
+    Type: String
+  VPNTunnelCIDRs:
+    Description: Specify the Tunnel InsideCIDRs for the on-premises firewall. You can use the default pre-filled CIDRs as well.
+    Type: CommaDelimitedList
+  VPCID:
+    Type: AWS::EC2::VPC::Id
+    Description: Select VPC which for VPC Attachment
+  TGWSubnet1CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Description: CIDR block for TGW subnet 1 located in Availability Zone 1
+    Type: String
+  TGWSubnet2CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Description: CIDR block for TGW subnet 2 located in Availability Zone 1
+    Type: String
+  TGWSubnet3CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Description: CIDR block for TGW subnet 3 located in Availability Zone 1
+    Type: String
+  TGWSubnet4CIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Description: CIDR block for TGW subnet 4 located in Availability Zone 1
+    Type: String
+  VPNPoolCIDR1:
+    Description: CIDR block for the VPN pool 1
+    Type: String
+  VPNPoolCIDR2:
+    Description: CIDR block for the VPN pool 2
+    Type: String
+  VPNPoolCIDR3:
+    Description: CIDR block for the VPN pool 3
+    Type: String
+  VPNPoolCIDR4:
+    Description: CIDR block for the VPN pool 4
+    Type: String
+  OnPremCIDR:
+    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]))$
+    ConstraintDescription: CIDR block parameter must be in the form x.x.x.x/16-28
+    Description: CIDR block for the On-prem network
+    Type: String
+  AvailabilityZones:
+    Description: >-
+      List of Availability Zones to use for the subnets in the VPC. Note: The
+      logical order is preserved and only 2 AZs are used for this deployment.
+    Type: 'List<AWS::EC2::AvailabilityZone::Name>'
+  NumberOfAZs:
+    Description: >-
+      Number of Availability Zones to use in the VPC. This must match your
+      selections in the list of Availability Zones parameter.
+    Type: String
+  NumberOfASAv:
+    Description: >-
+      Number of ASAv Instances to be initiated.
+    Type: String  
+  NetworkInterfaceId1ASAv1:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv1 for 1 ASAv deployment
+  NetworkInterfaceId1ASAv2:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv1 for 2 ASAv deployment
+  NetworkInterfaceId2ASAv2:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv2 for 2 ASAv deployment
+  NetworkInterfaceId1ASAv3:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv1 for 3 ASAv deployment
+  NetworkInterfaceId2ASAv3:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv2 for 3 ASAv deployment
+  NetworkInterfaceId3ASAv3:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv3 for 3 ASAv deployment
+  NetworkInterfaceId1ASAv4:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv1 for 4 ASAv deployment
+  NetworkInterfaceId2ASAv4:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv2 for 4 ASAv deployment
+  NetworkInterfaceId3ASAv4:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv3 for 4 ASAv deployment
+  NetworkInterfaceId4ASAv4:
+    Type: String
+    Default: 'null'
+    Description: NetworkInterfaceId of ASAv4 for 4 ASAv deployment
+  QSS3BucketName:
+    AllowedPattern: "^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$"
+    ConstraintDescription: >-
+      Quick Start bucket name can include numbers, lowercase letters, uppercase
+      letters, and hyphens (-). It cannot start or end with a hyphen (-).
+    Description: >-
+      S3 bucket name for the Quick Start assets. Quick Start bucket name can
+      include numbers, lowercase letters, uppercase letters, and hyphens (-). It
+      cannot start or end with a hyphen (-).
+    Type: String
+  QSS3KeyPrefix:
+    AllowedPattern: "^[0-9a-zA-Z-/]*$"
+    ConstraintDescription: >-
+      Quick Start key prefix can include numbers, lowercase letters, uppercase
+      letters, hyphens (-), and forward slash (/).
+    Description: >-
+      S3 key prefix for the Quick Start assets. Quick Start key prefix can
+      include numbers, lowercase letters, uppercase letters, hyphens (-), and
+      forward slash (/).
+    Type: String
+  QSS3BucketRegion:
+    Description: >-
+      The AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted.
+      When using your own bucket, you must specify this value.
+    Type: String
+Conditions:
+  UsingDefaultBucket: !Equals 
+    - !Ref QSS3BucketName
+    - aws-quickstart
+  1AZCondition: !Equals
+    - !Ref 'NumberOfAZs'
+    - '1'
+  2AZCondition: !Equals
+    - !Ref 'NumberOfAZs'
+    - '2'
+  3AZCondition: !Equals
+    - !Ref 'NumberOfAZs'
+    - '3'
+  4AZCondition: !Equals
+    - !Ref 'NumberOfAZs'
+    - '4'
+  #Subnet conditions to specifically handle TGW Subnet Resource constraints
+  1SubnetCondition: !Or
+    - !Equals
+      - !Ref 'NumberOfAZs'
+      - '1'
+    - !Condition 2SubnetCondition
+    - !Condition 3SubnetCondition
+    - !Condition 4SubnetCondition
+  2SubnetCondition: !Or
+    - !Equals
+      - !Ref 'NumberOfAZs'
+      - '2'
+    - !Condition 3SubnetCondition
+    - !Condition 4SubnetCondition
+  3SubnetCondition: !Or
+    - !Equals
+      - !Ref 'NumberOfAZs'
+      - '3'
+    - !Condition 4SubnetCondition
+  4SubnetCondition: !Equals
+    - !Ref 'NumberOfAZs'
+    - '4'
+  1ASAvCondition: !Equals
+    - !Ref 'NumberOfASAv'
+    - '1'
+  2ASAvCondition: !Equals
+    - !Ref 'NumberOfASAv'
+    - '2'
+  3ASAvCondition: !Equals
+    - !Ref 'NumberOfASAv'
+    - '3'
+  4ASAvCondition: !Equals
+    - !Ref 'NumberOfASAv'
+    - '4'
+Resources:
+#------------------ TGW Subnets and Routes -------------------------------------------
+  TGWSubnet1:
+    Type: AWS::EC2::Subnet
+    Properties:
+      VpcId: !Ref 'VPCID'
+      CidrBlock: !Ref 'TGWSubnet1CIDR'
+      AvailabilityZone: !Select
+        - '0'
+        - !Ref 'AvailabilityZones'
+      Tags:
+        - Key: Name
+          Value: TGW subnet 1
+  TGWSubnet2:
+    Condition: 2SubnetCondition
+    Type: AWS::EC2::Subnet
+    Properties:
+      VpcId: !Ref 'VPCID'
+      CidrBlock: !Ref 'TGWSubnet2CIDR'
+      AvailabilityZone: !Select
+        - '1'
+        - !Ref 'AvailabilityZones'
+      Tags:
+        - Key: Name
+          Value: TGW subnet 2
+  TGWSubnet3:
+    Condition: 3SubnetCondition
+    Type: AWS::EC2::Subnet
+    Properties:
+      VpcId: !Ref 'VPCID'
+      CidrBlock: !Ref 'TGWSubnet3CIDR'
+      AvailabilityZone: !Select
+        - '2'
+        - !Ref 'AvailabilityZones'
+      Tags:
+        - Key: Name
+          Value: TGW subnet 3
+  TGWSubnet4:
+    Condition: 4AZCondition
+    Type: AWS::EC2::Subnet
+    Properties:
+      VpcId: !Ref 'VPCID'
+      CidrBlock: !Ref 'TGWSubnet4CIDR'
+      AvailabilityZone: !Select
+        - '3'
+        - !Ref 'AvailabilityZones'
+      Tags:
+        - Key: Name
+          Value: TGW subnet 4
+  TGWSubnetRouteTable:
+    Type: AWS::EC2::RouteTable
+    Properties:
+      VpcId: !Ref 'VPCID'
+      Tags:
+        - Key: Name
+          Value: TGW subnets route table
+  TGWSubnet1Route:
+    Condition: 1ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR1
+      NetworkInterfaceId: !Ref NetworkInterfaceId1ASAv1
+  TGWSubnet1Route2ASAv:
+    Condition: 2ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR1
+      NetworkInterfaceId: !Ref NetworkInterfaceId1ASAv2
+  TGWSubnet1Route3ASAv:
+    Condition: 3ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR1
+      NetworkInterfaceId: !Ref NetworkInterfaceId1ASAv3
+  TGWSubnet1Route4ASAv:
+    Condition: 4ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR1
+      NetworkInterfaceId: !Ref NetworkInterfaceId1ASAv4 
+  TGWSubnet1AZRouteTableAssociation:
+    Type: AWS::EC2::SubnetRouteTableAssociation
+    Properties:
+      SubnetId: !Ref 'TGWSubnet1'
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+  TGWSubnet2Route:
+    Condition: 2ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR2
+      NetworkInterfaceId: !Ref NetworkInterfaceId2ASAv2
+  TGWSubnet2Route3ASAv:
+    Condition: 3ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR2
+      NetworkInterfaceId: !Ref NetworkInterfaceId2ASAv3
+  TGWSubnet2Route4ASAv:
+    Condition: 4ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR2
+      NetworkInterfaceId: !Ref NetworkInterfaceId2ASAv4
+  TGWSubnet2AZRouteTableAssociation:
+    Condition: 2SubnetCondition
+    Type: AWS::EC2::SubnetRouteTableAssociation
+    Properties:
+      SubnetId: !Ref 'TGWSubnet2'
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+  TGWSubnet3Route:
+    Condition: 3ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR3
+      NetworkInterfaceId: !Ref NetworkInterfaceId3ASAv3
+  TGWSubnet3Route4ASAv:
+    Condition: 4ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR3
+      NetworkInterfaceId: !Ref NetworkInterfaceId3ASAv4
+  TGWSubnet3AZRouteTableAssociation:
+    Condition: 3SubnetCondition
+    Type: AWS::EC2::SubnetRouteTableAssociation
+    Properties:
+      SubnetId: !Ref 'TGWSubnet3'
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+  TGWSubnet4Route:
+    Condition: 4ASAvCondition
+    Type: AWS::EC2::Route
+    Properties:
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+      DestinationCidrBlock: !Ref VPNPoolCIDR4
+      NetworkInterfaceId: !Ref NetworkInterfaceId4ASAv4
+  TGWSubnet4AZRouteTableAssociation:
+    Condition: 4SubnetCondition
+    Type: AWS::EC2::SubnetRouteTableAssociation
+    Properties:
+      SubnetId: !Ref 'TGWSubnet4'
+      RouteTableId: !Ref 'TGWSubnetRouteTable'
+#------------------ Transit Gateway -------------------------------------------
+  TransitGateway:
+    Type: "AWS::EC2::TransitGateway"
+    Properties:
+      AmazonSideAsn: !Ref AmazonSideAsn
+      AutoAcceptSharedAttachments: enable
+      DefaultRouteTableAssociation: disable
+      DefaultRouteTablePropagation: disable
+      Description: A transit gateway connect onpremsised with AWS 
+      Tags: 
+      - Key: Name
+        Value: !Sub ${AWS::StackName}-TGW
+#------------------ Copy lambda stack into local S3 bucket ------------------------------------------------
+  CopyLambdaStack:
+    Type: AWS::CloudFormation::Stack
+    Properties:
+      #TemplateURL: !Sub "https://${QSS3BucketName}.s3.amazonaws.com/${QSS3KeyPrefix}templates/copy-lambdas.yaml"
+      TemplateURL: !Sub 
+        - >-
+          https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/copy-lambdas.yaml
+        - S3Region: !If 
+            - UsingDefaultBucket
+            - !Ref 'AWS::Region'
+            - !Ref QSS3BucketRegion
+          S3Bucket: !If 
+            - UsingDefaultBucket
+            - !Sub '${QSS3BucketName}-${AWS::Region}'
+            - !Ref QSS3BucketName
+      Parameters:
+        QSS3BucketName: !Ref QSS3BucketName
+        QSS3KeyPrefix: !Ref QSS3KeyPrefix
+##------------------ Custom Resource lambda to get the various TGW properties needed -------------------------------------------
+  LambdaBasicExecutionRole:
+    Type: AWS::IAM::Role
+    Properties:
+      AssumeRolePolicyDocument:
+        Statement:
+        - Effect: Allow
+          Principal:
+            Service: lambda.amazonaws.com
+          Action: sts:AssumeRole
+          Condition: {}
+      Path: /
+      Policies:
+        - PolicyName: !Sub ${AWS::StackName}-tgwDescribe
+          PolicyDocument:
+            Version: 2012-10-17
+            Statement:
+              - Effect: Allow
+                Action:
+                  - logs:CreateLogGroup
+                  - logs:CreateLogStream
+                  - logs:PutLogEvents
+                Resource: !Sub arn:${AWS::Partition}:logs:*:*:*
+              - Effect: Allow
+                Action:
+                  - ec2:DescribeVpnConnections
+                  - ec2:DescribeTransitGatewayRouteTables
+                  - ec2:DescribeTransitGatewayAttachments
+                Resource: "*"
+  TransitGatewayProperties:
+    Type: Custom::TransitGatewayProperty
+    Properties:
+      ServiceToken: !GetAtt 'TransitGatewayLambda.Arn'
+      vpn_id: !Ref VPNAttachment
+      stackName: !Ref "AWS::StackName"
+  TransitGatewayLambda:
+    Type: AWS::Lambda::Function
+    Properties:
+      Handler: getTgwProperties/lambda_function.lambda_handler
+      Timeout: 60
+      Role: !GetAtt 'LambdaBasicExecutionRole.Arn'
+      Runtime: python3.6
+      Code:
+        S3Bucket: !GetAtt 'CopyLambdaStack.Outputs.LambdaZipsBucket'
+        S3Key: !Sub "${QSS3KeyPrefix}functions/packages/lambda.zip"
+      MemorySize: 3008
+#------------------ TGW Route Tables and Routes -------------------------------------------
+  TransitGatewaySecurityRouteTable:
+    Type: "AWS::EC2::TransitGatewayRouteTable"
+    Properties:
+      Tags: 
+      - Key: Name
+        Value: !Sub ${AWS::StackName}-Securityrtb
+      TransitGatewayId: !Ref TransitGateway
+  TransitGatewayVPNRoute:
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref OnPremCIDR
+      TransitGatewayAttachmentId: !GetAtt TransitGatewayProperties.vpn1_tgw_attachment_id
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute1:
+    Condition: 1ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR1
+      TransitGatewayAttachmentId: !Ref VPCAttachment1AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute2a:
+    Condition: 2ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR1
+      TransitGatewayAttachmentId: !Ref VPCAttachment2AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute2b:
+    Condition: 2ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR2
+      TransitGatewayAttachmentId: !Ref VPCAttachment2AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute3a:
+    Condition: 3ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR1
+      TransitGatewayAttachmentId: !Ref VPCAttachment3AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute3b:
+    Condition: 3ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR2
+      TransitGatewayAttachmentId: !Ref VPCAttachment3AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute3c:
+    Condition: 3ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR3
+      TransitGatewayAttachmentId: !Ref VPCAttachment3AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute4a:
+    Condition: 4ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR1
+      TransitGatewayAttachmentId: !Ref VPCAttachment4AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute4b:
+    Condition: 4ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR2
+      TransitGatewayAttachmentId: !Ref VPCAttachment4AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute4c:
+    Condition: 4ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR3
+      TransitGatewayAttachmentId: !Ref VPCAttachment4AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewayVPNPoolRoute4d:
+    Condition: 4ASAvCondition
+    Type: AWS::EC2::TransitGatewayRoute
+    Properties: 
+      DestinationCidrBlock: !Ref VPNPoolCIDR4
+      TransitGatewayAttachmentId: !Ref VPCAttachment4AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  TransitGatewaySpokeRouteTable:
+    Type: "AWS::EC2::TransitGatewayRouteTable"
+    Properties:
+      Tags: 
+      - Key: Name
+        Value: !Sub ${AWS::StackName}-Spokertb
+      TransitGatewayId: !Ref TransitGateway
+#------------------ TGW VPN attachment -------------------------------------------
+  CustomerGateway: 
+    Type: AWS::EC2::CustomerGateway
+    Properties: 
+      Type: ipsec.1
+      BgpAsn: !Ref OnPremFirewallASN
+      IpAddress: !Ref OnPremFirewallPublicIP
+      Tags:
+      - Key: Name
+        Value: !Sub "${AWS::StackName}-On-Premgateway"
+  VPNAttachment:
+    Type: AWS::EC2::VPNConnection
+    Properties: 
+      CustomerGatewayId: !Ref CustomerGateway
+      TransitGatewayId: !Ref TransitGateway
+      Type: ipsec.1
+      VpnTunnelOptionsSpecifications: 
+        - PreSharedKey: !Ref PreSharedKeyForVPNAttachment
+          TunnelInsideCidr: !Select [0, !Ref VPNTunnelCIDRs] 
+        - PreSharedKey: !Ref PreSharedKeyForVPNAttachment
+          TunnelInsideCidr: !Select [1, !Ref VPNTunnelCIDRs]
+      Tags:
+      - Key: Name
+        Value: !Sub "${AWS::StackName}-VPNAttachment"
+#------------------ TGW VPC attachments -------------------------------------------
+  VPCAttachment1AZ:
+    Condition: 1AZCondition
+    Type: AWS::EC2::TransitGatewayAttachment
+    Properties: 
+      SubnetIds: 
+        - !Ref TGWSubnet1
+      Tags:
+      - Key: Name
+        Value: !Sub "${AWS::StackName}-VPCAttachment"
+      TransitGatewayId: !Ref TransitGateway
+      VpcId: !Ref VPCID
+  VPCAttachment2AZ:
+    Condition: 2AZCondition
+    Type: AWS::EC2::TransitGatewayAttachment
+    Properties: 
+      SubnetIds: 
+        - !Ref TGWSubnet1
+        - !Ref TGWSubnet2
+      Tags:
+      - Key: Name
+        Value: !Sub "${AWS::StackName}-VPCAttachment"
+      TransitGatewayId: !Ref TransitGateway
+      VpcId: !Ref VPCID
+  VPCAttachment3AZ:
+    Condition: 3AZCondition
+    Type: AWS::EC2::TransitGatewayAttachment
+    Properties: 
+      SubnetIds: 
+        - !Ref TGWSubnet1
+        - !Ref TGWSubnet2
+        - !Ref TGWSubnet3
+      Tags:
+      - Key: Name
+        Value: !Sub "${AWS::StackName}-VPCAttachment"
+      TransitGatewayId: !Ref TransitGateway
+      VpcId: !Ref VPCID
+  VPCAttachment4AZ:
+    Condition: 4AZCondition
+    Type: AWS::EC2::TransitGatewayAttachment
+    Properties: 
+      SubnetIds: 
+        - !Ref TGWSubnet1
+        - !Ref TGWSubnet2
+        - !Ref TGWSubnet3
+        - !Ref TGWSubnet4
+      Tags:
+      - Key: Name
+        Value: !Sub "${AWS::StackName}-VPCAttachment"
+      TransitGatewayId: !Ref TransitGateway
+      VpcId: !Ref VPCID
+#------------------ TGW route table associations -------------------------------------------
+  CustomerGatewayTransitGatewayAssociation:
+    Type: "AWS::EC2::TransitGatewayRouteTableAssociation"
+    Properties:
+      TransitGatewayAttachmentId: !GetAtt TransitGatewayProperties.vpn1_tgw_attachment_id
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  #The VPC association works
+  VPCTransitGatewayAssociation1AZ:
+    Condition: 1AZCondition
+    Type: "AWS::EC2::TransitGatewayRouteTableAssociation"
+    Properties:
+      TransitGatewayAttachmentId: !Ref VPCAttachment1AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  VPCTransitGatewayAssociation2AZ:
+    Condition: 2AZCondition
+    Type: "AWS::EC2::TransitGatewayRouteTableAssociation"
+    Properties:
+      TransitGatewayAttachmentId: !Ref VPCAttachment2AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  VPCTransitGatewayAssociation3AZ:
+    Condition: 3AZCondition
+    Type: "AWS::EC2::TransitGatewayRouteTableAssociation"
+    Properties:
+      TransitGatewayAttachmentId: !Ref VPCAttachment3AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  VPCTransitGatewayAssociation4AZ:
+    Condition: 4AZCondition
+    Type: "AWS::EC2::TransitGatewayRouteTableAssociation"
+    Properties:
+      TransitGatewayAttachmentId: !Ref VPCAttachment4AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+#------------------ TGW route table propagations -------------------------------------------
+  EdgeRouteTablePropagation1AZ:
+    Condition: 1AZCondition
+    Type: "AWS::EC2::TransitGatewayRouteTablePropagation"
+    Properties:
+      TransitGatewayAttachmentId: !Ref VPCAttachment1AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  EdgeRouteTablePropagation2AZ:
+    Condition: 2AZCondition
+    Type: "AWS::EC2::TransitGatewayRouteTablePropagation"
+    Properties:
+      TransitGatewayAttachmentId: !Ref VPCAttachment2AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  EdgeRouteTablePropagation3AZ:
+    Condition: 3AZCondition
+    Type: "AWS::EC2::TransitGatewayRouteTablePropagation"
+    Properties:
+      TransitGatewayAttachmentId: !Ref VPCAttachment3AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  EdgeRouteTablePropagation4AZ:
+    Condition: 4AZCondition
+    Type: "AWS::EC2::TransitGatewayRouteTablePropagation"
+    Properties:
+      TransitGatewayAttachmentId: !Ref VPCAttachment4AZ
+      TransitGatewayRouteTableId: !Ref TransitGatewaySecurityRouteTable
+  RouteTableEntryPrivate1:
+    Type: AWS::EC2::Route
+    DependsOn: TransitGatewayVPNRoute
+    Properties: 
+      DestinationCidrBlock: !Ref OnPremCIDR
+      RouteTableId: !Ref PrivateSubnet1ARouteTable
+      TransitGatewayId: !Ref TransitGateway
+  RouteTableEntryPrivate2:
+    Condition: 2SubnetCondition
+    Type: AWS::EC2::Route
+    DependsOn: TransitGatewayVPNRoute
+    #DependsOn: VPCAttachment2AZ
+    Properties: 
+      DestinationCidrBlock: !Ref OnPremCIDR
+      RouteTableId: !Ref PrivateSubnet2ARouteTable
+      TransitGatewayId: !Ref TransitGateway
+  RouteTableEntryPrivate3:
+    Condition: 3SubnetCondition
+    DependsOn: TransitGatewayVPNRoute
+    #DependsOn: VPCAttachment3AZ
+    Type: AWS::EC2::Route
+    Properties: 
+      DestinationCidrBlock: !Ref OnPremCIDR
+      RouteTableId: !Ref PrivateSubnet3ARouteTable
+      TransitGatewayId: !Ref TransitGateway
+  RouteTableEntryPrivate4:
+    Condition: 4SubnetCondition
+    Type: AWS::EC2::Route
+    DependsOn: TransitGatewayVPNRoute
+    #DependsOn: VPCAttachment4AZ
+    Properties: 
+      DestinationCidrBlock: !Ref OnPremCIDR
+      RouteTableId: !Ref PrivateSubnet4ARouteTable
+      TransitGatewayId: !Ref TransitGateway
+Outputs:
+  TransitGateway:
+    Value: !Ref TransitGateway
+    Export: 
+      Name: !Sub ${AWS::StackName}-TransitGateway
+  AmazonSideAsn:
+    Description: "Amazon side ASN for the BGP session"
+    Value: !Ref AmazonSideAsn
+  VPNTunnelInsideCIDRs:
+    Description: "VPN  Tunnel CIDRs"
+    Value: !Join
+      - ','
+      - !Ref VPNTunnelCIDRs
+    Export: 
+      Name: !Sub ${AWS::StackName}-VPNTunnelInsideCIDRs
+  VPNTunnelOutsideIPs:
+    Description: "VPN Tunnel Outside IP"
+    Value: !Join
+      - ','
+      - !GetAtt TransitGatewayProperties.vpn0OutsideIps
+    Export: 
+      Name: !Sub ${AWS::StackName}-VPNTunnelOutsideIPs
+  VPNPreSharedKey:
+    Description: "VPN IPsec PreSharedKey"
+    Value: !Ref PreSharedKeyForVPNAttachment
+    Export: 
+      Name: !Sub ${AWS::StackName}-PreSharedKey

+ 0 - 0
base/cisco_vpn/security-groups.tf → base/_archive/cisco_vpn/security-groups.tf


+ 0 - 0
base/cisco_vpn/vars.tf → base/_archive/cisco_vpn/vars.tf


+ 0 - 0
base/_archive/aws_client_vpn/README.md → base/aws_client_vpn/README.md


+ 0 - 0
base/_archive/aws_client_vpn/auth.tf → base/aws_client_vpn/auth.tf


+ 0 - 0
base/_archive/aws_client_vpn/certificate.tf → base/aws_client_vpn/certificate.tf


+ 0 - 0
base/_archive/aws_client_vpn/cloudwatch.tf → base/aws_client_vpn/cloudwatch.tf


+ 0 - 0
base/_archive/aws_client_vpn/files/saml-metadata-okta-test.xml → base/aws_client_vpn/files/saml-metadata-okta-test.xml


+ 0 - 0
base/_archive/aws_client_vpn/saml.tf → base/aws_client_vpn/saml.tf


+ 0 - 0
base/_archive/aws_client_vpn/security-groups.tf → base/aws_client_vpn/security-groups.tf


+ 0 - 0
base/_archive/aws_client_vpn/terragrunt.hcl.example → base/aws_client_vpn/terragrunt.hcl.example


+ 0 - 0
base/_archive/aws_client_vpn/vars.tf → base/aws_client_vpn/vars.tf


+ 0 - 0
base/_archive/aws_client_vpn/vpn.tf → base/aws_client_vpn/vpn.tf