Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom user pool domain, redirect endpoints, and additional pass through settings for Cognito #47

Merged
merged 6 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.terraform.lock.hcl
.terraform
.idea
*.zip
.vscode
dist
22 changes: 22 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.common_tf_docs_config: &common_tf_docs_config
--hook-config=--add-to-existing-file=true
--hook-config=--create-file-if-not-exist=true

.common_tf_docs_readme_file: &common_tf_docs_readme_file
--hook-config=--path-to-file=README.md

repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.76.0
hooks:
- id: terraform_fmt
args:
- --args=-recursive

- id: terraform_docs
files: '^.*.tf$'
args:
- *common_tf_docs_readme_file
- *common_tf_docs_config
- --hook-config=--config=data-io/modules/data-io-regional/.terraform-docs.yml

5 changes: 5 additions & 0 deletions .terraform-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
formattter: markdown

sort:
enabled: true
by: name
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.0] - TBD

### Added
- Added support for Cognito custom user pool domains via new variable `cognito_user_pool_domain`.
- Added support for custom redirect endpoint for Cognito@Edge via new variable `cognito_redirect_path`.
- Added support for additional Cognito@Edge settings via new variable `cognito_additional_settings`.

### Changed
- Expand TF AWS provider range to allow support for `5.0.0` and greater.
- Update Lambda@Edge NodeJS version to `nodejs20.x` (was `nodejs14.x`) and make it user configurable via new variable `lambda_runtime`.
- Lambda@Edge lambda zip is now bundled via `esbuild` to reduce package size.
- Change default lambda timeout to `5` seconds (was `3` seconds) and make it user configurable via new variable `lambda_timeout`.
- Remove `aws-sdk` in favor of `@aws-sdk` v3 libraries.

## [1.0.1] - 2022-06-22

### Changed
Expand Down
21 changes: 14 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ enforce Cognito Authentication through a configured Cognito User Pool.

