Skip to content

Instantly share code, notes, and snippets.

@bernadinm
Created November 30, 2017 06:35
Show Gist options
  • Save bernadinm/ac07c6897841e4730d7e71ea3ff09da4 to your computer and use it in GitHub Desktop.
Save bernadinm/ac07c6897841e4730d7e71ea3ff09da4 to your computer and use it in GitHub Desktop.
Modified Cisco CSR To Help Delete S3 Buckets and Disable Termination Protection By Default
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "(SO0001) - Transit VPC: This template creates a dedicated transit VPC with Cisco CSRs for routing traffic. ***NOTE*** You must first subscribe to the appropriate Cisco CSR marketplace BYOL or License Included AMI from the AWS Marketplace before you launch this template. Version 5",
"Parameters" : {
"KeyName" : {
"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
"Type" : "AWS::EC2::KeyPair::KeyName",
"Default" : "Lab"
},
"TerminationProtection" : {
"Description" : "Enable termination protection on the CSR EC2 instances to avoid accidential CSR termination?",
"Type" : "String",
"Default" : "No",
"AllowedValues" : ["Yes", "No"]
},
"PreferredPathTag" : {
"Description" : "Tag to use to configure a preferred CSR VPN endpoint to control traffic flow through the Transit VPC CSRs (e.g. when integrating with stateful on-prem firewalls).",
"Type" : "String",
"Default" : "transitvpc:preferred-path"
},
"SpokeTag" : {
"Description" : "Tag to use to identify spoke VPCs to connect to Transit VPC.",
"Type" : "String",
"Default" : "transitvpc:spoke"
},
"SpokeTagValue" : {
"Description" : "Tag value to use to identify spoke VPCs to connect to Transit VPC.",
"Type" : "String",
"Default" : "true"
},
"BgpAsn" : {
"Description" : "BGP ASN to use for Transit VPC.",
"Type" : "String",
"Default" : "64512"
},
"VpcCidr" : {
"Description" : "CIDR block for Transit VPC.",
"Type" : "String",
"Default" : "100.64.127.224/27"
},
"PubSubnet1" : {
"Description" : "Address range for Transit VPC subnet to be created in AZ1.",
"Type" : "String",
"Default" : "100.64.127.224/28"
},
"PubSubnet2" : {
"Description" : "Address range for Transit VPC subnet to be created in AZ2.",
"Type" : "String",
"Default" : "100.64.127.240/28"
},
"CSRType" : {
"Description" : "Maximum network througput required for CSR instances.",
"Type" : "String",
"Default" : "2x500Mbps",
"AllowedValues" : [ "2x500Mbps","2x1Gbps", "2x2Gbps", "2x4.5Gbps" ]
},
"LicenseModel" : {
"Description" : "Choose between BYOL (Bring Your Own License) and License Included license models. Remember to first subscribe the the appropriate Marketplace AMI!",
"Type" : "String",
"Default" : "LicenseIncluded",
"AllowedValues" : ["LicenseIncluded", "BYOL"]
},
"S3Prefix" : {
"Description" : "S3 prefix to append before S3 key names.",
"Type" : "String",
"Default" : "vpnconfigs/",
"AllowedPattern": "^[a-z0-9A-Z_\/\\-\\.]*\/$"
},
"AccountId" : {
"Description" : "Another AWS Account ID to authorize access to VPN Config S3 bucket (for example bucket and KMS key policies).",
"Type" : "String",
"Default" : ""
},
"PubSubnet1AZ" : {
"Description" : "Optional: Availability Zone number for Public Subnet1.",
"Type" : "String",
"Default": "0",
"AllowedValues" : ["0", "1", "2", "3", "4", "5"]
},
"PubSubnet2AZ" : {
"Description" : "Optional: Availability Zone number for Public Subnet2.",
"Type" : "String",
"Default": "1",
"AllowedValues" : ["0", "1", "2", "3", "4", "5"]
}
},
"Conditions" : {
"AuthorizeAnotherAccount" : { "Fn::Not" : [ { "Fn::Equals" : [ { "Ref": "AccountId"}, "" ]} ]},
"EnableTerm" : {"Fn::Equals" : [{"Ref" : "TerminationProtection"}, "Yes"]}
},
"Metadata" : {
"AWS::CloudFormation::Interface" : {
"ParameterGroups" : [
{
"Label" : { "default":"Cisco CSR Configuration" },
"Parameters" : [ "CSRType", "KeyName", "LicenseModel", "TerminationProtection" ]
},
{
"Label" : { "default":"AWS Service Configuration" },
"Parameters" : [ "S3Prefix", "AccountId" ]
},
{
"Label" : { "default" : "Network Configuration" },
"Parameters" : [ "VpcCidr", "PubSubnet1", "PubSubnet2","BgpAsn","SpokeTag","SpokeTagValue","PreferredPathTag" ]
},
{
"Label" : { "default" : "Optional AZ Configuration" },
"Parameters" : [ "PubSubnet1AZ", "PubSubnet2AZ" ]
}
],
"ParameterLabels" : {
"BgpAsn" : { "default" : "Transit VPC BGP ASN" },
"SpokeTag" : { "default" : "Spoke VPC Tag Name" },
"SpokeTagValue" : { "default" : "Spoke VPC Tag Value" },
"PreferredPathTag" : { "default" : "Preferred VPN Endpoint Tag Name" },
"VpcCidr" : { "default" : "Transit VPC CIDR Block" },
"PubSubnet1" : { "default" : "1st Subnet Network" },
"PubSubnet2" : { "default" : "2nd Subnet Network" },
"PubSubnet1AZ" : { "default" : "1st Subnet AZ #" },
"PubSubnet2AZ" : { "default" : "2nd Subnet AZ #" },
"CSRType" : { "default" : "CSR Throughput Requirements" },
"KeyName" : { "default" : "SSH Key to access CSR" },
"S3Prefix" : { "default" : "Prefix for S3 Objects" },
"LicenseModel" : { "default" : "License Model" },
"TerminationProtection" : { "default" : "Enable Termination Protection" },
"AccountId" : { "default" : "Additional AWS Account ID (Optional)" }
}
}
},
"Mappings" : {
"Function" : {
"Configurator" : {
"S3Bucket" : "solutions",
"S3Key" : "transit-vpc/latest/transit-vpc-push-cisco-config.zip",
"Name" : "cisco-configurator",
"Handler": "transit_vpc_push_cisco_config/lambda_function.lambda_handler",
"Description": "Transit VPC: This function is invoked when a generic VPN configuration is placed in an S3 bucket - it converts the generic information into Cisco IOS specific commands and pushes the config to transit VPC routers.",
"Runtime": "python2.7",
"Timeout": "300",
"MemorySize": "128"
},
"Poller" : {
"S3Bucket" : "solutions",
"S3Key" : "transit-vpc/latest/transit-vpc-poller.zip",
"Name" : "vgw-poller",
"Handler": "transit-vpc-poller.lambda_handler",
"Description": "Transit VPC: Poller function responsible for identifying specifically tagged VGWs and creating VPN connections to transit VPC.",
"Runtime": "python2.7",
"Timeout": "120",
"MemorySize": "128"
},
"Csr" : {
"UserName" : "automate",
"PasswordLength" : "15",
"PrivateKey" : "prikey.pem",
"PublicKey" : "pubkey.pem"
}
},
"CiscoCsrAMI" : {
"ap-south-1" : { "BYOL" : "ami-88bbfee7", "LicenseIncluded" : "ami-79bffa16" },
"eu-west-2" : { "BYOL" : "ami-a30414c7", "LicenseIncluded" : "ami-7a04141e" },
"eu-west-1" : { "BYOL" : "ami-40946d39", "LicenseIncluded" : "ami-3e906947" },
"ap-northeast-2" : { "BYOL" : "ami-2914cc47", "LicenseIncluded" : "ami-2b14cc45" },
"ap-northeast-1" : { "BYOL" : "ami-53a75835", "LicenseIncluded" : "ami-3da6595b" },
"sa-east-1" : { "BYOL" : "ami-eb9ded87", "LicenseIncluded" : "ami-7e80f012" },
"ca-central-1" : { "BYOL" : "ami-6269d706", "LicenseIncluded" : "ami-6369d707" },
"ap-southeast-1" : { "BYOL" : "ami-d5c7a6b6", "LicenseIncluded" : "ami-4fc9a82c" },
"ap-southeast-2" : { "BYOL" : "ami-e96d778a", "LicenseIncluded" : "ami-3c62785f" },
"eu-central-1" : { "BYOL" : "ami-74309b1b", "LicenseIncluded" : "ami-77309b18" },
"us-east-1" : { "BYOL" : "ami-bcbfb9c7", "LicenseIncluded" : "ami-46b1b73d" },
"us-east-2" : { "BYOL" : "ami-b61437d3", "LicenseIncluded" : "ami-8f1536ea" },
"us-west-1" : { "BYOL" : "ami-99e5d0f9", "LicenseIncluded" : "ami-c5facfa5" },
"us-west-2" : { "BYOL" : "ami-e4d43d9c", "LicenseIncluded" : "ami-29d33a51" }
},
"CsrInstance" : {
"2x500Mbps" : { "Type" : "c4.large", "Bandwidth" : "500000" },
"2x1Gbps" : { "Type" : "c4.xlarge", "Bandwidth" : "1000000" },
"2x2Gbps" : { "Type" : "c4.2xlarge", "Bandwidth" : "2000000" },
"2x4.5Gbps" : { "Type" : "c4.4xlarge", "Bandwidth" : "4500000" }
},
"Send" : {
"AnonymousUsage" : { "Data" : "Yes" }
}
},
"Resources" : {
"VPNConfigS3Bucket" : {
"Type" : "AWS::S3::Bucket",
"DeletionPolicy" : "Delete"
},
"VPNConfigBucketPolicy" : {
"Type" : "AWS::S3::BucketPolicy",
"Properties" : {
"Bucket" : {"Ref" : "VPNConfigS3Bucket" },
"PolicyDocument": {
"Statement":[ {
"Sid": "DenyUnEncryptedObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "VPNConfigS3Bucket" },"/",{ "Ref" : "S3Prefix" }, "*" ]]},
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
},
{
"Action":["s3:GetObject", "s3:PutObject", "s3:PutObjectAcl"],
"Effect":"Allow",
"Resource": { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "VPNConfigS3Bucket" },"/",{ "Ref" : "S3Prefix" }, "*" ]]},
"Principal": {
"AWS" : [{ "Fn::Join" : ["", ["arn:aws:iam::",{"Fn::If": ["AuthorizeAnotherAccount", {"Ref" : "AccountId" }, { "Ref" : "AWS::AccountId" } ]}, ":root" ]]}]
}
}]
}
}
},
"KMSKey" : {
"Type" : "AWS::KMS::Key",
"Properties" : {
"Description" : "TransitVPC CMK for S3 SSE-KMS",
"KeyPolicy" : {
"Version": "2012-10-17",
"Id": "transit-vpc-1",
"Statement": [ {
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": { "AWS": [
{ "Fn::Join" : ["", ["arn:aws:iam::",{ "Ref" : "AWS::AccountId" }, ":root" ]]}
] },
"Action": [
"kms:*"
],
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": { "AWS": [
{ "Fn::Join" : ["", ["arn:aws:iam::",{"Fn::If": ["AuthorizeAnotherAccount", {"Ref" : "AccountId" }, { "Ref" : "AWS::AccountId" } ]}, ":root" ]]},
{ "Fn::GetAtt" : ["SolutionHelperRole", "Arn"] },
{ "Fn::GetAtt" : ["CiscoConfigFunctionRole", "Arn"] },
{ "Fn::GetAtt" : ["TransitVpcPollerRole", "Arn"] }
] },
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
} ]
}
}
},
"KMSKeyAlias" : {
"Type" : "AWS::KMS::Alias",
"Properties" : {
"AliasName" : { "Fn::Join": ["", [ "alias/", { "Ref" : "AWS::StackName" }, "-key" ]] },
"TargetKeyId" : {
"Ref" : "KMSKey"
}
}
},
"TransitVPC" : {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"CidrBlock" : { "Ref" : "VpcCidr" },
"Tags" : [
{ "Key" : "Name", "Value" : "Transit VPC" }
]
}
},
"VPCPubSub1" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"VpcId" : { "Ref" : "TransitVPC" },
"CidrBlock" : { "Ref" : "PubSubnet1" },
"AvailabilityZone" : { "Fn::Select": [{ "Ref": "PubSubnet1AZ"}, {"Fn::GetAZs": ""}] },
"Tags" : [
{ "Key" : "Network", "Value" : "Public" },
{ "Key" : "Name", "Value" : "Transit VPC Subnet1" }
]
}
},
"VPCPubSub2" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"VpcId" : { "Ref" : "TransitVPC" },
"CidrBlock" : { "Ref" : "PubSubnet2" },
"AvailabilityZone" : { "Fn::Select": [{ "Ref": "PubSubnet2AZ"}, {"Fn::GetAZs": ""}] },
"Tags" : [
{ "Key" : "Network", "Value" : "Public" },
{ "Key" : "Name", "Value" : "Transit VPC Subnet2" }
]
}
},
"IGW" : {
"Type" : "AWS::EC2::InternetGateway",
"Properties" : {
"Tags" : [
{ "Key" : "Name", "Value" : "Transit VPC IGW" }
]
}
},
"IGWToInternet" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"Properties" : {
"VpcId" : { "Ref" : "TransitVPC" },
"InternetGatewayId" : { "Ref" : "IGW" }
}
},
"VPCRouteTable" : {
"Type" : "AWS::EC2::RouteTable",
"Properties" : {
"VpcId" : { "Ref" : "TransitVPC" },
"Tags" : [
{ "Key" : "Network", "Value" : "Public" },
{ "Key" : "Name", "Value" : "Transit VPC" }
]
}
},
"VPCPublicRoute" : {
"Type" : "AWS::EC2::Route",
"Properties" : {
"RouteTableId" : { "Ref" : "VPCRouteTable" },
"DestinationCidrBlock" : "0.0.0.0/0",
"GatewayId" : { "Ref" : "IGW" }
}
},
"S3Endpoint" : {
"Type" : "AWS::EC2::VPCEndpoint",
"Properties" : {
"PolicyDocument" : {
"Version":"2012-10-17",
"Statement":[{
"Effect":"Allow",
"Principal": "*",
"Action":["s3:*"],
"Resource":["*"]
}]
},
"RouteTableIds" : [ {"Ref" : "VPCRouteTable"} ],
"ServiceName" : { "Fn::Join": [ "", [ "com.amazonaws.", { "Ref": "AWS::Region" }, ".s3" ] ] },
"VpcId" : {"Ref" : "TransitVPC"}
}
},
"VPCPubSubnetRouteTableAssociation1" : {
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
"Properties" : {
"SubnetId" : { "Ref" : "VPCPubSub1" },
"RouteTableId" : { "Ref" : "VPCRouteTable" }
}
},
"VPCPubSubnetRouteTableAssociation2" : {
"Type" : "AWS::EC2::SubnetRouteTableAssociation",
"Properties" : {
"SubnetId" : { "Ref" : "VPCPubSub2" },
"RouteTableId" : { "Ref" : "VPCRouteTable" }
}
},
"CsrEip1" : {
"Type" : "AWS::EC2::EIP",
"Properties" : {
"Domain" : "vpc",
"InstanceId" : { "Ref" : "VpcCsr1" }
}
},
"CsrEip2" : {
"Type" : "AWS::EC2::EIP",
"Properties" : {
"Domain" : "vpc",
"InstanceId" : { "Ref" : "VpcCsr2" }
}
},
"VpcCsr1" : {
"Type" : "AWS::EC2::Instance",
"Metadata" : {
"Comment1" : "Launch Cisco CSR1"
},
"Properties" : {
"InstanceType" : { "Fn::FindInMap" : [ "CsrInstance", { "Ref" : "CSRType" }, "Type"] },
"KeyName" : { "Ref" : "KeyName" },
"DisableApiTermination" : {"Fn::If": ["EnableTerm", true, false ]},
"ImageId" : { "Fn::FindInMap" : [ "CiscoCsrAMI", { "Ref" : "AWS::Region" }, { "Ref" : "LicenseModel" } ] },
"SubnetId" : { "Ref" : "VPCPubSub1" },
"SecurityGroupIds" : [{ "Ref" : "CSRSecurityGroup" }],
"Tags" : [
{ "Key" : "Name", "Value" : "Transit VPC CSR1" }
],
"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
"ios-config-1=\"username ",
{ "Fn::FindInMap" : [ "Function", "Csr", "UserName"]},
" priv 15 pass ",
{ "Fn::GetAtt" : [ "CreateRandomPassword" , "Password" ] },"\"\n",
"ios-config-2=\"service password-encryption\"\n",
"ios-config-3=\"crypto isakmp policy 200\"\n",
"ios-config-4=\"encryption aes 128\"\n",
"ios-config-5=\"authentication pre-share\"\n",
"ios-config-6=\"group 2\"\n",
"ios-config-7=\"lifetime 28800\"\n",
"ios-config-8=\"hash sha\"\n",
"ios-config-9=\"crypto ipsec transform-set ipsec-prop-vpn-aws esp-aes 128 esp-sha-hmac\"\n",
"ios-config-10=\"mode tunnel\"\n",
"ios-config-11=\"crypto ipsec df-bit clear\"\n",
"ios-config-12=\"crypto isakmp keepalive 15 10 on-demand\"\n",
"ios-config-13=\"crypto ipsec security-association replay window-size 1024\"\n",
"ios-config-14=\"crypto ipsec fragmentation before-encryption\"\n",
"ios-config-15=\"crypto ipsec profile ipsec-vpn-aws\"\n",
"ios-config-16=\"set pfs group2\"\n",
"ios-config-17=\"set security-association lifetime seconds 3600\"\n",
"ios-config-18=\"set transform-set ipsec-prop-vpn-aws\"\n",
"ios-config-19=\"router bgp ", { "Ref" : "BgpAsn" },"\"\n",
"ios-config-20=\"bgp log-neighbor-changes\"\n",
"ios-config-21=\"ip vrf vpn0\"\n",
"ios-config-22=\"rd ", { "Ref" : "BgpAsn" }, ":0\"\n",
"ios-config-23=\"ip ssh pubkey-chain\"\n",
"ios-config-24=\"username ", { "Fn::FindInMap" : [ "Function", "Csr", "UserName"]}, "\"\n",
"ios-config-25=\"key-hash ssh-rsa ", { "Fn::GetAtt" : [ "CreateRsaKey", "Fingerprint" ] },"\"\n",
"ios-config-26=\"ip ssh server algorithm authentication publickey\"\n",
"ios-config-27=\"ip ssh maxstartups 1\"\n"
]]}}
}
},
"VpcCsr2" : {
"Type" : "AWS::EC2::Instance",
"Metadata" : {
"Comment1" : "Launch Cisco CSR2"
},
"Properties" : {
"InstanceType" : { "Fn::FindInMap" : [ "CsrInstance", { "Ref" : "CSRType" }, "Type"] },
"KeyName" : { "Ref" : "KeyName" },
"DisableApiTermination" : {"Fn::If": ["EnableTerm", true, false ]},
"ImageId" : { "Fn::FindInMap" : [ "CiscoCsrAMI", { "Ref" : "AWS::Region" }, { "Ref" : "LicenseModel" } ] },
"SubnetId" : { "Ref" : "VPCPubSub2" },
"SecurityGroupIds" : [{ "Ref" : "CSRSecurityGroup" }],
"Tags" : [
{ "Key" : "Name", "Value" : "Transit VPC CSR2" }
],
"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
"ios-config-1=\"username ",
{ "Fn::FindInMap" : [ "Function", "Csr", "UserName"]},
" priv 15 pass ",
{ "Fn::GetAtt" : [ "CreateRandomPassword" , "Password" ] },"\"\n",
"ios-config-2=\"service password-encryption\"\n",
"ios-config-3=\"crypto isakmp policy 200\"\n",
"ios-config-4=\"encryption aes 128\"\n",
"ios-config-5=\"authentication pre-share\"\n",
"ios-config-6=\"group 2\"\n",
"ios-config-7=\"lifetime 28800\"\n",
"ios-config-8=\"hash sha\"\n",
"ios-config-9=\"crypto ipsec transform-set ipsec-prop-vpn-aws esp-aes 128 esp-sha-hmac\"\n",
"ios-config-10=\"mode tunnel\"\n",
"ios-config-11=\"crypto ipsec df-bit clear\"\n",
"ios-config-12=\"crypto isakmp keepalive 15 10 on-demand\"\n",
"ios-config-13=\"crypto ipsec security-association replay window-size 1024\"\n",
"ios-config-14=\"crypto ipsec fragmentation before-encryption\"\n",
"ios-config-15=\"crypto ipsec profile ipsec-vpn-aws\"\n",
"ios-config-16=\"set pfs group2\"\n",
"ios-config-17=\"set security-association lifetime seconds 3600\"\n",
"ios-config-18=\"set transform-set ipsec-prop-vpn-aws\"\n",
"ios-config-19=\"router bgp ", { "Ref" : "BgpAsn" },"\"\n",
"ios-config-20=\"bgp log-neighbor-changes\"\n",
"ios-config-21=\"ip vrf vpn0\"\n",
"ios-config-22=\"rd ", { "Ref" : "BgpAsn" }, ":0\"\n",
"ios-config-23=\"ip ssh pubkey-chain\"\n",
"ios-config-24=\"username ", { "Fn::FindInMap" : [ "Function", "Csr", "UserName"]}, "\"\n",
"ios-config-25=\"key-hash ssh-rsa ", { "Fn::GetAtt" : [ "CreateRsaKey", "Fingerprint" ] },"\"\n",
"ios-config-26=\"ip ssh server algorithm authentication publickey\"\n",
"ios-config-27=\"ip ssh maxstartups 1\"\n"
]]}}
}
},
"SolutionHelperRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version" : "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
} ]
},
"Path": "/"
}
},
"SolutionHelperRolePolicy" : {
"Type": "AWS::IAM::Policy",
"Properties": {
"Roles" : [ { "Ref" : "SolutionHelperRole" } ],
"PolicyName": "Solution_Helper_Permissions",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": { "Fn::Join" : ["", ["arn:aws:logs:",{"Ref" : "AWS::Region"},":",{ "Ref" : "AWS::AccountId" }, ":log-group:/aws/lambda/*" ]]}
},
{
"Effect": "Allow",
"Action": [
"s3:PutBucketNotification"
],
"Resource": { "Fn::Join": ["", ["arn:aws:s3:::", { "Ref" : "VPNConfigS3Bucket" } ]] }
},
{
"Effect": "Allow",
"Action": [
"lambda:*",
"events:*",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSubnets",
"ec2:DescribeVpcs"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:PassRole"
],
"Resource": [{ "Fn::GetAtt" : [ "CiscoConfigFunctionRole", "Arn" ] }, { "Fn::GetAtt" : [ "TransitVpcPollerRole", "Arn" ] }]
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": { "Fn::Join": ["", ["arn:aws:s3:::", { "Ref" : "VPNConfigS3Bucket" }, "/", {"Ref": "S3Prefix"}, "*" ]] }
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::solutions-reference/*"
}
]
}
}
},
"SolutionHelper": {
"Type": "AWS::Lambda::Function",
"DependsOn" : "SolutionHelperRolePolicy",
"Properties": {
"Handler": "solution-helper.lambda_handler",
"Role": { "Fn::GetAtt" : [ "SolutionHelperRole" , "Arn" ] },
"Description": "Transit VPC: CloudFormation custom resource function invoked during transit VPC CloudFormation create, update, and delete stack operations.",
"Code": {
"S3Bucket": { "Fn::Join": ["", ["solutions-", {"Ref" : "AWS::Region"}]] },
"S3Key": "library/solution-helper/v3/solution-helper.zip"
},
"Runtime": "python2.7",
"Timeout": "60"
}
},
"CreateRsaKey": {
"Type": "Custom::LoadLambda",
"Properties": {
"ServiceToken": { "Fn::GetAtt" : ["SolutionHelper", "Arn"] },
"Region": { "Ref": "AWS::Region" },
"CreateSshKey" : { "Fn::Join": ["", [
"{ 'Bucket' : '",{ "Ref" : "VPNConfigS3Bucket" },"', ",
"'SSEKMSKeyId' : 'arn:aws:kms:",{"Ref" : "AWS::Region"},":",{ "Ref" : "AWS::AccountId" }, ":key/", { "Ref" : "KMSKey" }, "', ",
"'PrivateKey' : '", { "Ref" : "S3Prefix" }, { "Fn::FindInMap" : [ "Function", "Csr", "PrivateKey"]}, "', ",
"'PublicKey' : '", { "Ref" : "S3Prefix" }, { "Fn::FindInMap" : [ "Function", "Csr", "PublicKey"]}, "' ",
"}"
]] }
}
},
"CreateRandomPassword": {
"Type": "Custom::LoadLambda",
"Properties": {
"ServiceToken": { "Fn::GetAtt" : ["SolutionHelper", "Arn"] },
"Region": { "Ref": "AWS::Region" },
"CreateRandomPassword" : { "Fn::FindInMap" : [ "Function", "Csr", "PasswordLength"]},
"RandomPasswordSpecialCharacters": "False"
}
},
"CiscoConfigFunctionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version" : "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
} ]
},
"Path": "/"
}
},
"CiscoConfigFunctionRolePolicy" : {
"Type": "AWS::IAM::Policy",
"Properties": {
"Roles" : [ { "Ref" : "CiscoConfigFunctionRole" } ],
"PolicyName": "Cisco_Config_Permissions",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": { "Fn::Join" : ["", ["arn:aws:logs:",{"Ref" : "AWS::Region"},":",{ "Ref" : "AWS::AccountId" }, ":log-group:/aws/lambda/*" ]]}
},
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DetachNetworkInterface",
"ec2:DeleteNetworkInterface"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": { "Fn::Join": ["", ["arn:aws:s3:::", { "Ref" : "VPNConfigS3Bucket" }, "/", {"Ref": "S3Prefix"}, "*" ]] }
}
]
}
}
},
"CiscoConfigFunction": {
"DependsOn": [
"CiscoConfigFunctionRolePolicy"
],
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName" : { "Fn::Join": ["-", [ { "Ref" : "AWS::StackName" }, { "Fn::FindInMap" : [ "Function", "Configurator", "Name"]} ]] },
"Code": {
"S3Bucket": { "Fn::Join": ["", [ { "Fn::FindInMap" : [ "Function", "Configurator", "S3Bucket"]}, "-", {"Ref": "AWS::Region"} ]] },
"S3Key": { "Fn::FindInMap" : [ "Function", "Configurator", "S3Key"]}
},
"MemorySize": { "Fn::FindInMap" : [ "Function", "Configurator", "MemorySize"]},
"Handler": { "Fn::FindInMap" : [ "Function", "Configurator", "Handler"]},
"Role": {"Fn::GetAtt": ["CiscoConfigFunctionRole", "Arn"]},
"Timeout": { "Fn::FindInMap" : [ "Function", "Configurator", "Timeout"]},
"Runtime": { "Fn::FindInMap" : [ "Function", "Configurator", "Runtime"]},
"Description": { "Fn::FindInMap" : [ "Function", "Configurator", "Description"]},
"VpcConfig" : {
"SecurityGroupIds" : [ { "Ref" : "CiscoConfigSecurityGroup" } ],
"SubnetIds" : [ { "Ref" : "VPCPubSub1" }, { "Ref" : "VPCPubSub2" } ]
},
"Environment": {
"Variables": {
"CONFIG_FILE": "transit_vpc_config.txt",
"LOG_LEVEL":"INFO"
}
}
}
},
"CiscoConfigS3Event": {
"Type": "Custom::LoadLambda",
"Properties": {
"ServiceToken": { "Fn::GetAtt" : ["SolutionHelper", "Arn"] },
"FunctionName": { "Fn::Join": ["-", [ { "Ref" : "AWS::StackName" }, { "Fn::FindInMap" : [ "Function", "Configurator", "Name"]} ]] },
"LambdaArn": { "Fn::GetAtt" : ["CiscoConfigFunction", "Arn"] },
"S3Event" : { "Fn::Join": ["", [
"{ 'Bucket' : '",{ "Ref" : "VPNConfigS3Bucket" },"', ",
"'EventPattern' : {",
"'LambdaFunctionConfigurations' : [ {",
"'LambdaFunctionArn': '", { "Fn::GetAtt" : ["CiscoConfigFunction", "Arn"] }, "',",
"'Events': ['s3:ObjectCreated:Put' ],",
"'Filter': {",
"'Key': {",
"'FilterRules': [ {",
"'Name': 'prefix',",
"'Value': '",{ "Ref" : "S3Prefix" },"'",
"}, {",
"'Name': 'suffix',",
"'Value': '.conf'",
"} ] } }",
"} ] }",
"}"
]] }
}
},
"TransitVpcS3Config": {
"Type": "Custom::LoadLambda",
"Properties": {
"ServiceToken": { "Fn::GetAtt" : ["SolutionHelper", "Arn"] },
"StoreInS3KMS" : { "Fn::Join": ["", [
"[{ 'Bucket' : '",{ "Ref" : "VPNConfigS3Bucket" },"', ",
"'Key' : '", { "Ref" : "S3Prefix" }, "transit_vpc_config.txt', ",
"'SSEKMSKeyId' : 'arn:aws:kms:",{"Ref" : "AWS::Region"},":",{ "Ref" : "AWS::AccountId" }, ":key/", { "Ref" : "KMSKey" }, "', ",
"'Body': \"{",
"'UUID':'",{"Fn::GetAtt": [ "CreateUniqueID", "UUID" ] },"',",
"'SENDDATA':'",{ "Fn::FindInMap" : [ "Send", "AnonymousUsage", "Data"]},"',",
"'EIP1':'",{ "Ref" : "CsrEip1" },"',",
"'EIP2':'",{ "Ref" : "CsrEip2" },"',",
"'PIP1':'",{ "Fn::GetAtt" : [ "VpcCsr1", "PrivateIp" ] },"',",
"'PIP2':'",{ "Fn::GetAtt" : [ "VpcCsr2", "PrivateIp" ] },"',",
"'BGP_ASN':",{ "Ref" : "BgpAsn" },",",
"'PREFERRED_PATH_TAG':'",{ "Ref" : "PreferredPathTag" },"',",
"'HUB_TAG':'",{ "Ref" : "SpokeTag" },"',",
"'HUB_TAG_VALUE':'",{ "Ref" : "SpokeTagValue" },"',",
"'USER_NAME':'",{ "Fn::FindInMap" : [ "Function", "Csr", "UserName"]},"',",
"'PRIVATE_KEY':'",{ "Fn::FindInMap" : [ "Function", "Csr", "PrivateKey"]},"',",
"'PUBLIC_KEY':'",{ "Fn::GetAtt" : [ "CreateRsaKey", "PubKey" ] },"',",
"'PASSWORD':'",{ "Fn::GetAtt" : [ "CreateRandomPassword" , "Password" ] },"',",
"'KMS_KEY':'arn:aws:kms:",{"Ref" : "AWS::Region"},":",{ "Ref" : "AWS::AccountId" }, ":key/", { "Ref" : "KMSKey" },"'",
"}\"",
"}]"
]] }
}
},
"TransitVpcPollerRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version" : "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
} ]
},
"Path": "/"
}
},
"TransitVpcPollerRolePolicy" : {
"Type": "AWS::IAM::Policy",
"Properties": {
"Roles" : [ { "Ref" : "TransitVpcPollerRole" } ],
"PolicyName": "Transit_VPC_Poller_Function_Permissions",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": { "Fn::Join" : ["", ["arn:aws:logs:",{"Ref" : "AWS::Region"},":",{ "Ref" : "AWS::AccountId" }, ":log-group:/aws/lambda/*" ]]}
},
{
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"ec2:CreateTags",
"ec2:CreateCustomerGateway",
"ec2:DeleteCustomerGateway",
"ec2:CreateVpnConnection",
"ec2:DeleteVpnConnection"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject"
],
"Resource": { "Fn::Join": ["", ["arn:aws:s3:::", { "Ref" : "VPNConfigS3Bucket" }, "/", {"Ref": "S3Prefix"}, "*" ]] }
}
]
}
}
},
"PollerFunction": {
"DependsOn": [
"TransitVpcPollerRolePolicy",
"CiscoConfigFunction",
"TransitVpcS3Config"
],
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName" : { "Fn::Join": ["-", [ { "Ref" : "AWS::StackName" }, { "Fn::FindInMap" : [ "Function", "Poller", "Name"]} ]] },
"Code": {
"S3Bucket": { "Fn::Join": ["", [ { "Fn::FindInMap" : [ "Function", "Poller", "S3Bucket"]}, "-", {"Ref": "AWS::Region"} ]] },
"S3Key": { "Fn::FindInMap" : [ "Function", "Poller", "S3Key"]}
},
"MemorySize": { "Fn::FindInMap" : [ "Function", "Poller", "MemorySize"]},
"Handler": { "Fn::FindInMap" : [ "Function", "Poller", "Handler"]},
"Role": {"Fn::GetAtt": ["TransitVpcPollerRole", "Arn"]},
"Timeout": { "Fn::FindInMap" : [ "Function", "Poller", "Timeout"]},
"Runtime": { "Fn::FindInMap" : [ "Function", "Poller", "Runtime"]},
"Description": { "Fn::FindInMap" : [ "Function", "Poller", "Description"]},
"Environment": {
"Variables": {
"BUCKET_NAME": { "Ref" : "VPNConfigS3Bucket" },
"BUCKET_PREFIX": { "Ref" : "S3Prefix" },
"CONFIG_FILE": "transit_vpc_config.txt",
"LOG_LEVEL":"INFO"
}
}
}
},
"PollerEvent": {
"Type": "AWS::Events::Rule",
"Properties": {
"Description": "Transit VPC: Rule to trigger VGW-Poller every minute to find VGWs that need to be attached to the transit VPC.",
"ScheduleExpression": "cron(* * * * ? *)",
"State": "ENABLED",
"Targets": [ {
"Id": { "Fn::Join": ["-", [ { "Ref" : "AWS::StackName" },"VGW-Poller-1min" ]] },
"Arn": { "Fn::GetAtt": [ "PollerFunction", "Arn" ] }
} ]
}
},
"PermissionForPollerEvent": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": { "Ref": "PollerFunction" },
"Action": "lambda:InvokeFunction",
"Principal": "events.amazonaws.com",
"SourceArn": { "Fn::GetAtt": ["PollerEvent", "Arn"] }
}
},
"CSRSecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "CSR Security Group Rules",
"VpcId" : { "Ref" : "TransitVPC" },
"SecurityGroupIngress" : [
{ "IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "SourceSecurityGroupId" : { "Ref" : "CiscoConfigSecurityGroup" }}
],
"SecurityGroupEgress" : [
{ "IpProtocol" : "-1", "FromPort" : "0", "ToPort" : "65535", "CidrIp" : "0.0.0.0/0" } ]
}
},
"CiscoConfigSecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Transit VPC Automation Security Group Rules",
"VpcId" : { "Ref" : "TransitVPC" },
"SecurityGroupEgress" : [{ "IpProtocol" : "tcp", "FromPort" : "443", "ToPort" : "443", "CidrIp" : "0.0.0.0/0" }]
}
},
"SSHtoCSR": {
"Type": "AWS::EC2::SecurityGroupEgress",
"Properties":{
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"DestinationSecurityGroupId": {
"Fn::GetAtt": [
"CSRSecurityGroup",
"GroupId"
]
},
"GroupId": {
"Fn::GetAtt": [
"CiscoConfigSecurityGroup",
"GroupId"
]
}
}
},
"CSR1RecoveryAlarm": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmDescription": "Trigger a recovery when CSR1 instance status check fails for 15 consecutive minutes.",
"Namespace": "AWS/EC2" ,
"MetricName": "StatusCheckFailed_System",
"Statistic": "Minimum",
"Period": "60",
"EvaluationPeriods": "15",
"ComparisonOperator": "GreaterThanThreshold",
"Threshold": "0",
"AlarmActions": [ {"Fn::Join" : ["", ["arn:aws:automate:", { "Ref" : "AWS::Region" }, ":ec2:recover" ]]} ],
"Dimensions": [{"Name": "InstanceId","Value": {"Ref": "VpcCsr1"}}]
}
},
"CSR2RecoveryAlarm": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmDescription": "Trigger a recovery when CSR2 instance status check fails for 15 consecutive minutes.",
"Namespace": "AWS/EC2" ,
"MetricName": "StatusCheckFailed_System",
"Statistic": "Minimum",
"Period": "60",
"EvaluationPeriods": "15",
"ComparisonOperator": "GreaterThanThreshold",
"Threshold": "0",
"AlarmActions": [ {"Fn::Join" : ["", ["arn:aws:automate:", { "Ref" : "AWS::Region" }, ":ec2:recover" ]]} ],
"Dimensions": [{"Name": "InstanceId","Value": {"Ref": "VpcCsr2"}}]
}
},
"CreateUniqueID": {
"Type": "Custom::LoadLambda",
"Properties": {
"ServiceToken": { "Fn::GetAtt": ["SolutionHelper", "Arn"] },
"Region": { "Ref": "AWS::Region" },
"CreateUniqueID": "true"
}
},
"SendingData": {
"Type": "Custom::LoadLambda",
"Properties": {
"ServiceToken": { "Fn::GetAtt": ["SolutionHelper", "Arn"] },
"SendAnonymousData": { "Fn::Join": ["", [
"{ 'Solution' : '", "SO0001", "', ",
"'UUID' : '", {"Fn::GetAtt": ["CreateUniqueID", "UUID"]}, "', ",
"'Data': {", "'CSRType': '", {"Ref": "CSRType"}, "',",
"'LicenseModel': '", {"Ref": "LicenseModel"}, "',",
"'TerminationProtection': '", {"Ref": "TerminationProtection"}, "',",
"'CreateVPC': 'Yes',",
"'SendAnonymousData': '", { "Fn::FindInMap" : [ "Send", "AnonymousUsage", "Data"]}, "'",
"}",
"}"
]]
}
}
}
},
"Outputs" : {
"CSR1" : {
"Description" : "IP Address for CSR1",
"Value" : { "Fn::GetAtt" : [ "VpcCsr1", "PublicIp" ] }
},
"CSR2" : {
"Description" : "IP Address for CSR2",
"Value" : { "Fn::GetAtt" : [ "VpcCsr2", "PublicIp" ] }
},
"ConfigS3Bucket" : {
"Description" : "S3 bucket for storing VPN configuration information.",
"Value" : { "Ref" : "VPNConfigS3Bucket" }
},
"BucketPrefix" : {
"Description" : "S3 prefix for storing VPN configuration information.",
"Value" : { "Ref" : "S3Prefix" }
},
"SpokeVPCTag" : {
"Description" : "Tag used to identify spoke VPCs.",
"Value" : { "Ref": "SpokeTag" }
},
"SpokeVPCTagValue" : {
"Description" : "Tag valued used to idenfity spoke VPCs.",
"Value" : { "Ref": "SpokeTagValue" }
},
"PreferredPathTagName" : {
"Description" : "Tag used to identify the spoke VPC preferred path.",
"Value" : { "Ref": "PreferredPathTag" }
},
"UUID": {
"Description": "Newly created random UUID.",
"Value": { "Fn::GetAtt": [ "CreateUniqueID", "UUID" ] }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment