There are a few different ways of getting and using the binary for this Lambda function:
- From SAR (Serverless Application Repository)
- Download a pre-built binary from GitHub
- Build the binary yourself
- Other approaches
This Lambda is hosted on SAR which means you can deploy it directly from there.
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: AWS SAM template with a simple API definition
Resources:
# The oidc-authorizer imported from SAR
oidcauthorizer:
Type: AWS::Serverless::Application
Properties:
Location:
ApplicationId: arn:aws:serverlessrepo:eu-west-1:795006566846:applications/oidc-authorizer
SemanticVersion: 0.1.0 # ⬅️ CHANGE: SPECIFY THE EXACT VERSION
Parameters:
# 👀 CHANGE THE FOLLOWING PARAMETERS
AcceptedAlgorithms: ""
AcceptedAudiences: ""
AcceptedIssuers: ""
DefaultPrincipalId: "unknown"
JwksUri: "THE ENDPOINT OF YOUR OIDC PROVIDER JWKS"
MinRefreshRate: "900"
PrincipalIdClaims: "preferred_username, sub"
# The amount of memory (in MB) to give to the authorizer Lambda.
LambdaMemorySize: "128"
# The timeout to give to the authorizer Lambda.
LambdaTimeout: "3"
# YOUR APIs HERE
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
Auth:
DefaultAuthorizer: OidcAuthorizer
Authorizers:
OidcAuthorizer:
FunctionArn: !GetAtt oidcauthorizer.Outputs.OidcAuthorizerArn # ⬅️ This is how your reference the actual lambda deployed by the SAR app
To deploy this stack with sam you'll need to enable the following capabilites: CAPABILITY_AUTO_EXPAND
, CAPABILITY_NAMED_IAM
, and CAPABILITY_IAM
.
A full example is available in the examples
folder.
The following snippet shows how to use the SAR application with CDK (using Typescript):
// import the authorizer lambda for the Serverless Application Repository
const authorizerApp = new cdk.aws_sam.CfnApplication(this, 'AuthorizerApp', {
location: {
applicationId: 'arn:aws:serverlessrepo:eu-west-1:795006566846:applications/oidc-authorizer',
semanticVersion: '0.1.0' // 👀 CHANGE ME
},
parameters: {
// 👀 CHANGE THE FOLLOWING PARAMETERS
AcceptedAlgorithms: "",
AcceptedAudiences: "",
AcceptedIssuers: "",
DefaultPrincipalId: "unknown",
JwksUri: "https://login.microsoftonline.com/3e4abf5a-fdc9-485c-9853-af03c4a32976/discovery/v2.0/keys",
MinRefreshRate: "900",
PrincipalIdClaims: "preferred_username, sub",
// The amount of memory (in MB) to give to the authorizer Lambda.
LambdaMemorySize: "128",
// The timeout to give to the authorizer Lambda.
LambdaTimeout: "3"
}
})
const lambdaAuthorizer = aws_lambda.Function.fromFunctionAttributes(this, 'AuthorizerFunction', {
functionArn: authorizerApp.getAtt('Outputs.OidcAuthorizerArn').toString(),
sameEnvironment: true, // Note: this is important since the lambda is created in another stack we need to make sure CDK knows it's in the same region
})
// creates the authorizer definition
const authorizer = new aws_apigw.TokenAuthorizer(this, 'Authorizer', {
handler: lambdaAuthorizer,
identitySource: aws_apigw.IdentitySource.header('authorization'),
authorizerName: 'OidcAuthorizer',
});
// Your API is here
const apiGw = new aws_apigw.RestApi(this, 'api', {
restApiName: 'OIDC Authorizer Demo',
description: 'A demo app to test the OIDC authorizer',
deployOptions: {
stageName: 'prod',
},
defaultCorsPreflightOptions: {
allowOrigins: aws_apigw.Cors.ALL_ORIGINS,
allowMethods: aws_apigw.Cors.ALL_METHODS,
},
endpointTypes: [aws_apigw.EndpointType.REGIONAL],
deploy: true,
});
const sampleApiLambda1 = new aws_lambda.Function(this, 'sampleApiLambda1', {
runtime: aws_lambda.Runtime.PYTHON_3_9,
handler: 'index.handler',
code: aws_lambda.Code.fromInline(`
def handler(event, context):
return {'body': 'Hello from endpoint1!', 'statusCode': 200}
`)
});
const sampleApiLambda2 = new aws_lambda.Function(this, 'sampleApiLambda2', {
runtime: aws_lambda.Runtime.PYTHON_3_9,
handler: 'index.handler',
code: aws_lambda.Code.fromInline(`
def handler(event, context):
return {'body': 'Hello ' + event['requestContext']['authorizer']['principalId'] + ' from endpoint2! These are your claims: ' + event['requestContext']['authorizer']['jwtClaims'], 'statusCode': 200}
`)
});
apiGw
.root
.addResource('1')
.addMethod('GET', new aws_apigw.LambdaIntegration(sampleApiLambda1), {
authorizer: authorizer,
authorizationType: aws_apigw.AuthorizationType.CUSTOM,
});
apiGw
.root
.addResource('2')
.addMethod('GET', new aws_apigw.LambdaIntegration(sampleApiLambda2), {
authorizer: authorizer,
authorizationType: aws_apigw.AuthorizationType.CUSTOM,
});
const apiGwEndpoint1Output = new cdk.CfnOutput(this, 'ApiEndpoint1', {
description: 'API Gateway endpoint 1',
value: `${apiGw.url}1`
});
const apiGwEndpoint2Output = new cdk.CfnOutput(this, 'ApiEndpoint2', {
description: 'API Gateway endpoint 2',
value: `${apiGw.url}2`
});
A full example is available in the examples
folder.
Note If you don't want to use the public SAR application, you can publish your own.
Every new release of this project is automatically built and published to GitHub as a release asset.
You can easily download the ARM64
binary for a given release by using the following URL template:
https://github.com/lmammino/oidc-authorizer/releases/download/<VERSION>/bootstrap.zip
Make sure to replace <VERSION>
with the actual version you intend to use.
Once you download the binary, you can easily add it to your project and reference it in your SAM template, CDK project, Terraform configuration or whatever you are using to deploy your Lambda functions.
Just make sure to define set the following Lambda properties as follow:
CodeUri: . # OR the path to the **directory** containing lambda binary (which needs to be unzipped)
Handler: bootstrap
Runtime: provided.al2
Architectures: [arm64]
Note
x86
binaries are currently not provided. If you want to use those, you have to build them by yourself.
If you have the Rust toolchain and Cargo Lambda installed in your system. You can compile the binary yourself with the following command:
cargo lambda build --arm64 --release
The compiled binary will be available in target/lambda/oidc-authorizer/bootstrap
.
Note:
cargo lambda
also allows you to cross-compile for other architectures and operative systems. Check out the official documentation to learn how to do that.
Other ways of building and deploying the Lambda function.
This application is already published to SAR and you can deploy it directly from there. But, if you want to publish and maintain your own version, here's how you can do it.
aws s3 mb s3://${YOUR_OWN_BUCKET_NAME}
Then apply the following policy to the bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "serverlessrepo.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::${YOUR_OWN_BUCKET_NAME}/*",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "${YOUR_OWN_ACCOUNT}"
}
}
}
]
}
Make sure to replace both ${YOUR_OWN_BUCKET_NAME}
and ${YOUR_OWN_ACCOUNT}
with the right values.
Requires the Rust toolchain to be installed, an updated version of cargo-lambda
and sam
:
sam build
sam package --output-template-file .aws-sam/packaged.yml --s3-bucket ${YOUR_OWN_BUCKET_NAME}
Make sure to replace ${YOUR_OWN_BUCKET_NAME}
with the right value.
sam publish --template .aws-sam/packaged.yml --region ${YOUR_OWN_REGION}
Make sure to replace ${YOUR_OWN_REGION}
with the right value.