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 --dev
We 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.txt
Additionally, pre-commit
manages its own requirements.
$ pre-commit autoupdate
Use a Lambda-like docker container to build the Lambda artifact
$ sam build --use-container
Tests 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/ -svv
Automated testing will upload coverage results to Coveralls.
Running integration tests requires docker
$ sam local invoke ALBListenerRuleFunction --event events/event.json
sam build
This 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::KmsDecryptPolicyArn
Install the lambda using sceptre:
sceptre --var "profile=my-profile" --var "region=us-east-1" launch prod/cfn-cr-alb-rule.yaml
Tess Thyer; Principal Data Engineer, Sage Bionetworks