From 044dc48883623547dde7bd118c964c428a68a294 Mon Sep 17 00:00:00 2001 From: Chris Date: Wed, 6 Oct 2021 13:13:38 +0000 Subject: [PATCH] add lambda to automate targer group and security group --- Makefile | 2 +- init.yml | 3 +- library/automation.yml | 154 ++++++++++++++++++++++++++++++++++++++ library/load-balancer.yml | 4 + template.yml | 31 ++++++++ 5 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 library/automation.yml diff --git a/Makefile b/Makefile index 0276247..28a59ba 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ package: --output-template-file template-output.yml ## Deploy Cloud Formation stack -deploy: +deploy: package aws --profile $(profile) \ --region $(region) \ cloudformation deploy \ diff --git a/init.yml b/init.yml index 1bf67b1..45c399f 100644 --- a/init.yml +++ b/init.yml @@ -1,6 +1,5 @@ AWSTemplateFormatVersion: '2010-09-09' - Resources: TemplateBucket: Type: AWS::S3::Bucket @@ -38,7 +37,7 @@ Resources: CloudformationUser: Type: AWS::IAM::User Properties: - UserName: cloudformation + UserName: cloudformation-user Policies: - PolicyName: cloudformation-cloud9-policy diff --git a/library/automation.yml b/library/automation.yml new file mode 100644 index 0000000..27932ce --- /dev/null +++ b/library/automation.yml @@ -0,0 +1,154 @@ +AWSTemplateFormatVersion: 2010-09-09 +Transform: AWS::Serverless-2016-10-31 +Description: Application Load Balancer Stack + +Parameters: + StackName: + Description: Main Stack Name + Type: String + User: + Description: Training User name + Type: String + TargetSecurityGroup: + Description: Target Security Group + Type: String + appTargetGroup: + Description: Target group to attach + Type: String + Port: + Description: On port X + Type: Number + +Resources: + + LambdaRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + Path: / + Policies: + - PolicyName: Lambda-Cf-Killer-Permissions + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/* + - Effect: Allow + Action: + - ec2:* + - Cloud9:* + - elasticloadbalancing:* + - elbv2:* + Resource: "*" + - Effect: Allow + Action: 'lambda:InvokeFunction' + Resource: 'arn:aws:lambda:*:*:function:*' + + AttachInstanceFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: python3.8 + Timeout: 60 + Description: Assign security-group + Role: !GetAtt LambdaRole.Arn + InlineCode: | + import json + import boto3 + from botocore.exceptions import ClientError + import cfnresponse + from botocore.config import Config + + def handler(event, context): + try: + print(event['RequestType']) + my_config = Config(region_name = 'us-east-1'); + + tg = boto3.client('elbv2') + ec2 = boto3.resource('ec2' , config=my_config); + params = event.get('ResourceProperties', None) + StackName = params["StackName"] + UserName = params["User"] + Port = int(params["TargetPort"]) + TargetGroup = params["TargetGroupArn"] + SecurityGroup = params["SecurityGroupId"] + + custom_filter = [{ + 'Name':'tag:Cloud9', + 'Values': ['yes']}, + {'Name':'tag:Stack', + 'Values': [StackName]}, + {'Name':'tag:User', + 'Values': [UserName]}, + {'Name': 'instance-state-name', + 'Values': ['running' , 'stopped' , 'stopping']}]; + + cloud9 = ec2.instances.filter(Filters=custom_filter); + + if(event['RequestType'] == "Delete"): + for instance in cloud9 : + response = tg.deregister_targets( + TargetGroupArn=TargetGroup, + Targets=[ + { + 'Id': instance.id, + 'Port': Port + }, + ] + ) + + all_sg_ids = instance.security_groups + if SecurityGroup in all_sg_ids: + all_sg_ids.remove(SecurityGroup) + instance.modify_attribute(Groups=all_sg_ids) + + cfnresponse.send(event, context, cfnresponse.SUCCESS, {"message": "environment ok delete"}) + + if(event['RequestType'] == "Create" or event['RequestType'] == "Update"): + for instance in cloud9 : + print(instance.state) + if instance.state['Code'] == 80 or instance.state['Code'] == 64 : + instance.start() + if instance.state['Code'] == 80 or instance.state['Code'] == 64 or instance.state['Code'] == 0 : + instance.wait_until_running() + if instance.state['Code'] == 16 : + response = tg.register_targets( + TargetGroupArn=TargetGroup, + Targets=[ + { + 'Id': instance.id, + 'Port': Port + }, + ] + ) + groups = [] + for group in instance.security_groups : + groups.append(str(group['GroupId'])) + groups.append(str(SecurityGroup)) + instance.modify_attribute(Groups=groups) + + cfnresponse.send(event, context, cfnresponse.SUCCESS, {"message": "environment ok Create"}) + except BaseException as e: + print(str(e)) + cfnresponse.send(event, context, cfnresponse.FAILED, { "message": str(e) }) + + + AssignElbCustom: + Type: Custom::AssignElb + Properties: + ServiceToken: !GetAtt AttachInstanceFunction.Arn + TargetPort: !Ref Port + SecurityGroupId: !Ref TargetSecurityGroup + TargetGroupArn: !Ref appTargetGroup + StackName: !Ref StackName + User: !Ref User diff --git a/library/load-balancer.yml b/library/load-balancer.yml index 5674650..3c16fe3 100644 --- a/library/load-balancer.yml +++ b/library/load-balancer.yml @@ -140,3 +140,7 @@ Outputs: DNSName: Description: ALB Hostname Value: !GetAtt Alb.DNSName + WebappTargetGroup: + Value: !Ref WebappTargetGroup + ApiTargetGroup: + Value: !Ref ApiTargetGroup diff --git a/template.yml b/template.yml index 81b571a..1770855 100644 --- a/template.yml +++ b/template.yml @@ -54,3 +54,34 @@ Resources: Name: !Ref AWS::StackName SubnetId: !GetAtt VpcStack.Outputs.Subnet1 OwnerArn: !Sub 'arn:aws:sts::${AWS::AccountId}:assumed-role/${RoleSSO}/${User}' + Tags: + - Key: Cloud9 + Value: 'yes' + - Key: Stack + Value: !Sub "${AWS::StackName}" + - Key: User + Value: !Ref User + + Cloud9Elb1: + Type: AWS::CloudFormation::Stack + DependsOn: DevelopmentEnvironment + Properties: + TemplateURL: ./library/automation.yml + Parameters: + StackName: !Sub "${AWS::StackName}" + User: !Ref User + TargetSecurityGroup: !GetAtt LoadBalancerStack.Outputs.TargetSecurityGroup + appTargetGroup: !GetAtt LoadBalancerStack.Outputs.WebappTargetGroup + Port: 80 + + Cloud9Elb2: + Type: AWS::CloudFormation::Stack + DependsOn: DevelopmentEnvironment + Properties: + TemplateURL: ./library/automation.yml + Parameters: + StackName: !Sub "${AWS::StackName}" + User: !Ref User + TargetSecurityGroup: !GetAtt LoadBalancerStack.Outputs.TargetSecurityGroup + appTargetGroup: !GetAtt LoadBalancerStack.Outputs.ApiTargetGroup + Port: 3000