Cloudformation Custom Resource that creates a listener rule for an AWS ALB. The rule contains two actions. The first is an authentication action; the second rule forwards to a target group, containing only a single instance, if the first rule succeeds.
Inventory of source code and supporting files:
- ruler - Code for the application's Lambda function.
- events - Invocation events that you can use to invoke the function.
- tests - Unit tests for the application code.
- template.yaml - A template that defines the application's AWS resources.
The AWS SAM CLI is used to build and package the lambda code. The sceptre utility is used to deploy the macro that invokes the lambda as a CloudFormation stack.
In addition to creating the ALBListenerRule custom resource, also required is a target group with a single target, the EC2 instance. It is necessary to create the target group so that the ALB can route to the instance if authentication succeeds.
Here's an example, inserted into a stack that contains an
AWS::EC2::Instance
resource with the Logical ID LinuxInstance. It also refers to several other
resources defined outside:
VpcId: this uses an imported value from the VPC that is home to the ALBServiceToken: this uses the Lambda function ARNListenerArn: the ARN of a listener created for the ALB
EC2TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub 'TargetGroup-${LinuxInstance}'
HealthCheckIntervalSeconds: 30
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 15
HealthyThresholdCount: 5
Matcher:
HttpCode: '200'
Port: 443
Protocol: HTTPS
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '20'
Targets:
- Id: !Ref LinuxInstance
Port: 443
UnhealthyThresholdCount: 3
VpcId: !ImportValue
'Fn::Sub': '${AWS::Region}-${VpcName}-VPCId'
Tags:
- Key: Name
Value: !Sub 'TargetGroup-${LinuxInstance}'
AlbListenerRule:
Type: Custom::ALBListenerRule
Properties:
ServiceToken: !ImportValue
'Fn::Sub': '${AWS::Region}-cfn-cr-alb-rule-FunctionArn'
InstanceId: !Ref LinuxInstance
TargetGroupArn: !Ref EC2TargetGroup
ListenerArn: 'arn:aws:elasticloadbalancing:us-east-1:465877038949:listener/app/sc135-poc/bf54cc972d64237b/8ad4c71091181c60'The creation of the custom resource triggers the lambda. The lambda makes several AWS API calls in order to create a listener rule. First, it pulls a secret key from AWS System Manager for the OIDC client. Second, it pulls all existing rules to calculate the priority. Finally, it creates the rule with the actions as described above.
Contributions are welcome.
Install the following applications:
Run pipenv install --dev to install both production and development
requirements, and pipenv shell to activate the virtual environment. For more
information see the pipenv docs.
After activating the virtual environment, run pre-commit install to install
the pre-commit git hook.
First, make any needed updates to the base requirements in Pipfile, then use
pipenv to regenerate both Pipfile.lock and requirements.txt.
$ pipenv update --devWe use pipenv to control versions in testing, but sam relies on
requirements.txt directly for building the lambda artifact, so we dynamically
generate requirements.txt from Pipfile.lock before building the artifact.
The file must be created in the CodeUri directory specified in
template.yaml.
$ pipenv requirements > ruler/requirements.txtAdditionally, pre-commit manages its own requirements.
$ pre-commit autoupdateUse a Lambda-like docker container to build the Lambda artifact
$ sam build --use-containerTests are defined in the tests folder in this project, and dependencies are
managed with pipenv. Install the development dependencies and run the tests
using coverage.
$ pipenv run coverage run -m pytest tests/ -svvAutomated testing will upload coverage results to Coveralls.
Running integration tests requires docker
$ sam local invoke ALBListenerRuleFunction --event events/event.jsonsam buildThis requires the correct permissions to upload to bucket
bootstrap-awss3cloudformationbucket-19qromfd235z9 and
essentials-awss3lambdaartifactsbucket-x29ftznj6pqw
sam package --template-file .aws-sam/build/template.yaml \
--s3-bucket essentials-awss3lambdaartifactsbucket-x29ftznj6pqw \
--output-template-file .aws-sam/build/cfn-cr-alb-rule.yaml
aws s3 cp .aws-sam/build/cfn-cr-alb-rule.yaml s3://bootstrap-awss3cloudformationbucket-19qromfd235z9/cfn-cr-alb-rule/master/Create the following sceptre file, changing the parameters to match the values for your OIDC client.
config/prod/cfn-cr-alb-rule.yaml
template:
type: "http"
url: "https://s3.amazonaws.com/bootstrap-awss3cloudformationbucket-19qromfd235z9/cfn-cr-alb-rule/master/cfn-cr-alb-rule.yaml"
stack_name: "cfn-cr-alb-rule"
parameters:
OidcClientSecretKeyName: '/alb-notebook-access/AuthenticateOidcClientSecret'
OidcIssuer: 'https://repo-prod.prod.sagebase.org/auth/v1'
OidcAuthorizationEndpoint: 'https://signin.synapse.org'
OidcTokenEndpoint: 'https://qtg2zn2bbf.execute-api.us-east-1.amazonaws.com/token'
OidcUserInfoEndpoint: 'https://repo-prod.prod.sagebase.org/auth/v1/oauth2/userinfo'
OidcClientId: '100050'
SessionCookieNamePrefix: 'AWSELBAuthSessionCookie'
SessionTimeout: 3600
KmsDecryptPolicyArn: !stack_output_external sc-kms-key::KmsDecryptPolicyArnInstall the lambda using sceptre:
sceptre --var "profile=my-profile" --var "region=us-east-1" launch prod/cfn-cr-alb-rule.yamlTess Thyer; Principal Data Engineer, Sage Bionetworks