├── .github └── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── lambda ├── auto-sg-updater.zip └── auto_sg_updater.py └── templates ├── master.yml └── prerequisites.yml /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/awslabs/aws-automating-security-group-updates/issues), or [recently closed](https://github.com/awslabs/aws-automating-security-group-updates/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/awslabs/aws-automating-security-group-updates/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/awslabs/aws-automating-security-group-updates/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aws-automating-security-group-updates 2 | This repository contains the artifacts that will be part of a blog post that explores the idea of using an AWS Lambda function, in combination with AutoScaling Lifecycle Hooks and a DynamoDB table, to automatically update security groups for a dynamic environment on your behalf, leaving you with automatically scoped down security groups. 3 | 4 | For more information on how this process works, check out the blog post on the AWS Compute Blog!## ${PRODUCT_NAME} 5 | 6 | ## License Summary 7 | 8 | This sample code is made available under the MIT-0 license. See the LICENSE file. 9 | -------------------------------------------------------------------------------- /lambda/auto-sg-updater.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awslabs/aws-automating-security-group-updates/be910b344bc1c65c734a416a867e36ef6017780f/lambda/auto-sg-updater.zip -------------------------------------------------------------------------------- /lambda/auto_sg_updater.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | 4 | SPDX-License-Identifier: MIT-0 5 | 6 | 7 | Automatically update security groups for clusters 8 | Initiated by AutoScaling Lifecycle Hooks and using a DynamoDB 9 | table to sync security groups across regions. 10 | Automatically adds/removes public IPs to security groups in both 11 | regions to enable for secure cross-region communication with publicly 12 | exposed endpoints. 13 | ''' 14 | import os 15 | import boto3 16 | import json 17 | 18 | def lambda_handler(event, context): 19 | ''' 20 | Main Lambda Handler 21 | ''' 22 | print json.dumps(event) 23 | # Local items 24 | local_sg = os.environ['local_sg'] 25 | local_region = os.environ['local_region'] 26 | local_table = os.environ['local_table'] 27 | 28 | # Remote items 29 | remote_sg = os.environ['remote_sg'] 30 | remote_region = os.environ['remote_region'] 31 | remote_table = os.environ['remote_table'] 32 | remote_asg = os.environ['remote_asg'] 33 | 34 | all_ips = {} 35 | all_ips['local'] = describe_asg(event) 36 | print "Retrieved list of public IPs for local ASG" 37 | 38 | # Update our local/remote DynamoDB table for tracking 39 | all_ips['remote'] = update_dynamo( 40 | local_table, 41 | local_region, 42 | event['detail']['AutoScalingGroupName'], 43 | remote_table, 44 | remote_region, 45 | remote_asg, 46 | all_ips['local'] 47 | ) 48 | 49 | # Updating local region first 50 | try: 51 | print "Performing SG updates for local region" 52 | update_sg(all_ips, local_sg, local_region) 53 | except Exception as error: 54 | # if anything goes wrong, catch the exception 55 | print error 56 | # signal back the error as we weren't able to update 57 | # our security group locally 58 | send_response(event, 'ABANDON') 59 | return 60 | 61 | # Now update remote region 62 | try: 63 | print "Performing SG updates for remote region" 64 | update_sg(all_ips, remote_sg, remote_region) 65 | except Exception as error: 66 | # if anything goes wrong, catch the exception, but 67 | # continue so remote issues don't affect our ability to 68 | # launch instances locally 69 | print error 70 | 71 | # Determining if this was invoked by our Lifecycle Hooks or a trueup 72 | if "trueup" not in event: 73 | print "Sending continue back to ASG Lifecycle Hook" 74 | # only send response back to Lifecycle Hook if this process was triggered 75 | # by a Lifecycle Hook. Otherwise it will return an error 76 | # signal back to autoscaling we're good to go 77 | send_response(event, 'CONTINUE') 78 | 79 | def describe_asg(event): 80 | ''' 81 | Gets a list of public IPs for all instances in the local ASG 82 | ''' 83 | # getting list of all instances in ASG 84 | asg_client = boto3.client('autoscaling') 85 | describe_asg_response = asg_client.describe_auto_scaling_groups( 86 | AutoScalingGroupNames=[event['detail']['AutoScalingGroupName']], 87 | ) 88 | instance_ips = [] 89 | ec2_client = boto3.client('ec2') 90 | 91 | # getting the public IPs for all instances in ASG 92 | for instance in describe_asg_response['AutoScalingGroups'][0]['Instances']: 93 | # getting details for specific instance 94 | describe_instance_response = ec2_client.describe_instances( 95 | InstanceIds=[instance['InstanceId']] 96 | ) 97 | if not describe_instance_response['Reservations']: 98 | print "Instance %s doesn't exist" % instance['InstanceId'] 99 | send_response(event, 'ABANDON') 100 | # omitting instances that are in the terminating state as we need to remove them 101 | # from the security groups 102 | if "Terminating" not in instance['LifecycleState']: 103 | try: 104 | if 'PublicIpAddress' not in describe_instance_response['Reservations'][0]['Instances'][0]: 105 | print "Instance %s doesn't have a public IP address" % instance['InstanceId'] 106 | continue 107 | instance_ips.append(describe_instance_response['Reservations'][0]['Instances'][0]['PublicIpAddress']+"/32") 108 | except Exception as error: 109 | print error 110 | # something happened, print error and continue 111 | continue 112 | return instance_ips 113 | 114 | def update_dynamo(local_table, local_region, local_asg, remote_table, remote_region, remote_asg, local_ips): 115 | ''' 116 | This method updates the dynamo table for both regions which will serve as the 117 | source of truth for SG rule comparisons later 118 | ''' 119 | print "Updating DynamoDB tables" 120 | # can't update DynamoDB with an empty set so we need to swap this out 121 | # with a null value if we've removed all instancees 122 | if not local_ips: 123 | eav = {"NULL": True} 124 | else: 125 | eav = {"SS":local_ips} 126 | # Updating the local region first 127 | local_client = boto3.client('dynamodb') 128 | local_client.update_item( 129 | TableName=local_table, 130 | Key={ 131 | 'region':{"S":local_region}, 132 | 'asg':{"S":local_asg} 133 | }, 134 | UpdateExpression='SET ips =:ips', 135 | ExpressionAttributeValues={ 136 | ':ips':eav 137 | } 138 | 139 | ) 140 | print "Updated local DynamoDB Table" 141 | # getting the IPs for the remote region from our local DynamoDB table 142 | remote_ips_response = local_client.get_item( 143 | TableName=local_table, 144 | Key={ 145 | 'region':{"S":remote_region}, 146 | 'asg':{"S":remote_asg} 147 | } 148 | ) 149 | # need to do error checking of type returned 150 | if 'Item' in remote_ips_response and "NULL" not in remote_ips_response['Item']['ips']: 151 | remote_ips = remote_ips_response['Item']['ips']['SS'] 152 | else: 153 | remote_ips = [] 154 | print "Retrieved list of remote IPs" 155 | # Update remote region's DynamoDB table 156 | try: 157 | if remote_table != '': 158 | remote_client = boto3.client('dynamodb', region_name=remote_region) 159 | remote_client.update_item( 160 | TableName=remote_table, 161 | Key={ 162 | 'region':{"S":local_region}, 163 | 'asg':{"S":local_asg} 164 | }, 165 | UpdateExpression='SET ips =:ips', 166 | ExpressionAttributeValues={ 167 | ':ips':eav 168 | } 169 | 170 | ) 171 | print "Updated remote DynamoDB Table" 172 | else: 173 | print "No remote DynamoDB table name, skipping remote update." 174 | except Exception as error: 175 | print error 176 | print "Unable to update remote DynamoDB table. Continuing to perform local updates to prevent remote issues preventing local operation" 177 | 178 | return remote_ips 179 | 180 | def update_sg(all_ips, security_group, region): 181 | ''' 182 | This function determines what IPs need to be added/removed from the 183 | passed in security group 184 | ''' 185 | client = boto3.client('ec2', region_name=region) 186 | # getting all the rules for the passed in security group 187 | response = client.describe_security_groups( 188 | GroupIds=[security_group] 189 | ) 190 | 191 | if not response['SecurityGroups'][0]['IpPermissions']: 192 | raise Exception("No rules in security group to append new public IP to") 193 | permissions = response['SecurityGroups'][0]['IpPermissions'] 194 | 195 | # creating master list of ips 196 | combined_ips = all_ips['local']+all_ips['remote'] 197 | 198 | # settig our placeholder objects which we'll pass later 199 | add_permissions = [] 200 | remove_permissions = [] 201 | 202 | for permission in permissions: 203 | # get list of all SG rule IPs 204 | sg_ips = [] 205 | if permission["IpRanges"]: 206 | for sg_ip in permission["IpRanges"]: 207 | sg_ips.append(sg_ip['CidrIp']) 208 | 209 | # blanking out the usergroup pairs so we don't remove the security group 210 | # rule that's acting as our placeholder 211 | permission['UserIdGroupPairs'] = [] 212 | 213 | # IPs to add to SG 214 | ips_to_add = list(set(combined_ips).difference(sg_ips)) 215 | if ips_to_add: 216 | temp_add_permission = permission.copy() 217 | temp_add_permission["IpRanges"] = [{"CidrIp":s} for s in ips_to_add] 218 | add_permissions.append(temp_add_permission) 219 | 220 | # IPs to remove from SG 221 | ips_to_remove = list(set(sg_ips).difference(combined_ips)) 222 | if ips_to_remove: 223 | temp_remove_permission = permission.copy() 224 | temp_remove_permission["IpRanges"] = [{"CidrIp":s} for s in ips_to_remove] 225 | remove_permissions.append(temp_remove_permission) 226 | 227 | print add_permissions 228 | if add_permissions: 229 | print "Adding SG permissions for region %s" % region 230 | add_sg_permissions(security_group, add_permissions, client) 231 | else: 232 | print "No rules to add for region %s" % region 233 | print remove_permissions 234 | if remove_permissions: 235 | print "Removing SG permissions for region %s" % region 236 | remove_sg_permissions(security_group, remove_permissions, client) 237 | else: 238 | print "No rules to remove for region %s" % region 239 | 240 | def add_sg_permissions(security_group, permissions, client): 241 | ''' 242 | Performing the adding of SG rules 243 | ''' 244 | try: 245 | client.authorize_security_group_ingress( 246 | GroupId=security_group, 247 | IpPermissions=permissions 248 | ) 249 | except Exception as error: 250 | print error 251 | 252 | def remove_sg_permissions(security_group, permissions, client): 253 | ''' 254 | Performing the removing of SG rules 255 | ''' 256 | try: 257 | client.revoke_security_group_ingress( 258 | GroupId=security_group, 259 | IpPermissions=permissions 260 | ) 261 | except Exception as error: 262 | print error 263 | 264 | def send_response(event, status): 265 | ''' 266 | Sends the response back to the Lifecycle hooks to CONTINUE or ABANDON 267 | ''' 268 | client = boto3.client('autoscaling') 269 | response = client.complete_lifecycle_action( 270 | LifecycleHookName=event['detail']['LifecycleHookName'], 271 | AutoScalingGroupName=event['detail']['AutoScalingGroupName'], 272 | LifecycleActionToken=event['detail']['LifecycleActionToken'], 273 | LifecycleActionResult=status 274 | ) 275 | print response 276 | -------------------------------------------------------------------------------- /templates/master.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Parameters: 4 | CodeBucket: 5 | Type: String 6 | Description: Bucket name where code is located 7 | Default: computeblog-us-east-1 8 | CodeKey: 9 | Type: String 10 | Description: Key name (including all prefixes) of code zip 11 | Default: automate-sg-lambda/auto-sg-updater.zip 12 | AutoScalingGroup: 13 | Type: String 14 | Description: The name of your AutoScalingGroup 15 | LocalSG: 16 | Type: String 17 | Description: The security group ID of your local Security Group (sg-abcd1234) 18 | RemoteSG: 19 | Type: String 20 | Description: The security group ID of your remote Security Group (sg-abcd1234) 21 | RemoteRegion: 22 | Type: String 23 | Description: The region name of the remote region (us-west-2, us-east-1, etc.) 24 | RemoteASG: 25 | Type: String 26 | Description: The name of your remote region AutoScalingGroup 27 | RemoteTable: 28 | Type: String 29 | Description: The name of the remote DynamoDB Table 30 | Outputs: 31 | DynamoTable: 32 | Description: Name of the DynamoDB Table to copy in remote region stack 33 | Value: !Ref DynamoDBTable 34 | Metadata: 35 | AWS::CloudFormation::Interface: 36 | ParameterGroups: 37 | - 38 | Label: 39 | default: "Local Resources" 40 | Parameters: 41 | - LocalSG 42 | - AutoScalingGroup 43 | - 44 | Label: 45 | default: "Remote Resources" 46 | Parameters: 47 | - RemoteSG 48 | - RemoteRegion 49 | - RemoteASG 50 | - RemoteTable 51 | - 52 | Label: 53 | default: "General Configuration - Change these when launching in remote region!" 54 | Parameters: 55 | - CodeBucket 56 | - CodeKey 57 | ParameterLabels: 58 | LocalSG: 59 | default: "Local Security Group ID" 60 | AutoScalingGroup: 61 | default: "Local Auto Scaling Group Name" 62 | RemoteSG: 63 | default: "Remote Security Group ID" 64 | RemoteRegion: 65 | default: "Remote Region Name" 66 | RemoteASG: 67 | default: "Remote Auto Scaling Group Name" 68 | RemoteTable: 69 | default: "Remote DynamoDB Table Name" 70 | CodeBucket: 71 | default: "Code Zip S3 Bucket Name" 72 | CodeKey: 73 | default: "Code Zip S3 Object Key" 74 | Resources: 75 | SGUpdater: 76 | Type: AWS::Serverless::Function 77 | Properties: 78 | Handler: auto_sg_updater.lambda_handler 79 | Runtime: python2.7 80 | Timeout: 300 81 | Policies: 82 | - AWSLambdaExecute 83 | - Version: '2012-10-17' 84 | Statement: 85 | - Effect: Allow 86 | Action: 87 | - autoscaling:CompleteLifecycleAction 88 | - ec2:DescribeSecurityGroups 89 | - ec2:AuthorizeSecurityGroupIngress 90 | - ec2:RevokeSecurityGroupIngress 91 | - ec2:DescribeInstances 92 | - autoscaling:DescribeAutoScalingGroups 93 | - dynamodb:UpdateItem 94 | - dynamodb:GetItem 95 | Resource: '*' 96 | CodeUri: 97 | Bucket: !Ref CodeBucket 98 | Key: !Ref CodeKey 99 | Environment: 100 | Variables: 101 | local_table: !Ref DynamoDBTable 102 | local_sg: !Ref LocalSG 103 | local_region: !Ref AWS::Region 104 | remote_table: !Ref RemoteTable 105 | remote_region: !Ref RemoteRegion 106 | remote_asg: !Ref RemoteASG 107 | remote_sg: !Ref RemoteSG 108 | Events: 109 | Stream: 110 | Type: CloudWatchEvent 111 | Properties: 112 | Pattern: 113 | source: 114 | - aws.autoscaling 115 | detail-type: 116 | - EC2 Instance-launch Lifecycle Action 117 | - EC2 Instance-terminate Lifecycle Action 118 | detail: 119 | AutoScalingGroupName: 120 | - !Ref AutoScalingGroup 121 | DynamoDBTable: 122 | Type: AWS::DynamoDB::Table 123 | Properties: 124 | AttributeDefinitions: 125 | - AttributeName: region 126 | AttributeType: S 127 | - AttributeName: asg 128 | AttributeType: S 129 | KeySchema: 130 | - AttributeName: region 131 | KeyType: HASH 132 | - AttributeName: asg 133 | KeyType: RANGE 134 | ProvisionedThroughput: 135 | ReadCapacityUnits: 3 136 | WriteCapacityUnits: 3 137 | LaunchLifecycleHook: 138 | Type: "AWS::AutoScaling::LifecycleHook" 139 | Properties: 140 | AutoScalingGroupName: !Ref AutoScalingGroup 141 | LifecycleTransition: autoscaling:EC2_INSTANCE_LAUNCHING 142 | TerminateLifecycleHook: 143 | Type: "AWS::AutoScaling::LifecycleHook" 144 | Properties: 145 | AutoScalingGroupName: !Ref AutoScalingGroup 146 | LifecycleTransition: autoscaling:EC2_INSTANCE_TERMINATING -------------------------------------------------------------------------------- /templates/prerequisites.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: VPC, Launch Configuration, and ASG for Automating Security Groups with Lifecycle Hooks Blog Post 3 | Mappings: 4 | RegionalMap: 5 | us-east-1: 6 | '64': ami-a4c7edb2 7 | us-east-2: 8 | '64': ami-8a7859ef 9 | us-west-2: 10 | '64': ami-6df1e514 11 | us-west-1: 12 | '64': ami-327f5352 13 | ca-central-1: 14 | '64': ami-a7aa15c3 15 | eu-west-1: 16 | '64': ami-d7b9a2b1 17 | eu-west-2: 18 | '64': ami-ed100689 19 | eu-central-1: 20 | '64': ami-82be18ed 21 | ap-southeast-1: 22 | '64': ami-77af2014 23 | ap-northeast-2: 24 | '64': ami-e21cc38c 25 | ap-northeast-1: 26 | '64': ami-3bd3c45c 27 | ap-southeast-2: 28 | '64': ami-10918173 29 | ap-south-1: 30 | '64': ami-47205e28 31 | Outputs: 32 | AutoScalingGroupName: 33 | Description: Name of the Auto Scaling Group 34 | Value: !Ref AutoScalingGroup 35 | SecurityGroupID: 36 | Description: ID of the Security Group 37 | Value: !GetAtt SecurityGroup.GroupId 38 | Resources: 39 | GatewayToInternet: 40 | Properties: 41 | InternetGatewayId: !Ref InternetGateway 42 | VpcId: !Ref VPC 43 | Type: AWS::EC2::VPCGatewayAttachment 44 | SecurityGroup: 45 | Properties: 46 | GroupDescription: Web Instance Security Group 47 | GroupName: automating-sg 48 | VpcId: !Ref VPC 49 | Type: AWS::EC2::SecurityGroup 50 | SecurityGroupIngress: 51 | Type: "AWS::EC2::SecurityGroupIngress" 52 | Properties: 53 | FromPort: '443' 54 | GroupId: !Ref SecurityGroup 55 | IpProtocol: tcp 56 | SourceSecurityGroupId: !Ref SecurityGroup 57 | ToPort: '443' 58 | InternetGateway: 59 | Type: AWS::EC2::InternetGateway 60 | DependsOn: VPC 61 | PublicRoute: 62 | Properties: 63 | DestinationCidrBlock: 0.0.0.0/0 64 | GatewayId: !Ref InternetGateway 65 | RouteTableId: !Ref PublicRouteTable 66 | Type: AWS::EC2::Route 67 | DependsOn: GatewayToInternet 68 | PublicRouteTable: 69 | Properties: 70 | VpcId: !Ref VPC 71 | Type: AWS::EC2::RouteTable 72 | PublicSubnet1: 73 | Properties: 74 | AvailabilityZone: 75 | Fn::Select: 76 | - '0' 77 | - Fn::GetAZs: '' 78 | CidrBlock: 10.0.0.128/28 79 | VpcId: !Ref VPC 80 | Type: AWS::EC2::Subnet 81 | PublicSubnet1RouteTableAssociation: 82 | Properties: 83 | RouteTableId: !Ref PublicRouteTable 84 | SubnetId: !Ref PublicSubnet1 85 | Type: AWS::EC2::SubnetRouteTableAssociation 86 | PublicSubnet2: 87 | Properties: 88 | AvailabilityZone: 89 | Fn::Select: 90 | - '1' 91 | - Fn::GetAZs: '' 92 | CidrBlock: 10.0.128.0/24 93 | VpcId: !Ref VPC 94 | Type: AWS::EC2::Subnet 95 | PublicSubnet2RouteTableAssociation: 96 | Properties: 97 | RouteTableId: !Ref PublicRouteTable 98 | SubnetId: !Ref PublicSubnet2 99 | Type: AWS::EC2::SubnetRouteTableAssociation 100 | VPC: 101 | Properties: 102 | CidrBlock: 10.0.0.0/16 103 | Tags: 104 | - Key: Name 105 | Value: AutomatingSGs 106 | Type: AWS::EC2::VPC 107 | AutoScalingGroup: 108 | Properties: 109 | AvailabilityZones: 110 | - Fn::Select: 111 | - '0' 112 | - Fn::GetAZs: '' 113 | - Fn::Select: 114 | - '1' 115 | - Fn::GetAZs: '' 116 | MaxSize: '2' 117 | MinSize: '0' 118 | LaunchConfigurationName: !Ref LaunchConfiguration 119 | VPCZoneIdentifier: 120 | - !Ref PublicSubnet1 121 | - !Ref PublicSubnet2 122 | Type: AWS::AutoScaling::AutoScalingGroup 123 | LaunchConfiguration: 124 | Type: "AWS::AutoScaling::LaunchConfiguration" 125 | Properties: 126 | AssociatePublicIpAddress: True 127 | ImageId: 128 | Fn::FindInMap: 129 | - RegionalMap 130 | - Ref: AWS::Region 131 | - '64' 132 | InstanceType: t2.micro 133 | SecurityGroups: 134 | - !Ref SecurityGroup --------------------------------------------------------------------------------