GreenfieldTech / lambda-route53-updates

Java AWS Lambda package that receives notifications to update Route53 records
http://www.greenfieldtech.net/open-source/
GNU Lesser General Public License v2.1
2 stars 1 forks source link

lambda-route53-updates

Java AWS Lambda package that receives notifications to update Route53 Hosted Zone DNS records.

This configurable implementation allows AWS Auto Scaling Groups to send events to SNS1 topics that will cause Route53 DNS resource records to be updated with the IP addresses of launched instances.

CircleCI Status Travis Status

Features:

Building

Use Maven to build the project with the shade goal to create a self-contained JAR that you can upload the AWS Lambda:

mvn package shade:shade

You can also just use the pre-built binaries in the latest release that you can find here

Installation

Create an AWS Lambda and upload the generated JAR, for example - using the AWS Console. Make sure to set up the execution role with the correct permissions for accessing the SNS topic you created. See here for a tutorial on how to create AWS Lambda to work with SNS.

The following additional configuration must be done for the AWS Lambda function created:

Permissions

Make sure the role you create for the AWS Lambda has permissions to update your Route53 DNS hosted zone as well as other APIs. Specifically we'll need the following permissions:

Environment Variables

The java implementation includes no hard coded configuration values and all configuration is done using AWS Lambda's support for "Environment Variables".

The lambda function reads the following environment variables:

Testing

To test:

  1. Create an auto scaling group.
  2. Create an SNS topic.
  3. Create a Route53 Hosted Zone.
  4. Create a lambda function as described above and configure it to receive events from the SNS topic created in step 2. Also make sure to set up the environment variables to the hosted zone you created in step 3 and the setting for DNS A round-robin or SRV record.
  5. Set up scaling notifications from the auto scaling group to the SNS topic created in step 2.
  6. Set the auto scaling group "desired" field to a new value to cause an instance to be launched or terminated.
  7. Wait a bit.
  8. Check the AWS CloudWatch log for the lambda function.
  9. Check the Route53 hosted zone to see if the required changes were made.

Sample CloudFormation Template

Using Life-Cycle Hooks With SRV Records

Resources:
  MyLambdaExecutionRole:
    Type: "AWS::IAM::Role"
    Properties:
      Path: /
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal: { Service: [ "lambda.amazonaws.com" ] }
            Action: [ "sts:AssumeRole" ]
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
      Policies:
        - PolicyName: MyRoute53LambdaUpdatePolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource: "*"
              - Effect: Allow
                Action:
                  - "ec2:describeInstances"
                  - "autoscaling:CompleteLifecycleAction"
                  - "route53:ListResourceRecordSets"
                  - "route53:ChangeResourceRecordSets"
                  - "route53:GetChange"
                Resource: "*"

  MyLambdaFunction:
    Type: "AWS::Lambda::Function"
    Properties:
      FunctionName: my-route53-update-lambda
      Runtime: java8
      Code:
         S3Bucket: my-organization-ct-template
         S3Key: cf-resources/lambda-route53-updates-0.2.3.jar
      Description: Update DNS with auto-scaled instance public host names
      MemorySize: 256
      Timeout: 60
      Handler: tech.greenfield.aws.route53.NotifyRecords
      Environment:
        Variables:
          HOSTED_ZONE_ID: "Z1111LLLLN7777"
          SRV_RECORD: "1:1:5060:_sip._udp.example.com"
      Role: !GetAtt [ MyLambdaExecutionRole, Arn ]

  MyAutoscaleUpdateTopic:
    Type: "AWS::SNS::Topic"
    Properties: 
      DisplayName: autoscale-route53-updates
      TopicName: autoscale-route53-updates
      Subscription:
        - Protocol: lambda
          Endpoint: !GetAtt [ MyLambdaFunction, Arn ]

  MyLambdaInvokePermission:
    Type: "AWS::Lambda::Permission"
    Properties:
      FunctionName: !GetAtt [ MyLambdaFunction, Arn ]
      Action: "lambda:InvokeFunction"
      Principal: sns.amazonaws.com
      SourceArn: !Ref MyAutoscaleUpdateTopic
    DependsOn:
      - MyLambdaFunction

  MyAutoScaleGroupLifeCycleScaleOut:
    Type: "AWS::AutoScaling::LifecycleHook"
    Properties:
      AutoScalingGroupName: !Ref MyAutoScaleGroup
      DefaultResult: ABANDON
      LifecycleTransition: "autoscaling:EC2_INSTANCE_LAUNCHING"
      NotificationTargetARN: !Ref MyAutoscaleUpdateTopic
      RoleARN: !GetAtt [ MyLambdaExecutionRole, Arn ]

  MyAutoScaleGroupLifeCycleScaleIn:
    Type: "AWS::AutoScaling::LifecycleHook"
    Properties:
      AutoScalingGroupName: !Ref MyAutoScaleGroup
      DefaultResult: ABANDON
      LifecycleTransition: "autoscaling:EC2_INSTANCE_TERMINATING"
      NotificationTargetARN: !Ref MyAutoscaleUpdateTopic
      RoleARN: !GetAtt [ MyLambdaExecutionRole, Arn ]

Using The Testing CloudFormation Templates

The projects comes with a few CloudFormation testing templates that can be found under src/test/resources. These can be used to exercise the Lambda code, or as a basis to build your own deployemnts.

The following test templates are available:

To use these test templates:

  1. Install the cloudformation-tool gem: gem install --user cloudformation-tool
  2. Make sure you have a key pair that can be used (a key pair is not managed by the template): aws ec2 describe-key-pairs
  3. Build the Lambda: mvn package
  4. Create a new CloudFormation stack: cftool create -p KeyName=<your-keypair> src/test/resources/cf-lifecycle-env.yaml r53-test
  5. Scale up the created stack: cftool scale r53-test ASGTest 1
  6. Wait until the scaling action has completed (i.e. the new server is "InService")
  7. Check that the Route53 hosted zone has been updated with the correct record, using the Route53 console
  8. Scale down the stack: cftool scale r53-test ASGTest 0
  9. Check that the Route53 hosted zone had the DNS record removed, using the Route53 console
  10. Remove the stack when you finish testing: cftool delete r53-test