## Requirements
- Terraform version >= 1.0.X
- NodeJS + NPM (compatible with NodeJS 14.X.X)
- NodeJS + NPM (compatible with NodeJS 18.X.X)
- Used for `npm ci` dependency installation for Lambda@Edge Bundle.
- Terraform AWS Provider in `us-east-1`
- Requirement for CloudFront + Lambda@Edge runtime.
Expand Down Expand Up @@ -54,7 +54,7 @@ resource "aws_cloudfront_distribution" "my_cloudfront_distribution" {

```

### Destroy Issues
### Destroy Issues (AWS Provider :: > v4.57.0)
Note that if a destroy action is performed on this terraform module, terraform is unable to delete the Lambda@Edge that was published as a part of this infrastructure (This is noted by this [issue](https://github.com/hashicorp/terraform-provider-aws/issues/1721) on the Terraform provider).
In order to properly delete this resource, it should be manually cleaned up, [instructions here](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-delete-replicas.html) and manually removed from the state.

Expand All @@ -64,20 +64,21 @@ The state deletion command should follow this format:
terraform state rm 'module.<my_module_name>.aws_lambda_function.cloudfront_auth_edge'
```

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | ~> 1.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~> 4.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_archive"></a> [archive](#provider\_archive) | 2.2.0 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | 3.57.0 |
| <a name="provider_null"></a> [null](#provider\_null) | 3.1.0 |
| <a name="provider_archive"></a> [archive](#provider\_archive) | 2.4.0 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | 5.26.0 |
| <a name="provider_null"></a> [null](#provider\_null) | 3.2.2 |

## Modules

Expand All @@ -101,14 +102,19 @@ No modules.

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_cognito_additional_settings"></a> [cognito\_additional\_settings](#input\_cognito\_additional\_settings) | Map of any to configure any additional cognito@edge parameters not handled by this module. | `map(any)` | `{}` | no |
| <a name="input_cognito_cookie_expiration_days"></a> [cognito\_cookie\_expiration\_days](#input\_cognito\_cookie\_expiration\_days) | Number of days to keep the cognito cookie valid. | `number` | `7` | no |
| <a name="input_cognito_disable_cookie_domain"></a> [cognito\_disable\_cookie\_domain](#input\_cognito\_disable\_cookie\_domain) | Sets domain attribute in cookies, defaults to false. | `bool` | `false` | no |
| <a name="input_cognito_log_level"></a> [cognito\_log\_level](#input\_cognito\_log\_level) | Logging level. Default: 'silent' | `string` | `"silent"` | no |
| <a name="input_cognito_redirect_path"></a> [cognito\_redirect\_path](#input\_cognito\_redirect\_path) | Optional path to redirect to after a successful cognito login. | `string` | `""` | no |
| <a name="input_cognito_user_pool_app_client_id"></a> [cognito\_user\_pool\_app\_client\_id](#input\_cognito\_user\_pool\_app\_client\_id) | Cognito User Pool App Client ID for the targeted user pool. | `string` | n/a | yes |
| <a name="input_cognito_user_pool_app_client_secret"></a> [cognito\_user\_pool\_app\_client\_secret](#input\_cognito\_user\_pool\_app\_client\_secret) | Cognito User Pool App Client Secret for the targeted user pool. NOTE: This is currently not compatible with AppSync applications. | `string` | `null` | no |
| <a name="input_cognito_user_pool_domain"></a> [cognito\_user\_pool\_domain](#input\_cognito\_user\_pool\_domain) | Optional: Full Domain of the Cognito User Pool to utilize. Mutually exclusive with 'cognito\_user\_pool\_name'. | `string` | `""` | no |
| <a name="input_cognito_user_pool_id"></a> [cognito\_user\_pool\_id](#input\_cognito\_user\_pool\_id) | Cognito User Pool ID for the targeted user pool. | `string` | n/a | yes |
| <a name="input_cognito_user_pool_name"></a> [cognito\_user\_pool\_name](#input\_cognito\_user\_pool\_name) | Name of the Cognito User Pool to utilize. | `string` | n/a | yes |
| <a name="input_cognito_user_pool_name"></a> [cognito\_user\_pool\_name](#input\_cognito\_user\_pool\_name) | Name of the Cognito User Pool to utilize. Required if 'cognito\_user\_pool\_domain' is not set. | `string` | `""` | no |
| <a name="input_cognito_user_pool_region"></a> [cognito\_user\_pool\_region](#input\_cognito\_user\_pool\_region) | AWS region where the cognito user pool was created. | `string` | `"us-west-2"` | no |
| <a name="input_lambda_runtime"></a> [lambda\_runtime](#input\_lambda\_runtime) | Lambda runtime to utilize for Lambda@Edge. | `string` | `"nodejs20.x"` | no |
| <a name="input_lambda_timeout"></a> [lambda\_timeout](#input\_lambda\_timeout) | Amount of timeout in seconds to set on for Lambda@Edge. | `number` | `5` | no |
| <a name="input_name"></a> [name](#input\_name) | Name to prefix on all infrastructure created by this module. | `string` | n/a | yes |
| <a name="input_tags"></a> [tags](#input\_tags) | Map of tags to attach to all AWS resources created by this module. | `map(string)` | `{}` | no |

Expand All @@ -118,3 +124,4 @@ No modules.
|------|-------------|
| <a name="output_arn"></a> [arn](#output\_arn) | ARN for the Lambda@Edge created by this module. |
| <a name="output_qualified_arn"></a> [qualified\_arn](#output\_qualified\_arn) | Qualified ARN for the Lambda@Edge created by this module. |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
18 changes: 10 additions & 8 deletions files/deployable/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const { STS, IAM, SSM } = require('aws-sdk');
const { IAMClient, GetRolePolicyCommand } = require('@aws-sdk/client-iam');
const { SSMClient, GetParameterCommand } = require('@aws-sdk/client-ssm');
const { STSClient, GetCallerIdentityCommand } = require('@aws-sdk/client-sts');

const NodeCache = require("node-cache");
const { Authenticator } = require('cognito-at-edge');

const { getLogger } = require('./logger');

// Global Static variables
Expand Down Expand Up @@ -48,20 +50,20 @@ async function createAuthenticatorFromConfiguration() {
const rootLogger = getLogger();

try {
const ssmClient = new SSM({ region: 'us-east-1' });
const stsClient = new STS({ region: 'us-east-1' });
const iamClient = new IAM({ region: 'us-east-1' });
const ssmClient = new SSMClient({ region: 'us-east-1' });
const stsClient = new STSClient({ region: 'us-east-1' });
const iamClient = new IAMClient({ region: 'us-east-1' });

// Get the IAM role that is currently running this lambda.
rootLogger.info('Attempting to get current execution IAM Role.');
const curIdentity = await stsClient.getCallerIdentity().promise();
const curIdentity = await stsClient.send(new GetCallerIdentityCommand({}));
const iamRole = curIdentity.Arn;
rootLogger.info(`Running as IAM Role[${iamRole}].`);
const iamRoleName = getRoleNameFromExecutionARN(iamRole, 'role')

// Get the predefined policy which references the SSM Parameter we need to pull
rootLogger.info(`Fetching Policy[${POLICY_NAME}] from IAM Role[${iamRole}].`);
const { PolicyDocument } = await iamClient.getRolePolicy({ PolicyName: POLICY_NAME, RoleName: iamRoleName }).promise();
const { PolicyDocument } = await iamClient.send(new GetRolePolicyCommand({ PolicyName: POLICY_NAME, RoleName: iamRoleName }));
rootLogger.info('Successfully fetched Policy document.');

const parsedPolicyDoc = decodeURIComponent(PolicyDocument);
Expand All @@ -72,7 +74,7 @@ async function createAuthenticatorFromConfiguration() {

// Fetch the data from parameter store
rootLogger.info(`Fetching Parameter[${ssmParameterName}].`);
const { Parameter } = await ssmClient.getParameter({ Name: ssmParameterName, WithDecryption: true }).promise();
const { Parameter } = await ssmClient.send(new GetParameterCommand({ Name: ssmParameterName, WithDecryption: true }));
rootLogger.info(`Successfully fetched Parameter[${ssmParameterName}].`);

const authConfig = JSON.parse(Parameter.Value);
Expand Down
Loading
Loading