From 270e101c218b9dfc71937b3692e41de69b684a3b Mon Sep 17 00:00:00 2001 From: "jack.armorgie" Date: Tue, 20 May 2025 11:42:58 +0100 Subject: [PATCH] feat: attempt to create auth0 tf module (copying okta native pattern) --- .github/workflows/ci.yml | 2 + .github/workflows/release.yml | 4 ++ README.md | 1 + authn/openid.index.js | 64 +++++++++++-------- build/build.js | 45 +++++++++++-- infra/terraform/README.md | 2 +- infra/terraform/modules/auth0/main.tf | 10 +++ infra/terraform/modules/auth0/outputs.tf | 4 ++ infra/terraform/modules/auth0/parameters.tf | 56 ++++++++++++++++ infra/terraform/modules/auth0/provider.tf | 10 +++ infra/terraform/modules/auth0/variables.tf | 71 +++++++++++++++++++++ 11 files changed, 233 insertions(+), 36 deletions(-) create mode 100644 infra/terraform/modules/auth0/main.tf create mode 100644 infra/terraform/modules/auth0/outputs.tf create mode 100644 infra/terraform/modules/auth0/parameters.tf create mode 100644 infra/terraform/modules/auth0/provider.tf create mode 100644 infra/terraform/modules/auth0/variables.tf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ea50103..f1eda48 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,8 @@ jobs: - run: npm run-script build-ci okta_native - run: test -f distributions/okta_native/okta_native.zip + - run: npm run-script build-ci auth0 + - run: test -f distributions/auth0/auth0.zip - run: npm run-script build-ci rotate_key_pair - run: test -f distributions/rotate_key_pair/rotate_key_pair.zip diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ee207bd..c2d50f2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,6 +28,9 @@ jobs: - name: Build okta_native run: npm run-script build-ci okta_native + - name: Build auth0 + run: npm run-script build-ci auth0 + - name: Build rotate_key_pair run: npm run-script build-ci rotate_key_pair @@ -36,4 +39,5 @@ jobs: with: files: | ./distributions/okta_native/okta_native.zip + ./distributions/auth0/auth0.zip ./distributions/rotate_key_pair/rotate_key_pair.zip diff --git a/README.md b/README.md index d4b548a..dd13225 100755 --- a/README.md +++ b/README.md @@ -177,6 +177,7 @@ If you need to build a generic package yourself, execute: The supported values of `package` are: * `okta_native` - builds a generic Lambda package for OKTA Native authentication +* `auth0` - builds a generic Lambda package for Auth0 authentication * `rotate_key_pair` - builds a Lambda package for rotating the RSA keys in AWS Secrets Manager GitHub Actions automatically creates a new GitHub release when the repository owner pushes a tag that begins with `v`. diff --git a/authn/openid.index.js b/authn/openid.index.js index 739dee7..5a919f3 100644 --- a/authn/openid.index.js +++ b/authn/openid.index.js @@ -5,6 +5,7 @@ const cookie = require('cookie'); const jwkToPem = require('jwk-to-pem'); const auth = require('./auth.js'); const nonce = require('./nonce.js'); +const cfg = require('./config.js'); const axios = require('axios'); const url = require('url'); const entities = require('html-entities'); @@ -15,40 +16,47 @@ var config; exports.handler = (event, context, callback) => { if (typeof jwks == 'undefined' || typeof discoveryDocument == 'undefined' || typeof config == 'undefined') { - config = JSON.parse(fs.readFileSync('config.json', 'utf8')); + cfg.getConfig('config.json', context.functionName, function(error, result) { + if (error) { + console.log("Internal server error: " + error.message); + internalServerError(callback); + } else { + config = result; - // Get Discovery Document data - console.log("Get discovery document data"); - axios.get(config.DISCOVERY_DOCUMENT) - .then(function(response) { - console.log(response); + // Get Discovery Document data + console.log("Get discovery document data"); + axios.get(config.DISCOVERY_DOCUMENT) + .then(function(response) { + console.log(response); - // Get jwks from discovery document url - console.log("Get jwks from discovery document"); - discoveryDocument = response.data; - if (discoveryDocument.hasOwnProperty('jwks_uri')) { + // Get jwks from discovery document url + console.log("Get jwks from discovery document"); + discoveryDocument = response.data; + if (discoveryDocument.hasOwnProperty('jwks_uri')) { - // Get public key and verify JWT - axios.get(discoveryDocument.jwks_uri) - .then(function(response) { - console.log(response); - jwks = response.data; + // Get public key and verify JWT + axios.get(discoveryDocument.jwks_uri) + .then(function(response) { + console.log(response); + jwks = response.data; - // Callback to main function - mainProcess(event, context, callback); - }) - .catch(function(error) { - console.log("Internal server error: " + error.message); + // Callback to main function + mainProcess(event, context, callback); + }) + .catch(function(error) { + console.log("Internal server error: " + error.message); + internalServerError(callback); + }); + } else { + console.log("Internal server error: Unable to find JWK in discovery document"); internalServerError(callback); - }); - } else { - console.log("Internal server error: Unable to find JWK in discovery document"); - internalServerError(callback); + } + }) + .catch(function(error) { + console.log("Internal server error: " + error.message); + internalServerError(callback); + }); } - }) - .catch(function(error) { - console.log("Internal server error: " + error.message); - internalServerError(callback); }); } else { mainProcess(event, context, callback); diff --git a/build/build.js b/build/build.js index 427b14e..e4538d1 100755 --- a/build/build.js +++ b/build/build.js @@ -18,6 +18,9 @@ if (config.DISTRIBUTION) { case 'okta_native': genericOktaConfiguration(); break; + case 'auth0': + genericAuth0Configuration(); + break; case 'rotate_key_pair': buildRotateKeyPair(); break; @@ -565,16 +568,44 @@ function auth0Configuration() { config.TOKEN_REQUEST.redirect_uri = result.REDIRECT_URI; config.TOKEN_REQUEST.grant_type = 'authorization_code'; - config.AUTHZ = "AUTH0"; + buildAuth0(); + }); +} - shell.cp('./authn/openid.index.js', './distributions/' + config.DISTRIBUTION + '/index.js'); - shell.cp('./nonce.js', './distributions/' + config.DISTRIBUTION + '/nonce.js'); +function genericAuth0Configuration() { + config.PRIVATE_KEY = '${private-key}'; + config.PUBLIC_KEY = '${public-key}'; - fs.writeFileSync('distributions/' + config.DISTRIBUTION + '/config.json', JSON.stringify(result, null, 4)); + config.DISCOVERY_DOCUMENT = '${base-url}/.well-known/openid-configuration'; + config.SESSION_DURATION = '${session-duration}'; - shell.cp('./authz/auth0.js', './distributions/' + config.DISTRIBUTION + '/auth.js'); - writeConfig(config, zip, ['config.json', 'index.js', 'auth.js', 'nonce.js']); - }); + config.BASE_URL = '${base-url}'; + config.CALLBACK_PATH = '${callback-path}'; + config.LOGOUT_PATH = '${logout-path}'; + + config.AUTH_REQUEST.client_id = '${client-id}'; + config.AUTH_REQUEST.response_type = 'code'; + config.AUTH_REQUEST.scope = '${scope}'; + config.AUTH_REQUEST.redirect_uri = 'https://${domain-name}${callback-path}'; + + config.TOKEN_REQUEST.client_id = '${client-id}'; + config.TOKEN_REQUEST.redirect_uri = 'https://${domain-name}${callback-path}'; + config.TOKEN_REQUEST.grant_type = 'authorization_code'; + config.TOKEN_REQUEST.client_secret = '${client-secret}'; + + buildAuth0(true); +} + +function buildAuth0(isGeneric) { + config.AUTHZ = "AUTH0"; + + shell.cp('./authn/openid.index.js', './distributions/' + config.DISTRIBUTION + '/index.js'); + shell.cp('./nonce.js', './distributions/' + config.DISTRIBUTION + '/nonce.js'); + + shell.cp(isGeneric ? './config/generic.config.js' : './config/custom.config.js', './distributions/' + config.DISTRIBUTION + '/config.js'); + + shell.cp('./authz/auth0.js', './distributions/' + config.DISTRIBUTION + '/auth.js'); + writeConfig(config, zip, ['config.json', 'config.js', 'index.js', 'auth.js', 'nonce.js']); } // Centrify configuration diff --git a/infra/terraform/README.md b/infra/terraform/README.md index 606da90..6ed7650 100644 --- a/infra/terraform/README.md +++ b/infra/terraform/README.md @@ -1,6 +1,6 @@ # Terraform Modules for CloudFront Authentication -This directory contains the _Terraform_ configuration for adding authentication to a CloudFront distribution. Currently only OKTA Native authentication is supported. +This directory contains the _Terraform_ configuration for adding authentication to a CloudFront distribution. Currently only OKTA Native and Auth0 authentication is supported. ## Usage diff --git a/infra/terraform/modules/auth0/main.tf b/infra/terraform/modules/auth0/main.tf new file mode 100644 index 0000000..493956c --- /dev/null +++ b/infra/terraform/modules/auth0/main.tf @@ -0,0 +1,10 @@ +module "auth" { + source = "../_auth" + + release_version = var.release_version + name = var.name + tags = var.tags + package_url = "https://github.com/iress/cloudfront-auth/releases/download/${var.release_version}/auth0.zip" + key_pair_rotation_period_days = var.key_pair_rotation_period_days + kms_key_arn = var.kms_key_arn +} diff --git a/infra/terraform/modules/auth0/outputs.tf b/infra/terraform/modules/auth0/outputs.tf new file mode 100644 index 0000000..e181587 --- /dev/null +++ b/infra/terraform/modules/auth0/outputs.tf @@ -0,0 +1,4 @@ +output "auth_lambda_arn" { + value = module.auth.auth_lambda_arn + description = "The Amazon Resource Name (ARN) identifying the authentication Lambda Function Version" +} diff --git a/infra/terraform/modules/auth0/parameters.tf b/infra/terraform/modules/auth0/parameters.tf new file mode 100644 index 0000000..585b838 --- /dev/null +++ b/infra/terraform/modules/auth0/parameters.tf @@ -0,0 +1,56 @@ +resource "aws_ssm_parameter" "base_url" { + name = "/${var.name}/base-url" + type = "String" + value = var.org_url + tags = var.tags +} + +resource "aws_ssm_parameter" "client_id" { + name = "/${var.name}/client-id" + type = "String" + value = var.client_id + tags = var.tags +} + +resource "aws_ssm_parameter" "domain_name" { + name = "/${var.name}/domain-name" + type = "String" + value = var.domain_name + tags = var.tags +} + +resource "aws_ssm_parameter" "callback_path" { + name = "/${var.name}/callback-path" + type = "String" + value = var.callback_path + tags = var.tags +} + +resource "aws_ssm_parameter" "logout_path" { + name = "/${var.name}/logout-path" + type = "String" + value = var.logout_path + tags = var.tags +} + +resource "aws_ssm_parameter" "session_duration" { + name = "/${var.name}/session-duration" + type = "String" + value = var.session_duration * 60 * 60 + tags = var.tags +} + +resource "aws_ssm_parameter" "scope" { + name = "/${var.name}/scope" + type = "String" + value = var.scope + tags = var.tags +} + +resource "aws_ssm_parameter" "client_secret" { + name = "/${var.name}/client-secret" + type = "SecureString" + value = var.client_secret + tags = var.tags + +} diff --git a/infra/terraform/modules/auth0/provider.tf b/infra/terraform/modules/auth0/provider.tf new file mode 100644 index 0000000..6312173 --- /dev/null +++ b/infra/terraform/modules/auth0/provider.tf @@ -0,0 +1,10 @@ +# Provider passed in should always be us-east-1 + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 3.28" + } + } +} diff --git a/infra/terraform/modules/auth0/variables.tf b/infra/terraform/modules/auth0/variables.tf new file mode 100644 index 0000000..f9a356d --- /dev/null +++ b/infra/terraform/modules/auth0/variables.tf @@ -0,0 +1,71 @@ +variable "release_version" { + description = "The name of the GitHub release version to deploy" + type = string +} + +variable "name" { + description = "A name for the AWS resources created by this module" + type = string +} + +variable "tags" { + description = "Tags to add to each resource" + type = map(string) + default = {} +} + +variable "org_url" { + description = "The org URL for the Auth0 environment" + type = string +} + +variable "client_id" { + description = "Public identifier for the client (can be found in Auth0 Admin -> Applications)" + type = string +} + +variable "client_secret" { + description = "The client secret for the Auth0 application" + type = string +} + +variable "domain_name" { + description = "Domain name of the CloudFront distribution" + type = string +} + +variable "callback_path" { + description = "The path of the URI where Auth0 will send users after authentication" + type = string + default = "/_callback" +} + +variable "logout_path" { + description = "The path of the URI where Auth0 will send users after logout" + type = string + default = "/_logout" +} + +variable "session_duration" { + description = "The number of hours that the JWT is valid for" + type = number + default = 2 +} + +variable "key_pair_rotation_period_days" { + description = "The number of days between automatic scheduled rotations of the key pair" + type = number + default = 7 +} + +variable "scope" { + description = "A space delimited list of Auth0 scopes which are used by an application during authentication to authorize access to a user's details, openid is required for authentication requests and other scopes like email may also be included." + type = string + default = "openid email" +} + +variable "kms_key_arn" { + description = "The ARN of the KMS key used to encrypt the key pair" + type = string + default = null +}