├── diagram ├── diagram.png └── diagram.drawio ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── CONTRIBUTING.md └── main.yml /diagram/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/access-internal-alb-through-aws-global-accelerator/main/diagram/diagram.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 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 | 16 | -------------------------------------------------------------------------------- /diagram/diagram.drawio: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Access Internal Application Load Balancer through AWS Global Accelerator 2 | The purpose of this repository is to demo how to access an internal Application Load Balancer (ALB) through AWS Global Accelerator. 3 | 4 | AWS CloudFormation template (main.yml) will deploy a Virtual Private Cloud(VPC) with 2 Public and 2 Private subnets within the VPC. Later it will create an Internal Application Load Balancer attached to an Auto Scaling Group where it will serve a simple PHP application and echo real-client IP using HTTP_X_FORWARDED_FOR header. The access to this PHP application is done through AWS Global Accelerator. 5 | 6 | You can read more in this [blog post](https://aws.amazon.com/blogs/networking-and-content-delivery/accessing-private-application-load-balancers-and-instances-through-aws-global-accelerator/). 7 | 8 | ### Architecture 9 | ![int-alb-with-aws-ga](diagram/diagram.png) 10 | 11 | ### Launch the AWS CloudFormation Stack 12 | 13 | Click on the **Launch Stack** button below to launch the CloudFormation Stack to set up the AWS Global Accelerator Demo in the region of your preference, by default this demo will be deployed in us-west-2 (Oregon) region. 14 | 15 | [![Launch CFN stack](https://s3.amazonaws.com/cloudformation-examples/cloudformation-launch-stack.png)](https://us-west-2.console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/quickcreate?templateUrl=https%3A%2F%2Faws-global-accelerator-with-internal-alb-demo.s3-us-west-2.amazonaws.com%2Fmain.yml&stackName=int-alb-with-aws-ga) 16 | 17 | Provide a stack name eg **int-alb-with-aws-ga**. 18 | 19 | You can launch the same stack using the AWS CLI. Here's an example: 20 | 21 | ``` 22 | aws cloudformation create-stack --stack-name int-alb-with-aws-ga \ 23 | --template-body file://main.yml \ 24 | --capabilities CAPABILITY_NAMED_IAM \ 25 | --region us-west-2 26 | ``` 27 | ### How to Access Your Application 28 | Once stack creation is completed, it will output the AWS Global Accelerator DNS Name under "Outputs" tab of your stack. Another way of accessing via CLI: 29 | 30 | ``` 31 | aws cloudformation describe-stacks --stack-name int-alb-with-aws-ga \ 32 | --query "Stacks[0].Outputs[0].OutputValue" \ 33 | --region us-west-2 34 | ``` 35 | 36 | ### Clean up 37 | After completing your demo, delete AWS CloudFormation Stack using AWS Console or AWS CLI: 38 | ``` 39 | aws cloudformation delete-stack --stack-name int-alb-with-aws-ga --region us-west-2 40 | ``` 41 | 42 | ## Security 43 | 44 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 45 | 46 | ## License 47 | 48 | This library is licensed under the MIT-0 License. See the LICENSE file. 49 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /main.yml: -------------------------------------------------------------------------------- 1 | Parameters: 2 | 3 | VpcCIDR: 4 | Description: Please enter the IP range (CIDR notation) for this VPC 5 | Type: String 6 | Default: 10.10.0.0/16 7 | 8 | PublicSubnet1CIDR: 9 | Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone 10 | Type: String 11 | Default: 10.10.10.0/24 12 | 13 | PublicSubnet2CIDR: 14 | Description: Please enter the IP range (CIDR notation) for the public subnet in the second Availability Zone 15 | Type: String 16 | Default: 10.10.11.0/24 17 | 18 | PrivateSubnet1CIDR: 19 | Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone 20 | Type: String 21 | Default: 10.10.20.0/24 22 | 23 | PrivateSubnet2CIDR: 24 | Description: Please enter the IP range (CIDR notation) for the private subnet in the second Availability Zone 25 | Type: String 26 | Default: 10.10.21.0/24 27 | 28 | AllowedIP: 29 | Description: Allowed IP range 30 | Type: String 31 | Default: 0.0.0.0/0 32 | 33 | LatestLinux2AmiId: 34 | Description: Region specific image from the Parameter Store 35 | Type: 'AWS::SSM::Parameter::Value' 36 | Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' 37 | 38 | ResourceName: 39 | Type: String 40 | Default: int-alb-with-aws-ga 41 | Description: Prefix of Resources created for this workshop. 42 | 43 | Metadata: 44 | AWS::CloudFormation::Interface: 45 | ParameterGroups: 46 | - 47 | Label: 48 | default: "Resource Configuration" 49 | Parameters: 50 | - ResourceName 51 | ParameterLabels: 52 | ResourceName: 53 | default: "Resource Prefix" 54 | 55 | Resources: 56 | VPC: 57 | Type: AWS::EC2::VPC 58 | Properties: 59 | CidrBlock: !Ref VpcCIDR 60 | EnableDnsSupport: true 61 | EnableDnsHostnames: true 62 | Tags: 63 | - Key: Name 64 | Value: !Join [ -, [!Ref ResourceName, 'VPC'] ] 65 | 66 | InternetGateway: 67 | Type: AWS::EC2::InternetGateway 68 | Properties: 69 | Tags: 70 | - Key: Name 71 | Value: !Join [ -, [!Ref ResourceName, 'IGW'] ] 72 | 73 | InternetGatewayAttachment: 74 | Type: AWS::EC2::VPCGatewayAttachment 75 | Properties: 76 | InternetGatewayId: !Ref InternetGateway 77 | VpcId: !Ref VPC 78 | 79 | PublicSubnet1: 80 | Type: AWS::EC2::Subnet 81 | Properties: 82 | VpcId: !Ref VPC 83 | AvailabilityZone: !Select [ 0, !GetAZs '' ] 84 | CidrBlock: !Ref PublicSubnet1CIDR 85 | MapPublicIpOnLaunch: true 86 | Tags: 87 | - Key: Name 88 | Value: Public Subnet (AZ1) 89 | 90 | PublicSubnet2: 91 | Type: AWS::EC2::Subnet 92 | Properties: 93 | VpcId: !Ref VPC 94 | AvailabilityZone: !Select [ 1, !GetAZs '' ] 95 | CidrBlock: !Ref PublicSubnet2CIDR 96 | MapPublicIpOnLaunch: true 97 | Tags: 98 | - Key: Name 99 | Value: Public Subnet (AZ2) 100 | 101 | PrivateSubnet1: 102 | Type: AWS::EC2::Subnet 103 | Properties: 104 | VpcId: !Ref VPC 105 | AvailabilityZone: !Select [ 0, !GetAZs '' ] 106 | CidrBlock: !Ref PrivateSubnet1CIDR 107 | MapPublicIpOnLaunch: false 108 | Tags: 109 | - Key: Name 110 | Value: Private Subnet (AZ1) 111 | 112 | PrivateSubnet2: 113 | Type: AWS::EC2::Subnet 114 | Properties: 115 | VpcId: !Ref VPC 116 | AvailabilityZone: !Select [ 1, !GetAZs '' ] 117 | CidrBlock: !Ref PrivateSubnet2CIDR 118 | MapPublicIpOnLaunch: false 119 | Tags: 120 | - Key: Name 121 | Value: Private Subnet (AZ2) 122 | 123 | NatGateway1EIP: 124 | Type: AWS::EC2::EIP 125 | DependsOn: InternetGatewayAttachment 126 | Properties: 127 | Domain: vpc 128 | 129 | NatGateway2EIP: 130 | Type: AWS::EC2::EIP 131 | DependsOn: InternetGatewayAttachment 132 | Properties: 133 | Domain: vpc 134 | 135 | NatGateway1: 136 | Type: AWS::EC2::NatGateway 137 | Properties: 138 | AllocationId: !GetAtt NatGateway1EIP.AllocationId 139 | SubnetId: !Ref PublicSubnet1 140 | 141 | NatGateway2: 142 | Type: AWS::EC2::NatGateway 143 | Properties: 144 | AllocationId: !GetAtt NatGateway2EIP.AllocationId 145 | SubnetId: !Ref PublicSubnet2 146 | 147 | PublicRouteTable: 148 | Type: AWS::EC2::RouteTable 149 | Properties: 150 | VpcId: !Ref VPC 151 | Tags: 152 | - Key: Name 153 | Value: Public Routes 154 | 155 | DefaultPublicRoute: 156 | Type: AWS::EC2::Route 157 | DependsOn: InternetGatewayAttachment 158 | Properties: 159 | RouteTableId: !Ref PublicRouteTable 160 | DestinationCidrBlock: 0.0.0.0/0 161 | GatewayId: !Ref InternetGateway 162 | 163 | PublicSubnet1RouteTableAssociation: 164 | Type: AWS::EC2::SubnetRouteTableAssociation 165 | Properties: 166 | RouteTableId: !Ref PublicRouteTable 167 | SubnetId: !Ref PublicSubnet1 168 | 169 | PublicSubnet2RouteTableAssociation: 170 | Type: AWS::EC2::SubnetRouteTableAssociation 171 | Properties: 172 | RouteTableId: !Ref PublicRouteTable 173 | SubnetId: !Ref PublicSubnet2 174 | 175 | 176 | PrivateRouteTable1: 177 | Type: AWS::EC2::RouteTable 178 | Properties: 179 | VpcId: !Ref VPC 180 | Tags: 181 | - Key: Name 182 | Value: Private Routes (AZ1) 183 | 184 | DefaultPrivateRoute1: 185 | Type: AWS::EC2::Route 186 | Properties: 187 | RouteTableId: !Ref PrivateRouteTable1 188 | DestinationCidrBlock: 0.0.0.0/0 189 | NatGatewayId: !Ref NatGateway1 190 | 191 | PrivateSubnet1RouteTableAssociation: 192 | Type: AWS::EC2::SubnetRouteTableAssociation 193 | Properties: 194 | RouteTableId: !Ref PrivateRouteTable1 195 | SubnetId: !Ref PrivateSubnet1 196 | 197 | PrivateRouteTable2: 198 | Type: AWS::EC2::RouteTable 199 | Properties: 200 | VpcId: !Ref VPC 201 | Tags: 202 | - Key: Name 203 | Value: Private Routes (AZ2) 204 | 205 | DefaultPrivateRoute2: 206 | Type: AWS::EC2::Route 207 | Properties: 208 | RouteTableId: !Ref PrivateRouteTable2 209 | DestinationCidrBlock: 0.0.0.0/0 210 | NatGatewayId: !Ref NatGateway2 211 | 212 | PrivateSubnet2RouteTableAssociation: 213 | Type: AWS::EC2::SubnetRouteTableAssociation 214 | Properties: 215 | RouteTableId: !Ref PrivateRouteTable2 216 | SubnetId: !Ref PrivateSubnet2 217 | 218 | WebServerPrefixList: 219 | Type: AWS::EC2::PrefixList 220 | Properties: 221 | PrefixListName: "WebServerPrefixList" 222 | AddressFamily: "IPv4" 223 | MaxEntries: 10 224 | Entries: 225 | - Cidr: !Ref AllowedIP 226 | Description: "AllowedIP" 227 | 228 | WebServerSecurityGroup: 229 | Type: AWS::EC2::SecurityGroup 230 | Properties: 231 | GroupName: "web-server-sg" 232 | GroupDescription: "Security Group for Web Servers" 233 | VpcId: !Ref VPC 234 | SecurityGroupIngress: 235 | - IpProtocol: tcp 236 | SourceSecurityGroupId: !Ref ALBSecurityGroup 237 | FromPort: 80 238 | ToPort: 80 239 | 240 | # Internal ALB 241 | InternalALBListener: 242 | Type: AWS::ElasticLoadBalancingV2::Listener 243 | Properties: 244 | DefaultActions: 245 | - Type: forward 246 | TargetGroupArn: 247 | Ref: WebServerTargetGroup 248 | LoadBalancerArn: 249 | Ref: InternalApplicationLoadBalancer 250 | Port: 80 251 | Protocol: HTTP 252 | 253 | InternalApplicationLoadBalancer: 254 | Type: AWS::ElasticLoadBalancingV2::LoadBalancer 255 | Properties: 256 | Scheme: internal 257 | Subnets: 258 | - Ref: PrivateSubnet1 259 | - Ref: PrivateSubnet2 260 | SecurityGroups: 261 | - Ref: ALBSecurityGroup 262 | 263 | # Internal ALB Security Group with Allowed IP prefix 264 | ALBSecurityGroup: 265 | Type: AWS::EC2::SecurityGroup 266 | Properties: 267 | GroupDescription: 'int-alb-with-ga-sg' 268 | VpcId: 269 | Ref: VPC 270 | SecurityGroupIngress: 271 | - IpProtocol: tcp 272 | SourcePrefixListId: !Ref WebServerPrefixList 273 | FromPort: 80 274 | ToPort: 80 275 | 276 | WebServerTargetGroup: 277 | Type: AWS::ElasticLoadBalancingV2::TargetGroup 278 | Properties: 279 | HealthCheckIntervalSeconds: 5 280 | HealthCheckProtocol: HTTP 281 | HealthCheckTimeoutSeconds: 3 282 | HealthyThresholdCount: 3 283 | Matcher: 284 | HttpCode: '200' 285 | Name: WebServerTargetGroup 286 | Port: 80 287 | Protocol: HTTP 288 | TargetGroupAttributes: 289 | - Key: deregistration_delay.timeout_seconds 290 | Value: '10' 291 | UnhealthyThresholdCount: 3 292 | VpcId: 293 | Ref: 'VPC' 294 | 295 | LaunchConfigWebServer: 296 | Type: AWS::AutoScaling::LaunchConfiguration 297 | Properties: 298 | ImageId: !Ref LatestLinux2AmiId 299 | IamInstanceProfile: !Ref WebServerInstanceProfile 300 | SecurityGroups: 301 | - Ref: WebServerSecurityGroup 302 | InstanceType: t3.micro 303 | UserData: !Base64 | 304 | #!/bin/bash -x 305 | yum update -y 306 | yum install httpd -y 307 | sudo amazon-linux-extras install -y php7.2 308 | service httpd start 309 | chkconfig httpd on 310 | cd /var/www/html 311 | cat <<'EOT' >> /var/www/html/index.php 312 | '; 314 | echo 'HTTP_X_FORWARDED_FOR: '; 315 | print_r($_SERVER['HTTP_X_FORWARDED_FOR']); 316 | echo ''; 317 | exit; 318 | ?> 319 | EOT 320 | EbsOptimized: "true" 321 | 322 | 323 | AutoScalingWebServer: 324 | Type: AWS::AutoScaling::AutoScalingGroup 325 | Properties: 326 | VPCZoneIdentifier: 327 | - !Ref PrivateSubnet1 328 | - !Ref PrivateSubnet2 329 | LaunchConfigurationName: !Ref LaunchConfigWebServer 330 | MinSize: '1' 331 | MaxSize: '1' 332 | HealthCheckGracePeriod: 300 333 | MaxInstanceLifetime: 2592000 334 | TargetGroupARNs: 335 | - !Ref WebServerTargetGroup 336 | 337 | ### WebServer IAM Role 338 | WebServerRole: 339 | Type: AWS::IAM::Role 340 | Properties: 341 | RoleName: 342 | Fn::Join: 343 | - '-' 344 | - ['webserver-role', !Ref "AWS::Region"] 345 | AssumeRolePolicyDocument: 346 | Version: 2012-10-17 347 | Statement: 348 | - 349 | Effect: Allow 350 | Principal: 351 | Service: 352 | - ec2.amazonaws.com 353 | Action: 354 | - sts:AssumeRole 355 | Path: / 356 | ManagedPolicyArns: 357 | - arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM 358 | Policies: 359 | - 360 | PolicyName: !Join [ -, ['webserver-policy', !Ref "AWS::Region"] ] 361 | PolicyDocument: 362 | Version: 2012-10-17 363 | Statement: 364 | - 365 | Effect: Allow 366 | Action: 367 | - ssm:GetParameter 368 | - ssm:GetParameters 369 | - ssm:DescribeParameters 370 | Resource: 371 | Fn::Join: 372 | - ':' 373 | - ["arn:aws:ssm", !Ref "AWS::Region", !Ref "AWS::AccountId", "*"] 374 | 375 | WebServerInstanceProfile: 376 | Type: AWS::IAM::InstanceProfile 377 | Properties: 378 | InstanceProfileName: 379 | Fn::Join: 380 | - '-' 381 | - ['webserver-profile', !Ref "AWS::Region"] 382 | Path: / 383 | Roles: 384 | - !Ref WebServerRole 385 | 386 | GlobalAccelerator: 387 | Type: AWS::GlobalAccelerator::Accelerator 388 | Properties: 389 | Name: WebGlobalAccelerator 390 | Enabled: true 391 | 392 | WebGAListener: 393 | Type: AWS::GlobalAccelerator::Listener 394 | Properties: 395 | AcceleratorArn: !Ref GlobalAccelerator 396 | Protocol: TCP 397 | PortRanges: 398 | - FromPort: 80 399 | ToPort: 80 400 | 401 | GlobalAcceleratorEndpointGroup: 402 | Type: AWS::GlobalAccelerator::EndpointGroup 403 | Properties: 404 | ListenerArn: 405 | Ref: WebGAListener 406 | EndpointGroupRegion: 407 | Ref: "AWS::Region" 408 | TrafficDialPercentage: 100 409 | EndpointConfigurations: 410 | - EndpointId: !Ref InternalApplicationLoadBalancer 411 | ClientIPPreservationEnabled: true 412 | Weight: 100 413 | 414 | GlobalAcceleratorSGCleanUp: 415 | Type: Custom::GlobalAcceleratorSGCleanUp 416 | Properties: 417 | ServiceToken: 418 | Fn::GetAtt: 419 | - "GlobalAcceleratorSGCleanUpLambda" 420 | - "Arn" 421 | 422 | GlobalAcceleratorSGCleanUpLambdaLogGroup: 423 | Type: AWS::Logs::LogGroup 424 | Properties: 425 | LogGroupName: /aws/lambda/GlobalAcceleratorSGCleanUpLambda 426 | RetentionInDays: 30 427 | 428 | GlobalAcceleratorSGCleanUpLambdaRole: 429 | Type: AWS::IAM::Role 430 | Properties: 431 | AssumeRolePolicyDocument: 432 | Version: '2012-10-17' 433 | Statement: 434 | - Effect: Allow 435 | Principal: 436 | Service: 437 | - lambda.amazonaws.com 438 | Action: 439 | - sts:AssumeRole 440 | Path: "/" 441 | Policies: 442 | - PolicyName: !Join [ -, ['cleanup-lambda-policy', !Ref "AWS::Region"] ] 443 | PolicyDocument: 444 | Version: '2012-10-17' 445 | Statement: 446 | - Effect: Allow 447 | Action: 448 | - logs:DescribeLogStreams 449 | - logs:CreateLogStream 450 | - logs:PutLogEvents 451 | - ec2:DescribeSecurityGroups 452 | - ec2:DeleteSecurityGroup 453 | - ec2:DescribeNetworkInterfaces 454 | Resource: '*' 455 | 456 | GlobalAcceleratorSGCleanUpLambda: 457 | Type: AWS::Lambda::Function 458 | Properties: 459 | FunctionName: GlobalAcceleratorSGCleanUpLambda 460 | Handler: "index.lambda_handler" 461 | Runtime: python3.7 462 | MemorySize: 128 463 | Timeout: 60 464 | Role: !GetAtt GlobalAcceleratorSGCleanUpLambdaRole.Arn 465 | Code: 466 | ZipFile: !Sub | 467 | import json, boto3, logging, os, urllib3 468 | import cfnresponse 469 | logger = logging.getLogger() 470 | logger.setLevel(logging.INFO) 471 | VPCID = os.environ['VPCID'] 472 | 473 | def lambda_handler(event, context): 474 | logger.info("event: {}".format(event)) 475 | try: 476 | if event['RequestType'] == 'Delete': 477 | ec2 = boto3.client('ec2') 478 | response = ec2.describe_security_groups( Filters=[{'Name': 'vpc-id', 'Values': [ VPCID ]},{'Name': 'group-name', 'Values': [ 'GlobalAccelerator' ]}]) 479 | sg_id = response.get('SecurityGroups', [{}])[0].get('GroupId', '') 480 | enis = list_network_interfaces(sg_id) 481 | count = len(enis) 482 | while True: 483 | if count == 0: 484 | ec2.delete_security_group(GroupId=sg_id) 485 | break 486 | elif event['RequestType'] == 'Create': 487 | logger.info("event: {}".format(event)) 488 | 489 | sendResponseCfn(event, context, cfnresponse.SUCCESS) 490 | except Exception as e: 491 | logger.info("Exception: {}".format(e)) 492 | sendResponseCfn(event, context, cfnresponse.FAILED) 493 | 494 | def sendResponseCfn(event, context, responseStatus): 495 | responseData = {} 496 | responseData['Data'] = {} 497 | cfnresponse.send(event, context, responseStatus, responseData, "CustomResourcePhysicalID") 498 | 499 | def list_network_interfaces(sg_id): 500 | # Retrieve the list network interfaces 501 | ec2 = boto3.client('ec2') 502 | try: 503 | response = ec2.describe_network_interfaces( Filters=[{'Name': 'group-id', 'Values': [ sg_id ]}]) 504 | print(response) 505 | except ClientError as e: 506 | logging.error(e) 507 | return None 508 | return response['NetworkInterfaces'] 509 | 510 | Environment: 511 | Variables: 512 | VPCID: 513 | !Ref VPC 514 | 515 | Outputs: 516 | GlobalAcceleratorDNSName: 517 | Description: "The Domain Name System (DNS) name that Global Accelerator creates that points to your accelerator's static IP addresses." 518 | Value: !GetAtt GlobalAccelerator.DnsName 519 | --------------------------------------------------------------------------------