diff --git a/README.md b/README.md index f261b87..7b5fbdf 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ aws-cloudtrail aws-cloudtrail-s3-bucket aws-cloudwatch aws-cloudwatch-event-rule-master +aws-cognito-user-pool aws-dynamodb-dax aws-dynamodb-table aws-ecr diff --git a/aws-cognito-user-pool/CHANGELOG.md b/aws-cognito-user-pool/CHANGELOG.md new file mode 100644 index 0000000..a7be72d --- /dev/null +++ b/aws-cognito-user-pool/CHANGELOG.md @@ -0,0 +1,313 @@ +## 0.24.0 (November 13, 2023) + +FIXES: + +* Make sure `attribute_constraints` are created for string and number schemas (thanks @@mhorbul) + +## 0.23.0 (July 19, 2023) + +ENHANCEMENTS: + +* Add Cognito User Pool name as output (thanks @SlavaNL) + +## 0.22.0 (March 31, 2023) + +FIXES: + +* Fix user attribute update settings lookup (thanks @trahim) + +## 0.21.0 (January 6, 2023) + +ENHANCEMENTS: + +* Add support for `auth_session_validity` parameter to user pool client (thanks @xposix) + +## 0.20.1 (November 24, 2022) + +FIXES: + +* Updated AWS provider minimum version to v4.38 as a requirement for `deletion_protection` (thanks @gchristidis) + +## 0.20.0 (September 22, 2022) + +ENHANCEMENTS: + +* Add support for user pool deletion_protection (thanks @dmcgillen) +* Set `identity_providers` variable to `sensitive` (thanks @LawrenceWarren) + +FIXES: + +* Remove duplicate `require_lowercasei` key for password policies (thanks @jeromegamez) + +## 0.19.0 (September 22, 2022) + +FIXES: + +* Fix the attributes constraints for number and string schemas (thanks @sgtoj) + +## 0.18.2 (August 12, 2022) + +FIXES: + +* Fix ´username_configuration´ typo in README (thanks @ajoga and @KelvinVenancio) + +## 0.18.1 (August 12, 2022) + +ENHANCEMENTS: + +* Add 0.13.7 as the lowest Terraform version supported (thanks @oleksiidv) + +## 0.18.0 (July 25, 2022) + +ENHANCEMENTS: + +* Add missing option to allow client token revocation (thanks @rastakajakwanna) + +## 0.17.0 (June 3, 2022) + +ENHANCEMENTS: + +* Add `configuration_set` field in `email_configuration` block (thanks @tiagoposse) + +## 0.16.0 (May 30, 2022) + +ENHANCEMENTS: + +* Update complete example +* Update .pre-commit yaml file + +FIXES: + +* Fix `lambda_config` keeps changing + +## 0.15.2 (February 19, 2022) + +FIXES: + +* Change aws provider version constraints to be able to use 4.x + +## 0.15.1 (February 15, 2022) + +FIXES: + +* Change default value for `client_prevent_user_existence_errors` (thanks @juan-acevedo-ntt) + +## 0.15.0 (February 12, 2022) + +ENHANCEMENTS: + +* Add custom sms and email sender support (thanks @xposix) + +## 0.14.2 (September 20, 2021) + +FIXES: + +* Add identity provider as a dependency for `aws_cognito_user_pool_client` (thanks @xposix) + +## 0.14.1 (August 25, 2021) + +FIXES: + +* Use accepted token validity periods (thanks @bobdoah) + +## 0.14.0 (August 19, 2021) + +ENHANCEMENTS: + +* Add map output for client and secret ids (thanks @dmytro-dorofeiev) + +## 0.13.0 (August 10, 2021) + +ENHANCEMENTS: + +* Add support for Cognito Identity Providers (thanks @bobdoah) + +## 0.12.0 (July 4, 2021) + +FIXES: + +* Set client_secrets output to be sensitive (thanks @sapei) + +## 0.11.1 (May 21, 2021) + +FIXES: + +* Revert prevent_destroy due to [Variables may not be used here issue](https://github.com/hashicorp/terraform/issues/22544) + +## 0.11.0 (May 21, 2021) + +ENHANCEMENTS: + +* Add support to prevent the user pool from being destroyed (thanks @Waschnick) + +## 0.10.5 (May 12, 2021) + +FIXES: + +* Fix incorrect example with `access_token_validity` (thanks @tsimbalar) + +## 0.10.4 (April 25, 2021) + +FIXES: + +* Add `depends_on` servers in `aws_cognito_user_pool_client.client` resource + +## 0.10.3 (April 15, 2021) + +FIXES: + +* Make code formatting works with Terraform >= 0.14 (Thanks @stevie-) + +## 0.10.2 (April 10, 2021) + +FIXES: + +* Remove lifecycle for schema addition ([issue](https://github.com/hashicorp/terraform-provider-aws/pull/18512) fixed in the AWS provider) + +## 0.10.1 (April 10, 2021) + +FIXES: + +* Update complete example + +## 0.10.0 (April 10, 2021) + +ENHANCEMENTS: + +* Add support for `access_token_validity`, `id_token_validity` and `token_validity_units` +* Update complete example with `access_token_validity`, `id_token_validity` and `token_validity_units` + +## 0.9.4 (February 14, 2021) + +FIXES: + +* Update README to include schema changes know issue + +## 0.9.3 (January 27, 2021) + +ENHANCEMENTS: + +* Update description for `enabled` variable + + +## 0.9.2 (January 27, 2021) + +ENHANCEMENTS: + +* Update conditional creation example + +## 0.9.1 (January 27, 2021) + +FIXES: + +* Set default value for enable variable to `true` + +## 0.9.0 (January 24, 2021) + +ENHANCEMENTS: + +* Support conditional creation (thanks @Necromancerx) + +## 0.8.0 (December 28, 2020) + +ENHANCEMENTS: + +* Add support for support `account_recovery_setting` + +## 0.7.1 (December 11, 2020) + +FIXES: + +* Ignore schema changes and prevent pool destruction + +## 0.7.0 (November 25, 2020) + +ENHANCEMENTS: + +* Add `from_email_address` + +## 0.6.2 (August 13, 2020) + +FIXES: + +* Update CHANGELOG + +## 0.6.1 (August 13, 2020) + +ENHANCEMENTS: + +* Change source in examples to use Terraform format + +FIXES: + +* Add `username_configuration` dynamic block to avoid forcing a new resource when importing a user pool +* Remove `case_sensitive` variable. Use the `username_configuration` map variable to define the `case_sensitive` attribute + +UPDATES: + +* Updated README and examples + +## 0.5.0 (July 31, 2020) + +FIXES: + +* Depcreate support to `unused_account_validity_days` +* Update README and examples removing any reference to the deprecated `unused_account_validity_days` field + +## 0.4.0 (May 2, 2020) + +ENHANCEMENTS: + +* Add support for `software_token_mfa_configuration` + +## 0.3.3 (April 24, 2020) + +FIXES: + +* Applies `case_sensitive` via `username_configuration` + +## 0.3.2 (April 24, 2020) + +UPDATE: + +* Update README with `case_sensitive` + +## 0.3.1 (April 24, 2020) + +ENHANCEMENTS: + +* Add `case_sensitive` for `aws_cognito_user_pool` + +## 0.3.0 (April 1, 2020) + +ENHANCEMENTS: + +* Add `param client_prevent_user_existence_errors` for client + +UPDATES: + +* Add Terraform logo in README + +## 0.2.2 (March 16, 2020) + +FIXES: + +* Fix typo in comments + +## 0.2.1 (February 6, 2020) + +BUG FIXES: + +* Cognito unused_account_validity_days bug with 2.47: The aws-provider reports the existence of the `unused_account_validity_days` even if it was never declared, automatically matching the new `temporary_password_validity_day` + +## 0.2.0 (February 5, 2020) + +UPDATES: + +* AWS Provider 2.47.0: Deprecate unused_account_validity_days argument and add support for temporary_password_validity_days argument + +## 0.1.0 (November 23, 2019) + +FEATURES: + + * Module implementation diff --git a/aws-cognito-user-pool/LICENSE b/aws-cognito-user-pool/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/aws-cognito-user-pool/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/aws-cognito-user-pool/README.md b/aws-cognito-user-pool/README.md new file mode 100644 index 0000000..6122cb0 --- /dev/null +++ b/aws-cognito-user-pool/README.md @@ -0,0 +1,294 @@ +# terraform-aws-cognito-user-pool + +Terraform module to create [Amazon Cognito User Pools](https://aws.amazon.com/cognito/), configure its attributes and resources such as **app clients**, **domain**, **resource servers**. Amazon Cognito User Pools provide a secure user directory that scales to hundreds of millions of users. As a fully managed service, User Pools are easy to set up without any worries about standing up server infrastructure. + +## Usage + +You can use this module to create a Cognito User Pool using the default values or use the detailed definition to set every aspect of the Cognito User Pool + +Check the [examples](examples/) where you can see the **simple** example using the default values, the **simple_extended** version which adds  **app clients**, **domain**, **resource servers** resources, or the **complete** version with a detailed example. + +### Example (simple) + +This simple example creates a AWS Cognito User Pool with the default values: + +``` +module "aws_cognito_user_pool_simple" { + + source = "lgallard/cognito-user-pool/aws" + + user_pool_name = "mypool" + + tags = { + Owner = "infra" + Environment = "production" + Terraform = true + } +``` + +### Example (conditional creation) + +If you need to create Cognito User Pool resources conditionally in ealierform versions such as 0.11, 0,12 and 0.13 you can set the input variable `enabled` to false: + +``` +# This Cognito User Pool will not be created +module "aws_cognito_user_pool_conditional_creation" { + + source = "lgallard/cognito-user-pool/aws" + + user_pool_name = "conditional_user_pool" + + enabled = false + + tags = { + Owner = "infra" + Environment = "production" + Terraform = true + } + +} +``` + +For Terraform 0.14 and later you can use `count` inside `module` blocks, or use the input variable `enabled` as described above. + +### Example (complete) + +This more complete example creates a AWS Cognito User Pool using a detailed configuration. Please check the example folder to get the example with all options: + +``` +module "aws_cognito_user_pool_complete" { + + source = "lgallard/cognito-user-pool/aws" + + user_pool_name = "mypool" + alias_attributes = ["email", "phone_number"] + auto_verified_attributes = ["email"] + + deletion_protection = "ACTIVE" + + admin_create_user_config = { + email_subject = "Here, your verification code baby" + } + + email_configuration = { + email_sending_account = "DEVELOPER" + reply_to_email_address = "email@example.com" + source_arn = "arn:aws:ses:us-east-1:888888888888:identity/example.com" + } + + password_policy = { + minimum_length = 10 + require_lowercase = false + require_numbers = true + require_symbols = true + require_uppercase = true + } + + schemas = [ + { + attribute_data_type = "Boolean" + developer_only_attribute = false + mutable = true + name = "available" + required = false + }, + { + attribute_data_type = "Boolean" + developer_only_attribute = true + mutable = true + name = "registered" + required = false + } + ] + + string_schemas = [ + { + attribute_data_type = "String" + developer_only_attribute = false + mutable = false + name = "email" + required = true + + string_attribute_constraints = { + min_length = 7 + max_length = 15 + } + } + ] + + recovery_mechanisms = [ + { + name = "verified_email" + priority = 1 + }, + { + name = "verified_phone_number" + priority = 2 + } + ] + + tags = { + Owner = "infra" + Environment = "production" + Terraform = true + } + +``` + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= v0.13.7 | +| [aws](#requirement\_aws) | >= 4.38 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | 5.8.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_cognito_identity_provider.identity_provider](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_identity_provider) | resource | +| [aws_cognito_resource_server.resource](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_resource_server) | resource | +| [aws_cognito_user_group.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_group) | resource | +| [aws_cognito_user_pool.pool](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_pool) | resource | +| [aws_cognito_user_pool_client.client](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_pool_client) | resource | +| [aws_cognito_user_pool_domain.domain](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_pool_domain) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [admin\_create\_user\_config](#input\_admin\_create\_user\_config) | The configuration for AdminCreateUser requests | `map(any)` | `{}` | no | +| [admin\_create\_user\_config\_allow\_admin\_create\_user\_only](#input\_admin\_create\_user\_config\_allow\_admin\_create\_user\_only) | Set to True if only the administrator is allowed to create user profiles. Set to False if users can sign themselves up via an app | `bool` | `true` | no | +| [admin\_create\_user\_config\_email\_message](#input\_admin\_create\_user\_config\_email\_message) | The message template for email messages. Must contain `{username}` and `{####}` placeholders, for username and temporary password, respectively | `string` | `"{username}, your verification code is `{####}`"` | no | +| [admin\_create\_user\_config\_email\_subject](#input\_admin\_create\_user\_config\_email\_subject) | The subject line for email messages | `string` | `"Your verification code"` | no | +| [admin\_create\_user\_config\_sms\_message](#input\_admin\_create\_user\_config\_sms\_message) | - The message template for SMS messages. Must contain `{username}` and `{####}` placeholders, for username and temporary password, respectively | `string` | `"Your username is {username} and temporary password is `{####}`"` | no | +| [alias\_attributes](#input\_alias\_attributes) | Attributes supported as an alias for this user pool. Possible values: phone\_number, email, or preferred\_username. Conflicts with `username_attributes` | `list(string)` | `null` | no | +| [auto\_verified\_attributes](#input\_auto\_verified\_attributes) | The attributes to be auto-verified. Possible values: email, phone\_number | `list(string)` | `[]` | no | +| [client\_access\_token\_validity](#input\_client\_access\_token\_validity) | Time limit, between 5 minutes and 1 day, after which the access token is no longer valid and cannot be used. This value will be overridden if you have entered a value in `token_validity_units`. | `number` | `60` | no | +| [client\_allowed\_oauth\_flows](#input\_client\_allowed\_oauth\_flows) | The name of the application client | `list(string)` | `[]` | no | +| [client\_allowed\_oauth\_flows\_user\_pool\_client](#input\_client\_allowed\_oauth\_flows\_user\_pool\_client) | Whether the client is allowed to follow the OAuth protocol when interacting with Cognito user pools | `bool` | `true` | no | +| [client\_allowed\_oauth\_scopes](#input\_client\_allowed\_oauth\_scopes) | List of allowed OAuth scopes (phone, email, openid, profile, and aws.cognito.signin.user.admin) | `list(string)` | `[]` | no | +| [client\_auth\_session\_validity](#input\_client\_auth\_session\_validity) | Amazon Cognito creates a session token for each API request in an authentication flow. AuthSessionValidity is the duration, in minutes, of that session token. Your user pool native user must respond to each authentication challenge before the session expires. Valid values between 3 and 15. Default value is 3. | `number` | `3` | no | +| [client\_callback\_urls](#input\_client\_callback\_urls) | List of allowed callback URLs for the identity providers | `list(string)` | `[]` | no | +| [client\_default\_redirect\_uri](#input\_client\_default\_redirect\_uri) | The default redirect URI. Must be in the list of callback URLs | `string` | `""` | no | +| [client\_enable\_token\_revocation](#input\_client\_enable\_token\_revocation) | Whether the client token can be revoked | `bool` | `true` | no | +| [client\_explicit\_auth\_flows](#input\_client\_explicit\_auth\_flows) | List of authentication flows (ADMIN\_NO\_SRP\_AUTH, CUSTOM\_AUTH\_FLOW\_ONLY, USER\_PASSWORD\_AUTH) | `list(string)` | `[]` | no | +| [client\_generate\_secret](#input\_client\_generate\_secret) | Should an application secret be generated | `bool` | `true` | no | +| [client\_id\_token\_validity](#input\_client\_id\_token\_validity) | Time limit, between 5 minutes and 1 day, after which the ID token is no longer valid and cannot be used. Must be between 5 minutes and 1 day. Cannot be greater than refresh token expiration. This value will be overridden if you have entered a value in `token_validity_units`. | `number` | `60` | no | +| [client\_logout\_urls](#input\_client\_logout\_urls) | List of allowed logout URLs for the identity providers | `list(string)` | `[]` | no | +| [client\_name](#input\_client\_name) | The name of the application client | `string` | `null` | no | +| [client\_prevent\_user\_existence\_errors](#input\_client\_prevent\_user\_existence\_errors) | Choose which errors and responses are returned by Cognito APIs during authentication, account confirmation, and password recovery when the user does not exist in the user pool. When set to ENABLED and the user does not exist, authentication returns an error indicating either the username or password was incorrect, and account confirmation and password recovery return a response indicating a code was sent to a simulated destination. When set to LEGACY, those APIs will return a UserNotFoundException exception if the user does not exist in the user pool. | `string` | `null` | no | +| [client\_read\_attributes](#input\_client\_read\_attributes) | List of user pool attributes the application client can read from | `list(string)` | `[]` | no | +| [client\_refresh\_token\_validity](#input\_client\_refresh\_token\_validity) | The time limit in days refresh tokens are valid for. Must be between 60 minutes and 3650 days. This value will be overridden if you have entered a value in `token_validity_units` | `number` | `30` | no | +| [client\_supported\_identity\_providers](#input\_client\_supported\_identity\_providers) | List of provider names for the identity providers that are supported on this client | `list(string)` | `[]` | no | +| [client\_token\_validity\_units](#input\_client\_token\_validity\_units) | Configuration block for units in which the validity times are represented in. Valid values for the following arguments are: `seconds`, `minutes`, `hours` or `days`. | `any` |
{
"access_token": "minutes",
"id_token": "minutes",
"refresh_token": "days"
}
| no | +| [client\_write\_attributes](#input\_client\_write\_attributes) | List of user pool attributes the application client can write to | `list(string)` | `[]` | no | +| [clients](#input\_clients) | A container with the clients definitions | `any` | `[]` | no | +| [deletion\_protection](#input\_deletion\_protection) | When active, DeletionProtection prevents accidental deletion of your user pool. Before you can delete a user pool that you have protected against deletion, you must deactivate this feature. Valid values are `ACTIVE` and `INACTIVE`. | `string` | `"INACTIVE"` | no | +| [device\_configuration](#input\_device\_configuration) | The configuration for the user pool's device tracking | `map(any)` | `{}` | no | +| [device\_configuration\_challenge\_required\_on\_new\_device](#input\_device\_configuration\_challenge\_required\_on\_new\_device) | Indicates whether a challenge is required on a new device. Only applicable to a new device | `bool` | `false` | no | +| [device\_configuration\_device\_only\_remembered\_on\_user\_prompt](#input\_device\_configuration\_device\_only\_remembered\_on\_user\_prompt) | If true, a device is only remembered on user prompt | `bool` | `false` | no | +| [domain](#input\_domain) | Cognito User Pool domain | `string` | `null` | no | +| [domain\_certificate\_arn](#input\_domain\_certificate\_arn) | The ARN of an ISSUED ACM certificate in us-east-1 for a custom domain | `string` | `null` | no | +| [email\_configuration](#input\_email\_configuration) | The Email Configuration | `map(any)` | `{}` | no | +| [email\_configuration\_configuration\_set](#input\_email\_configuration\_configuration\_set) | The name of the configuration set | `string` | `null` | no | +| [email\_configuration\_email\_sending\_account](#input\_email\_configuration\_email\_sending\_account) | Instruct Cognito to either use its built-in functional or Amazon SES to send out emails. Allowed values: `COGNITO_DEFAULT` or `DEVELOPER` | `string` | `"COGNITO_DEFAULT"` | no | +| [email\_configuration\_from\_email\_address](#input\_email\_configuration\_from\_email\_address) | Sender’s email address or sender’s display name with their email address (e.g. `john@example.com`, `John Smith ` or `"John Smith Ph.D." )`. Escaped double quotes are required around display names that contain certain characters as specified in RFC 5322 | `string` | `null` | no | +| [email\_configuration\_reply\_to\_email\_address](#input\_email\_configuration\_reply\_to\_email\_address) | The REPLY-TO email address | `string` | `""` | no | +| [email\_configuration\_source\_arn](#input\_email\_configuration\_source\_arn) | The ARN of the email source | `string` | `""` | no | +| [email\_verification\_message](#input\_email\_verification\_message) | A string representing the email verification message | `string` | `null` | no | +| [email\_verification\_subject](#input\_email\_verification\_subject) | A string representing the email verification subject | `string` | `null` | no | +| [enabled](#input\_enabled) | Change to false to avoid deploying any resources | `bool` | `true` | no | +| [identity\_providers](#input\_identity\_providers) | Cognito Pool Identity Providers | `list(any)` | `[]` | no | +| [lambda\_config](#input\_lambda\_config) | A container for the AWS Lambda triggers associated with the user pool | `any` | `{}` | no | +| [lambda\_config\_create\_auth\_challenge](#input\_lambda\_config\_create\_auth\_challenge) | The ARN of the lambda creating an authentication challenge. | `string` | `null` | no | +| [lambda\_config\_custom\_email\_sender](#input\_lambda\_config\_custom\_email\_sender) | A custom email sender AWS Lambda trigger. | `any` | `{}` | no | +| [lambda\_config\_custom\_message](#input\_lambda\_config\_custom\_message) | A custom Message AWS Lambda trigger. | `string` | `null` | no | +| [lambda\_config\_custom\_sms\_sender](#input\_lambda\_config\_custom\_sms\_sender) | A custom SMS sender AWS Lambda trigger. | `any` | `{}` | no | +| [lambda\_config\_define\_auth\_challenge](#input\_lambda\_config\_define\_auth\_challenge) | Defines the authentication challenge. | `string` | `null` | no | +| [lambda\_config\_kms\_key\_id](#input\_lambda\_config\_kms\_key\_id) | The Amazon Resource Name of Key Management Service Customer master keys. Amazon Cognito uses the key to encrypt codes and temporary passwords sent to CustomEmailSender and CustomSMSSender. | `string` | `null` | no | +| [lambda\_config\_post\_authentication](#input\_lambda\_config\_post\_authentication) | A post-authentication AWS Lambda trigger | `string` | `null` | no | +| [lambda\_config\_post\_confirmation](#input\_lambda\_config\_post\_confirmation) | A post-confirmation AWS Lambda trigger | `string` | `null` | no | +| [lambda\_config\_pre\_authentication](#input\_lambda\_config\_pre\_authentication) | A pre-authentication AWS Lambda trigger | `string` | `null` | no | +| [lambda\_config\_pre\_sign\_up](#input\_lambda\_config\_pre\_sign\_up) | A pre-registration AWS Lambda trigger | `string` | `null` | no | +| [lambda\_config\_pre\_token\_generation](#input\_lambda\_config\_pre\_token\_generation) | Allow to customize identity token claims before token generation | `string` | `null` | no | +| [lambda\_config\_user\_migration](#input\_lambda\_config\_user\_migration) | The user migration Lambda config type | `string` | `null` | no | +| [lambda\_config\_verify\_auth\_challenge\_response](#input\_lambda\_config\_verify\_auth\_challenge\_response) | Verifies the authentication challenge response | `string` | `null` | no | +| [mfa\_configuration](#input\_mfa\_configuration) | Set to enable multi-factor authentication. Must be one of the following values (ON, OFF, OPTIONAL) | `string` | `"OFF"` | no | +| [number\_schemas](#input\_number\_schemas) | A container with the number schema attributes of a user pool. Maximum of 50 attributes | `list(any)` | `[]` | no | +| [password\_policy](#input\_password\_policy) | A container for information about the user pool password policy |
object({
minimum_length = number,
require_lowercase = bool,
require_numbers = bool,
require_symbols = bool,
require_uppercase = bool,
temporary_password_validity_days = number
})
| `null` | no | +| [password\_policy\_minimum\_length](#input\_password\_policy\_minimum\_length) | The minimum length of the password policy that you have set | `number` | `8` | no | +| [password\_policy\_require\_lowercase](#input\_password\_policy\_require\_lowercase) | Whether you have required users to use at least one lowercase letter in their password | `bool` | `true` | no | +| [password\_policy\_require\_numbers](#input\_password\_policy\_require\_numbers) | Whether you have required users to use at least one number in their password | `bool` | `true` | no | +| [password\_policy\_require\_symbols](#input\_password\_policy\_require\_symbols) | Whether you have required users to use at least one symbol in their password | `bool` | `true` | no | +| [password\_policy\_require\_uppercase](#input\_password\_policy\_require\_uppercase) | Whether you have required users to use at least one uppercase letter in their password | `bool` | `true` | no | +| [password\_policy\_temporary\_password\_validity\_days](#input\_password\_policy\_temporary\_password\_validity\_days) | The minimum length of the password policy that you have set | `number` | `7` | no | +| [recovery\_mechanisms](#input\_recovery\_mechanisms) | The list of Account Recovery Options | `list(any)` | `[]` | no | +| [resource\_server\_identifier](#input\_resource\_server\_identifier) | An identifier for the resource server | `string` | `null` | no | +| [resource\_server\_name](#input\_resource\_server\_name) | A name for the resource server | `string` | `null` | no | +| [resource\_server\_scope\_description](#input\_resource\_server\_scope\_description) | The scope description | `string` | `null` | no | +| [resource\_server\_scope\_name](#input\_resource\_server\_scope\_name) | The scope name | `string` | `null` | no | +| [resource\_servers](#input\_resource\_servers) | A container with the user\_groups definitions | `list(any)` | `[]` | no | +| [schemas](#input\_schemas) | A container with the schema attributes of a user pool. Maximum of 50 attributes | `list(any)` | `[]` | no | +| [sms\_authentication\_message](#input\_sms\_authentication\_message) | A string representing the SMS authentication message | `string` | `null` | no | +| [sms\_configuration](#input\_sms\_configuration) | The SMS Configuration | `map(any)` | `{}` | no | +| [sms\_configuration\_external\_id](#input\_sms\_configuration\_external\_id) | The external ID used in IAM role trust relationships | `string` | `""` | no | +| [sms\_configuration\_sns\_caller\_arn](#input\_sms\_configuration\_sns\_caller\_arn) | The ARN of the Amazon SNS caller. This is usually the IAM role that you've given Cognito permission to assume | `string` | `""` | no | +| [sms\_verification\_message](#input\_sms\_verification\_message) | A string representing the SMS verification message | `string` | `null` | no | +| [software\_token\_mfa\_configuration](#input\_software\_token\_mfa\_configuration) | Configuration block for software token MFA (multifactor-auth). mfa\_configuration must also be enabled for this to work | `map(any)` | `{}` | no | +| [software\_token\_mfa\_configuration\_enabled](#input\_software\_token\_mfa\_configuration\_enabled) | If true, and if mfa\_configuration is also enabled, multi-factor authentication by software TOTP generator will be enabled | `bool` | `false` | no | +| [string\_schemas](#input\_string\_schemas) | A container with the string schema attributes of a user pool. Maximum of 50 attributes | `list(any)` | `[]` | no | +| [tags](#input\_tags) | A mapping of tags to assign to the User Pool | `map(string)` | `{}` | no | +| [temporary\_password\_validity\_days](#input\_temporary\_password\_validity\_days) | The user account expiration limit, in days, after which the account is no longer usable | `number` | `7` | no | +| [user\_attribute\_update\_settings](#input\_user\_attribute\_update\_settings) | Configuration block for user attribute update settings. Must contain key `attributes_require_verification_before_update` with list with only valid values of `email` and `phone_number` | `map(list(string))` | `null` | no | +| [user\_group\_description](#input\_user\_group\_description) | The description of the user group | `string` | `null` | no | +| [user\_group\_name](#input\_user\_group\_name) | The name of the user group | `string` | `null` | no | +| [user\_group\_precedence](#input\_user\_group\_precedence) | The precedence of the user group | `number` | `null` | no | +| [user\_group\_role\_arn](#input\_user\_group\_role\_arn) | The ARN of the IAM role to be associated with the user group | `string` | `null` | no | +| [user\_groups](#input\_user\_groups) | A container with the user\_groups definitions | `list(any)` | `[]` | no | +| [user\_pool\_add\_ons](#input\_user\_pool\_add\_ons) | Configuration block for user pool add-ons to enable user pool advanced security mode features | `map(any)` | `{}` | no | +| [user\_pool\_add\_ons\_advanced\_security\_mode](#input\_user\_pool\_add\_ons\_advanced\_security\_mode) | The mode for advanced security, must be one of `OFF`, `AUDIT` or `ENFORCED` | `string` | `null` | no | +| [user\_pool\_name](#input\_user\_pool\_name) | The name of the user pool | `string` | n/a | yes | +| [username\_attributes](#input\_username\_attributes) | Specifies whether email addresses or phone numbers can be specified as usernames when a user signs up. Conflicts with `alias_attributes` | `list(string)` | `null` | no | +| [username\_configuration](#input\_username\_configuration) | The Username Configuration. Setting `case_sensitive` specifies whether username case sensitivity will be applied for all users in the user pool through Cognito APIs | `map(any)` | `{}` | no | +| [verification\_message\_template](#input\_verification\_message\_template) | The verification message templates configuration | `map(any)` | `{}` | no | +| [verification\_message\_template\_default\_email\_option](#input\_verification\_message\_template\_default\_email\_option) | The default email option. Must be either `CONFIRM_WITH_CODE` or `CONFIRM_WITH_LINK`. Defaults to `CONFIRM_WITH_CODE` | `string` | `null` | no | +| [verification\_message\_template\_email\_message\_by\_link](#input\_verification\_message\_template\_email\_message\_by\_link) | The email message template for sending a confirmation link to the user, it must contain the `{##Click Here##}` placeholder | `string` | `null` | no | +| [verification\_message\_template\_email\_subject\_by\_link](#input\_verification\_message\_template\_email\_subject\_by\_link) | The subject line for the email message template for sending a confirmation link to the user | `string` | `null` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [arn](#output\_arn) | The ARN of the user pool | +| [client\_ids](#output\_client\_ids) | The ids of the user pool clients | +| [client\_ids\_map](#output\_client\_ids\_map) | The ids map of the user pool clients | +| [client\_secrets](#output\_client\_secrets) | The client secrets of the user pool clients | +| [client\_secrets\_map](#output\_client\_secrets\_map) | The client secrets map of the user pool clients | +| [creation\_date](#output\_creation\_date) | The date the user pool was created | +| [domain\_app\_version](#output\_domain\_app\_version) | The app version | +| [domain\_aws\_account\_id](#output\_domain\_aws\_account\_id) | The AWS account ID for the user pool owner | +| [domain\_cloudfront\_distribution\_arn](#output\_domain\_cloudfront\_distribution\_arn) | The ARN of the CloudFront distribution | +| [domain\_s3\_bucket](#output\_domain\_s3\_bucket) | The S3 bucket where the static files for this domain are stored | +| [endpoint](#output\_endpoint) | The endpoint name of the user pool. Example format: cognito-idp.REGION.amazonaws.com/xxxx\_yyyyy | +| [id](#output\_id) | The id of the user pool | +| [last\_modified\_date](#output\_last\_modified\_date) | The date the user pool was last modified | +| [name](#output\_name) | The name of the user pool | +| [resource\_servers\_scope\_identifiers](#output\_resource\_servers\_scope\_identifiers) | A list of all scopes configured in the format identifier/scope\_name | + + +## Know issues +### Removing all lambda triggers +If you define lambda triggers using the `lambda_config` block or any `lambda_config_*` variable and you want to remove all triggers, define the lambda_config block with an empty map `{}` and apply the plan. Then comment the `lambda_config` block or define it as `null` and apply the plan again. + +This is needed because all parameters for the `lambda_config` block are optional and keeping all block attributes empty or null forces to create a `lambda_config {}` block very time a plan/apply is run. diff --git a/aws-cognito-user-pool/client.tf b/aws-cognito-user-pool/client.tf new file mode 100644 index 0000000..303867c --- /dev/null +++ b/aws-cognito-user-pool/client.tf @@ -0,0 +1,90 @@ +resource "aws_cognito_user_pool_client" "client" { + count = var.enabled ? length(local.clients) : 0 + allowed_oauth_flows = lookup(element(local.clients, count.index), "allowed_oauth_flows", null) + allowed_oauth_flows_user_pool_client = lookup(element(local.clients, count.index), "allowed_oauth_flows_user_pool_client", null) + allowed_oauth_scopes = lookup(element(local.clients, count.index), "allowed_oauth_scopes", null) + auth_session_validity = lookup(element(local.clients, count.index), "auth_session_validity", null) + callback_urls = lookup(element(local.clients, count.index), "callback_urls", null) + default_redirect_uri = lookup(element(local.clients, count.index), "default_redirect_uri", null) + explicit_auth_flows = lookup(element(local.clients, count.index), "explicit_auth_flows", null) + generate_secret = lookup(element(local.clients, count.index), "generate_secret", null) + logout_urls = lookup(element(local.clients, count.index), "logout_urls", null) + name = lookup(element(local.clients, count.index), "name", null) + read_attributes = lookup(element(local.clients, count.index), "read_attributes", null) + access_token_validity = lookup(element(local.clients, count.index), "access_token_validity", null) + id_token_validity = lookup(element(local.clients, count.index), "id_token_validity", null) + refresh_token_validity = lookup(element(local.clients, count.index), "refresh_token_validity", null) + supported_identity_providers = lookup(element(local.clients, count.index), "supported_identity_providers", null) + prevent_user_existence_errors = lookup(element(local.clients, count.index), "prevent_user_existence_errors", null) + write_attributes = lookup(element(local.clients, count.index), "write_attributes", null) + enable_token_revocation = lookup(element(local.clients, count.index), "enable_token_revocation", null) + user_pool_id = aws_cognito_user_pool.pool[0].id + + # token_validity_units + dynamic "token_validity_units" { + for_each = length(lookup(element(local.clients, count.index), "token_validity_units", {})) == 0 ? [] : [lookup(element(local.clients, count.index), "token_validity_units")] + content { + access_token = lookup(token_validity_units.value, "access_token", null) + id_token = lookup(token_validity_units.value, "id_token", null) + refresh_token = lookup(token_validity_units.value, "refresh_token", null) + } + } + + depends_on = [ + aws_cognito_resource_server.resource, + aws_cognito_identity_provider.identity_provider + ] +} + +locals { + clients_default = [ + { + allowed_oauth_flows = var.client_allowed_oauth_flows + allowed_oauth_flows_user_pool_client = var.client_allowed_oauth_flows_user_pool_client + allowed_oauth_scopes = var.client_allowed_oauth_scopes + auth_session_validity = var.client_auth_session_validity + callback_urls = var.client_callback_urls + default_redirect_uri = var.client_default_redirect_uri + explicit_auth_flows = var.client_explicit_auth_flows + generate_secret = var.client_generate_secret + logout_urls = var.client_logout_urls + name = var.client_name + read_attributes = var.client_read_attributes + access_token_validity = var.client_access_token_validity + id_token_validity = var.client_id_token_validity + token_validity_units = var.client_token_validity_units + refresh_token_validity = var.client_refresh_token_validity + supported_identity_providers = var.client_supported_identity_providers + prevent_user_existence_errors = var.client_prevent_user_existence_errors + write_attributes = var.client_write_attributes + enable_token_revocation = var.client_enable_token_revocation + } + ] + + # This parses vars.clients which is a list of objects (map), and transforms it to a tuple of elements to avoid conflict with the ternary and local.clients_default + clients_parsed = [for e in var.clients : { + allowed_oauth_flows = lookup(e, "allowed_oauth_flows", null) + allowed_oauth_flows_user_pool_client = lookup(e, "allowed_oauth_flows_user_pool_client", null) + allowed_oauth_scopes = lookup(e, "allowed_oauth_scopes", null) + auth_session_validity = lookup(e, "auth_session_validity", null) + callback_urls = lookup(e, "callback_urls", null) + default_redirect_uri = lookup(e, "default_redirect_uri", null) + explicit_auth_flows = lookup(e, "explicit_auth_flows", null) + generate_secret = lookup(e, "generate_secret", null) + logout_urls = lookup(e, "logout_urls", null) + name = lookup(e, "name", null) + read_attributes = lookup(e, "read_attributes", null) + access_token_validity = lookup(e, "access_token_validity", null) + id_token_validity = lookup(e, "id_token_validity", null) + refresh_token_validity = lookup(e, "refresh_token_validity", null) + token_validity_units = lookup(e, "token_validity_units", {}) + supported_identity_providers = lookup(e, "supported_identity_providers", null) + prevent_user_existence_errors = lookup(e, "prevent_user_existence_errors", null) + write_attributes = lookup(e, "write_attributes", null) + enable_token_revocation = lookup(e, "enable_token_revocation", null) + } + ] + + clients = length(var.clients) == 0 && (var.client_name == null || var.client_name == "") ? [] : (length(var.clients) > 0 ? local.clients_parsed : local.clients_default) + +} diff --git a/aws-cognito-user-pool/domain.tf b/aws-cognito-user-pool/domain.tf new file mode 100644 index 0000000..7872cf5 --- /dev/null +++ b/aws-cognito-user-pool/domain.tf @@ -0,0 +1,6 @@ +resource "aws_cognito_user_pool_domain" "domain" { + count = !var.enabled || var.domain == null || var.domain == "" ? 0 : 1 + domain = var.domain + certificate_arn = var.domain_certificate_arn + user_pool_id = aws_cognito_user_pool.pool[0].id +} diff --git a/aws-cognito-user-pool/examples/complete/README.md b/aws-cognito-user-pool/examples/complete/README.md new file mode 100644 index 0000000..c025085 --- /dev/null +++ b/aws-cognito-user-pool/examples/complete/README.md @@ -0,0 +1,264 @@ +# This is a complete example + +``` +module "aws_cognito_user_pool_complete_example" { + + source = "lgallard/cognito-user-pool/aws" + + user_pool_name = "mypool_complete" + alias_attributes = ["email", "phone_number"] + auto_verified_attributes = ["email"] + sms_authentication_message = "Your username is {username} and temporary password is {####}." + sms_verification_message = "This is the verification message {####}." + + deletion_protection = "ACTIVE" + + mfa_configuration = "OPTIONAL" + software_token_mfa_configuration = { + enabled = true + } + + admin_create_user_config = { + email_message = "Dear {username}, your verification code is {####}." + email_subject = "Here, your verification code baby" + sms_message = "Your username is {username} and temporary password is {####}." + } + + device_configuration = { + challenge_required_on_new_device = true + device_only_remembered_on_user_prompt = true + } + + email_configuration = { + email_sending_account = "DEVELOPER" + reply_to_email_address = "email@mydomain.com" + source_arn = "arn:aws:ses:us-east-1:123456789012:identity/myemail@mydomain.com" + } + + lambda_config = { + create_auth_challenge = "arn:aws:lambda:us-east-1:123456789012:function:create_auth_challenge" + custom_message = "arn:aws:lambda:us-east-1:123456789012:function:custom_message" + define_auth_challenge = "arn:aws:lambda:us-east-1:123456789012:function:define_auth_challenge" + post_authentication = "arn:aws:lambda:us-east-1:123456789012:function:post_authentication" + post_confirmation = "arn:aws:lambda:us-east-1:123456789012:function:post_confirmation" + pre_authentication = "arn:aws:lambda:us-east-1:123456789012:function:pre_authentication" + pre_sign_up = "arn:aws:lambda:us-east-1:123456789012:function:pre_sign_up" + pre_token_generation = "arn:aws:lambda:us-east-1:123456789012:function:pre_token_generation" + user_migration = "arn:aws:lambda:us-east-1:123456789012:function:user_migration" + verify_auth_challenge_response = "arn:aws:lambda:us-east-1:123456789012:function:verify_auth_challenge_response" + } + + password_policy = { + minimum_length = 10 + require_lowercase = false + require_numbers = true + require_symbols = true + require_uppercase = true + temporary_password_validity_days = 120 + + } + + user_pool_add_ons = { + advanced_security_mode = "ENFORCED" + } + + verification_message_template = { + default_email_option = "CONFIRM_WITH_CODE" + } + + schemas = [ + { + attribute_data_type = "Boolean" + developer_only_attribute = false + mutable = true + name = "available" + required = false + }, + { + attribute_data_type = "Boolean" + developer_only_attribute = true + mutable = true + name = "registered" + required = false + } + ] + + string_schemas = [ + { + attribute_data_type = "String" + developer_only_attribute = false + mutable = false + name = "email" + required = true + + string_attribute_constraints = { + min_length = 7 + max_length = 15 + } + }, + { + attribute_data_type = "String" + developer_only_attribute = false + mutable = false + name = "gender" + required = true + + string_attribute_constraints = { + min_length = 7 + max_length = 15 + } + }, + ] + + number_schemas = [ + { + attribute_data_type = "Number" + developer_only_attribute = true + mutable = true + name = "mynumber1" + required = false + + number_attribute_constraints = { + min_value = 2 + max_value = 6 + } + }, + { + attribute_data_type = "Number" + developer_only_attribute = true + mutable = true + name = "mynumber2" + required = false + + number_attribute_constraints = { + min_value = 2 + max_value = 6 + } + }, + ] + + # user_pool_domain + domain = "mydomain-com" + + # clients + clients = [ + { + allowed_oauth_flows = [] + allowed_oauth_flows_user_pool_client = false + allowed_oauth_scopes = [] + callback_urls = ["https://mydomain.com/callback"] + default_redirect_uri = "https://mydomain.com/callback" + explicit_auth_flows = [] + generate_secret = true + logout_urls = [] + name = "test1" + read_attributes = ["email"] + supported_identity_providers = [] + write_attributes = [] + access_token_validity = 1 + id_token_validity = 1 + refresh_token_validity = 60 + token_validity_units = { + access_token = "hours" + id_token = "hours" + refresh_token = "days" + } + }, + { + allowed_oauth_flows = [] + allowed_oauth_flows_user_pool_client = false + allowed_oauth_scopes = [] + callback_urls = ["https://mydomain.com/callback"] + default_redirect_uri = "https://mydomain.com/callback" + explicit_auth_flows = [] + generate_secret = false + logout_urls = [] + name = "test2" + read_attributes = [] + supported_identity_providers = [] + write_attributes = [] + refresh_token_validity = 30 + }, + { + allowed_oauth_flows = ["code", "implicit"] + allowed_oauth_flows_user_pool_client = true + allowed_oauth_scopes = ["email", "openid"] + callback_urls = ["https://mydomain.com/callback"] + default_redirect_uri = "https://mydomain.com/callback" + explicit_auth_flows = ["CUSTOM_AUTH_FLOW_ONLY", "ADMIN_NO_SRP_AUTH"] + generate_secret = false + logout_urls = ["https://mydomain.com/logout"] + name = "test3" + read_attributes = ["email", "phone_number"] + supported_identity_providers = [] + write_attributes = ["email", "gender", "locale", ] + refresh_token_validity = 30 + } + ] + + # user_group + user_groups = [ + { name = "mygroup1" + description = "My group 1" + }, + { name = "mygroup2" + description = "My group 2" + }, + ] + + # resource_servers + resource_servers = [ + { + identifier = "https://mydomain.com" + name = "mydomain" + scope = [ + { + scope_name = "sample-scope-1" + scope_description = "A sample Scope Description for mydomain.com" + }, + { + scope_name = "sample-scope-2" + scope_description = "Another sample Scope Description for mydomain.com" + }, + ] + }, + { + identifier = "https://weather-read-app.com" + name = "weather-read" + scope = [ + { + scope_name = "weather.read" + scope_description = "Read weather forecasts" + } + ] + } + ] + + # identity_providers + identity_providers = [ + { + provider_name = "Google" + provider_type = "Google" + + provider_details = { + authorize_scopes = "email" + client_id = "your client_id" + client_secret = "your client_secret" + } + + attribute_mapping = { + email = "email" + username = "sub" + gender = "gender" + } + } + ] + + # tags + tags = { + Owner = "infra" + Environment = "production" + Terraform = true + } +} +``` diff --git a/aws-cognito-user-pool/examples/complete/main.tf b/aws-cognito-user-pool/examples/complete/main.tf new file mode 100644 index 0000000..f4e4270 --- /dev/null +++ b/aws-cognito-user-pool/examples/complete/main.tf @@ -0,0 +1,280 @@ +module "aws_cognito_user_pool_complete_example" { + + source = "lgallard/cognito-user-pool/aws" + + user_pool_name = "mypool_complete" + alias_attributes = ["email", "phone_number"] + auto_verified_attributes = ["email"] + sms_authentication_message = "Your username is {username} and temporary password is {####}." + sms_verification_message = "This is the verification message {####}." + + deletion_protection = "ACTIVE" + + mfa_configuration = "OPTIONAL" + software_token_mfa_configuration = { + enabled = true + } + + admin_create_user_config = { + email_message = "Dear {username}, your verification code is {####}." + email_subject = "Here, your verification code baby" + sms_message = "Your username is {username} and temporary password is {####}." + } + + device_configuration = { + challenge_required_on_new_device = true + device_only_remembered_on_user_prompt = true + } + + email_configuration = { + email_sending_account = "DEVELOPER" + reply_to_email_address = "email@mydomain.com" + source_arn = "arn:aws:ses:us-east-1:123456789012:identity/myemail@mydomain.com" + } + + lambda_config = { + create_auth_challenge = "arn:aws:lambda:us-east-1:123456789012:function:create_auth_challenge" + custom_message = "arn:aws:lambda:us-east-1:123456789012:function:custom_message" + define_auth_challenge = "arn:aws:lambda:us-east-1:123456789012:function:define_auth_challenge" + post_authentication = "arn:aws:lambda:us-east-1:123456789012:function:post_authentication" + post_confirmation = "arn:aws:lambda:us-east-1:123456789012:function:post_confirmation" + pre_authentication = "arn:aws:lambda:us-east-1:123456789012:function:pre_authentication" + pre_sign_up = "arn:aws:lambda:us-east-1:123456789012:function:pre_sign_up" + pre_token_generation = "arn:aws:lambda:us-east-1:123456789012:function:pre_token_generation" + user_migration = "arn:aws:lambda:us-east-1:123456789012:function:user_migration" + verify_auth_challenge_response = "arn:aws:lambda:us-east-1:123456789012:function:verify_auth_challenge_response" + kms_key_id = aws_kms_key.lambda-custom-sender.arn + custom_email_sender = { + lambda_arn = "arn:aws:lambda:us-east-1:123456789012:function:custom_email_sender" + lambda_version = "V1_0" + } + custom_sms_sender = { + lambda_arn = "arn:aws:lambda:us-east-1:123456789012:function:custom_sms_sender" + lambda_version = "V1_0" + } + } + + password_policy = { + minimum_length = 10 + require_lowercase = false + require_numbers = true + require_symbols = true + require_uppercase = true + temporary_password_validity_days = 120 + + } + + user_pool_add_ons = { + advanced_security_mode = "ENFORCED" + } + + verification_message_template = { + default_email_option = "CONFIRM_WITH_CODE" + } + + schemas = [ + { + attribute_data_type = "Boolean" + developer_only_attribute = false + mutable = true + name = "available" + required = false + }, + { + attribute_data_type = "Boolean" + developer_only_attribute = true + mutable = true + name = "registered" + required = false + } + ] + + string_schemas = [ + { + attribute_data_type = "String" + developer_only_attribute = false + mutable = false + name = "email" + required = true + + string_attribute_constraints = { + min_length = 7 + max_length = 15 + } + }, + { + attribute_data_type = "String" + developer_only_attribute = false + mutable = false + name = "gender" + required = true + + string_attribute_constraints = { + min_length = 7 + max_length = 15 + } + }, + ] + + number_schemas = [ + { + attribute_data_type = "Number" + developer_only_attribute = true + mutable = true + name = "mynumber1" + required = false + + number_attribute_constraints = { + min_value = 2 + max_value = 6 + } + }, + { + attribute_data_type = "Number" + developer_only_attribute = true + mutable = true + name = "mynumber2" + required = false + + number_attribute_constraints = { + min_value = 2 + max_value = 6 + } + }, + ] + + # user_pool_domain + domain = "mydomain-com" + + # clients + clients = [ + { + allowed_oauth_flows = [] + allowed_oauth_flows_user_pool_client = false + allowed_oauth_scopes = [] + callback_urls = ["https://mydomain.com/callback"] + default_redirect_uri = "https://mydomain.com/callback" + explicit_auth_flows = [] + generate_secret = true + logout_urls = [] + name = "test1" + read_attributes = ["email"] + supported_identity_providers = [] + write_attributes = [] + access_token_validity = 1 + id_token_validity = 1 + refresh_token_validity = 60 + token_validity_units = { + access_token = "hours" + id_token = "hours" + refresh_token = "days" + } + }, + { + allowed_oauth_flows = [] + allowed_oauth_flows_user_pool_client = false + allowed_oauth_scopes = [] + callback_urls = ["https://mydomain.com/callback"] + default_redirect_uri = "https://mydomain.com/callback" + explicit_auth_flows = [] + generate_secret = false + logout_urls = [] + name = "test2" + read_attributes = [] + supported_identity_providers = [] + write_attributes = [] + refresh_token_validity = 30 + }, + { + allowed_oauth_flows = ["code", "implicit"] + allowed_oauth_flows_user_pool_client = true + allowed_oauth_scopes = ["email", "openid"] + callback_urls = ["https://mydomain.com/callback"] + default_redirect_uri = "https://mydomain.com/callback" + explicit_auth_flows = ["CUSTOM_AUTH_FLOW_ONLY", "ADMIN_NO_SRP_AUTH"] + generate_secret = false + logout_urls = ["https://mydomain.com/logout"] + name = "test3" + read_attributes = ["email", "phone_number"] + supported_identity_providers = [] + write_attributes = ["email", "gender", "locale", ] + refresh_token_validity = 30 + } + ] + + # user_group + user_groups = [ + { name = "mygroup1" + description = "My group 1" + }, + { name = "mygroup2" + description = "My group 2" + }, + ] + + # resource_servers + resource_servers = [ + { + identifier = "https://mydomain.com" + name = "mydomain" + scope = [ + { + scope_name = "sample-scope-1" + scope_description = "A sample Scope Description for mydomain.com" + }, + { + scope_name = "sample-scope-2" + scope_description = "Another sample Scope Description for mydomain.com" + }, + ] + }, + { + identifier = "https://weather-read-app.com" + name = "weather-read" + scope = [ + { + scope_name = "weather.read" + scope_description = "Read weather forecasts" + } + ] + } + ] + + # identity_providers + identity_providers = [ + { + provider_name = "Google" + provider_type = "Google" + + provider_details = { + authorize_scopes = "email" + client_id = "your client_id" + client_secret = "your client_secret" + attributes_url_add_attributes = "true" + authorize_url = "https://accounts.google.com/o/oauth2/v2/auth" + oidc_issuer = "https://accounts.google.com" + token_request_method = "POST" + token_url = "https://www.googleapis.com/oauth2/v4/token" + } + + attribute_mapping = { + email = "email" + username = "sub" + gender = "gender" + } + } + ] + + # tags + tags = { + Owner = "infra" + Environment = "production" + Terraform = true + } +} + + +# KMS key for lambda custom sender config" +resource "aws_kms_key" "lambda-custom-sender" { + description = "KMS key for lambda custom sender config" +} diff --git a/aws-cognito-user-pool/examples/complete/provider.tf b/aws-cognito-user-pool/examples/complete/provider.tf new file mode 100644 index 0000000..634c762 --- /dev/null +++ b/aws-cognito-user-pool/examples/complete/provider.tf @@ -0,0 +1,4 @@ +provider "aws" { + region = var.env["region"] + profile = var.env["profile"] +} diff --git a/aws-cognito-user-pool/examples/complete/variables.tf b/aws-cognito-user-pool/examples/complete/variables.tf new file mode 100644 index 0000000..c7b7aed --- /dev/null +++ b/aws-cognito-user-pool/examples/complete/variables.tf @@ -0,0 +1,4 @@ +variable "env" { + type = map(any) + default = {} +} diff --git a/aws-cognito-user-pool/examples/simple/README.md b/aws-cognito-user-pool/examples/simple/README.md new file mode 100644 index 0000000..b70971f --- /dev/null +++ b/aws-cognito-user-pool/examples/simple/README.md @@ -0,0 +1,17 @@ +# The simple example + +``` +module "aws_cognito_user_pool_simple_example" { + + source = "../modules/terraform-aws-cognito-user-pool" + + user_pool_name = "simple_pool" + + # tags + tags = { + Owner = "infra" + Environment = "production" + Terraform = true + } +} +``` diff --git a/aws-cognito-user-pool/examples/simple/main.tf b/aws-cognito-user-pool/examples/simple/main.tf new file mode 100644 index 0000000..1600e81 --- /dev/null +++ b/aws-cognito-user-pool/examples/simple/main.tf @@ -0,0 +1,13 @@ +module "aws_cognito_user_pool_simple_example" { + + source = "lgallard/cognito-user-pool/aws" + + user_pool_name = "simple_pool" + + # tags + tags = { + Owner = "infra" + Environment = "production" + Terraform = true + } +} diff --git a/aws-cognito-user-pool/examples/simple/provider.tf b/aws-cognito-user-pool/examples/simple/provider.tf new file mode 100644 index 0000000..634c762 --- /dev/null +++ b/aws-cognito-user-pool/examples/simple/provider.tf @@ -0,0 +1,4 @@ +provider "aws" { + region = var.env["region"] + profile = var.env["profile"] +} diff --git a/aws-cognito-user-pool/examples/simple/variables.tf b/aws-cognito-user-pool/examples/simple/variables.tf new file mode 100644 index 0000000..c7b7aed --- /dev/null +++ b/aws-cognito-user-pool/examples/simple/variables.tf @@ -0,0 +1,4 @@ +variable "env" { + type = map(any) + default = {} +} diff --git a/aws-cognito-user-pool/examples/simple_extended/README.md b/aws-cognito-user-pool/examples/simple_extended/README.md new file mode 100644 index 0000000..34e2987 --- /dev/null +++ b/aws-cognito-user-pool/examples/simple_extended/README.md @@ -0,0 +1,73 @@ +# This is the simple example, but extended +``` +module "aws_cognito_user_pool_simple_extended_example" { + + source = "../modules/terraform-aws-cognito-user-pool" + + user_pool_name = "simple_extended_pool" + alias_attributes = ["email", "phone_number"] + auto_verified_attributes = ["email"] + sms_authentication_message = "Your username is {username} and temporary password is {####}." + sms_verification_message = "This is the verification message {####}." + lambda_config_verify_auth_challenge_response = "arn:aws:lambda:us-east-1:123456789012:function:my_lambda_function" + password_policy_require_lowercase = false + password_policy_minimum_length = 11 + user_pool_add_ons_advanced_security_mode = "OFF" + verification_message_template_default_email_option = "CONFIRM_WITH_CODE" + + # schemas + schemas = [ + { + attribute_data_type = "Boolean" + developer_only_attribute = false + mutable = true + name = "available" + required = false + }, + ] + + string_schemas = [ + { + attribute_data_type = "String" + developer_only_attribute = false + mutable = false + name = "email" + required = true + + string_attribute_constraints = { + min_length = 7 + max_length = 15 + } + }, + ] + + # user_pool_domain + domain = "mydomain-com" + + # client + client_name = "client0" + client_allowed_oauth_flows_user_pool_client = false + client_callback_urls = ["https://mydomain.com/callback"] + client_default_redirect_uri = "https://mydomain.com/callback" + client_read_attributes = ["email"] + client_refresh_token_validity = 30 + + + # user_group + user_group_name = "mygroup" + user_group_description = "My group" + + # ressource server + resource_server_identifier = "https://mydomain.com" + resource_server_name = "mydomain" + resource_server_scope_name = "scope" + resource_server_scope_description = "a Sample Scope Description for mydomain" + + # tags + tags = { + Owner = "infra" + Environment = "production" + Terraform = true + } +} +``` diff --git a/aws-cognito-user-pool/examples/simple_extended/main.tf b/aws-cognito-user-pool/examples/simple_extended/main.tf new file mode 100644 index 0000000..c0ce344 --- /dev/null +++ b/aws-cognito-user-pool/examples/simple_extended/main.tf @@ -0,0 +1,70 @@ +module "aws_cognito_user_pool_simple_extended_example" { + + source = "lgallard/cognito-user-pool/aws" + + user_pool_name = "simple_extended_pool" + alias_attributes = ["email", "phone_number"] + auto_verified_attributes = ["email"] + sms_authentication_message = "Your username is {username} and temporary password is {####}." + sms_verification_message = "This is the verification message {####}." + lambda_config_verify_auth_challenge_response = "arn:aws:lambda:us-east-1:123456789012:function:my_lambda_function" + password_policy_require_lowercase = false + password_policy_minimum_length = 11 + user_pool_add_ons_advanced_security_mode = "OFF" + verification_message_template_default_email_option = "CONFIRM_WITH_CODE" + + # schemas + schemas = [ + { + attribute_data_type = "Boolean" + developer_only_attribute = false + mutable = true + name = "available" + required = false + }, + ] + + string_schemas = [ + { + attribute_data_type = "String" + developer_only_attribute = false + mutable = false + name = "email" + required = true + + string_attribute_constraints = { + min_length = 7 + max_length = 15 + } + }, + ] + + # user_pool_domain + domain = "mydomain-com" + + # client + client_name = "client0" + client_allowed_oauth_flows_user_pool_client = false + client_callback_urls = ["https://mydomain.com/callback"] + client_default_redirect_uri = "https://mydomain.com/callback" + client_read_attributes = ["email"] + client_refresh_token_validity = 30 + + + # user_group + user_group_name = "mygroup" + user_group_description = "My group" + + # ressource server + resource_server_identifier = "https://mydomain.com" + resource_server_name = "mydomain" + resource_server_scope_name = "scope" + resource_server_scope_description = "a Sample Scope Description for mydomain" + + # tags + tags = { + Owner = "infra" + Environment = "production" + Terraform = true + } +} diff --git a/aws-cognito-user-pool/examples/simple_extended/provider.tf b/aws-cognito-user-pool/examples/simple_extended/provider.tf new file mode 100644 index 0000000..634c762 --- /dev/null +++ b/aws-cognito-user-pool/examples/simple_extended/provider.tf @@ -0,0 +1,4 @@ +provider "aws" { + region = var.env["region"] + profile = var.env["profile"] +} diff --git a/aws-cognito-user-pool/examples/simple_extended/variables.tf b/aws-cognito-user-pool/examples/simple_extended/variables.tf new file mode 100644 index 0000000..c7b7aed --- /dev/null +++ b/aws-cognito-user-pool/examples/simple_extended/variables.tf @@ -0,0 +1,4 @@ +variable "env" { + type = map(any) + default = {} +} diff --git a/aws-cognito-user-pool/identity-provider.tf b/aws-cognito-user-pool/identity-provider.tf new file mode 100644 index 0000000..5c00861 --- /dev/null +++ b/aws-cognito-user-pool/identity-provider.tf @@ -0,0 +1,11 @@ +resource "aws_cognito_identity_provider" "identity_provider" { + count = var.enabled ? length(var.identity_providers) : 0 + user_pool_id = aws_cognito_user_pool.pool[0].id + provider_name = lookup(element(var.identity_providers, count.index), "provider_name") + provider_type = lookup(element(var.identity_providers, count.index), "provider_type") + + # Optional arguments + attribute_mapping = lookup(element(var.identity_providers, count.index), "attribute_mapping", {}) + idp_identifiers = lookup(element(var.identity_providers, count.index), "idp_identifiers", []) + provider_details = lookup(element(var.identity_providers, count.index), "provider_details", {}) +} diff --git a/aws-cognito-user-pool/main.tf b/aws-cognito-user-pool/main.tf new file mode 100644 index 0000000..a7466db --- /dev/null +++ b/aws-cognito-user-pool/main.tf @@ -0,0 +1,325 @@ +resource "aws_cognito_user_pool" "pool" { + count = var.enabled ? 1 : 0 + + alias_attributes = var.alias_attributes + auto_verified_attributes = var.auto_verified_attributes + name = var.user_pool_name + email_verification_subject = var.email_verification_subject == "" || var.email_verification_subject == null ? var.admin_create_user_config_email_subject : var.email_verification_subject + email_verification_message = var.email_verification_message == "" || var.email_verification_message == null ? var.admin_create_user_config_email_message : var.email_verification_message + mfa_configuration = var.mfa_configuration + sms_authentication_message = var.sms_authentication_message + sms_verification_message = var.sms_verification_message + username_attributes = var.username_attributes + deletion_protection = var.deletion_protection + + # username_configuration + dynamic "username_configuration" { + for_each = local.username_configuration + content { + case_sensitive = lookup(username_configuration.value, "case_sensitive") + } + } + + # admin_create_user_config + dynamic "admin_create_user_config" { + for_each = local.admin_create_user_config + content { + allow_admin_create_user_only = lookup(admin_create_user_config.value, "allow_admin_create_user_only") + + dynamic "invite_message_template" { + for_each = lookup(admin_create_user_config.value, "email_message", null) == null && lookup(admin_create_user_config.value, "email_subject", null) == null && lookup(admin_create_user_config.value, "sms_message", null) == null ? [] : [1] + content { + email_message = lookup(admin_create_user_config.value, "email_message") + email_subject = lookup(admin_create_user_config.value, "email_subject") + sms_message = lookup(admin_create_user_config.value, "sms_message") + } + } + } + } + + # device_configuration + dynamic "device_configuration" { + for_each = local.device_configuration + content { + challenge_required_on_new_device = lookup(device_configuration.value, "challenge_required_on_new_device") + device_only_remembered_on_user_prompt = lookup(device_configuration.value, "device_only_remembered_on_user_prompt") + } + } + + # email_configuration + dynamic "email_configuration" { + for_each = local.email_configuration + content { + configuration_set = lookup(email_configuration.value, "configuration_set") + reply_to_email_address = lookup(email_configuration.value, "reply_to_email_address") + source_arn = lookup(email_configuration.value, "source_arn") + email_sending_account = lookup(email_configuration.value, "email_sending_account") + from_email_address = lookup(email_configuration.value, "from_email_address") + } + } + + # lambda_config + dynamic "lambda_config" { + for_each = var.lambda_config == null || length(var.lambda_config) == 0 ? [] : [1] + content { + create_auth_challenge = lookup(var.lambda_config, "create_auth_challenge", var.lambda_config_create_auth_challenge) + custom_message = lookup(var.lambda_config, "custom_message", var.lambda_config_custom_message) + define_auth_challenge = lookup(var.lambda_config, "define_auth_challenge", var.lambda_config_define_auth_challenge) + post_authentication = lookup(var.lambda_config, "post_authentication", var.lambda_config_post_authentication) + post_confirmation = lookup(var.lambda_config, "post_confirmation", var.lambda_config_post_confirmation) + pre_authentication = lookup(var.lambda_config, "pre_authentication", var.lambda_config_pre_authentication) + pre_sign_up = lookup(var.lambda_config, "pre_sign_up", var.lambda_config_pre_sign_up) + pre_token_generation = lookup(var.lambda_config, "pre_token_generation", var.lambda_config_pre_token_generation) + user_migration = lookup(var.lambda_config, "user_migration", var.lambda_config_user_migration) + verify_auth_challenge_response = lookup(var.lambda_config, "verify_auth_challenge_response", var.lambda_config_verify_auth_challenge_response) + kms_key_id = lookup(var.lambda_config, "kms_key_id", var.lambda_config_kms_key_id) + dynamic "custom_email_sender" { + for_each = lookup(var.lambda_config, "custom_email_sender", var.lambda_config_custom_email_sender) == {} ? [] : [1] + content { + lambda_arn = lookup(lookup(var.lambda_config, "custom_email_sender", var.lambda_config_custom_email_sender), "lambda_arn", null) + lambda_version = lookup(lookup(var.lambda_config, "custom_email_sender", var.lambda_config_custom_email_sender), "lambda_version", null) + } + } + dynamic "custom_sms_sender" { + for_each = lookup(var.lambda_config, "custom_sms_sender", var.lambda_config_custom_sms_sender) == {} ? [] : [1] + content { + lambda_arn = lookup(lookup(var.lambda_config, "custom_sms_sender", var.lambda_config_custom_sms_sender), "lambda_arn", null) + lambda_version = lookup(lookup(var.lambda_config, "custom_sms_sender", var.lambda_config_custom_sms_sender), "lambda_version", null) + } + } + } + } + + # sms_configuration + dynamic "sms_configuration" { + for_each = local.sms_configuration + content { + external_id = lookup(sms_configuration.value, "external_id") + sns_caller_arn = lookup(sms_configuration.value, "sns_caller_arn") + } + } + + # software_token_mfa_configuration + dynamic "software_token_mfa_configuration" { + for_each = local.software_token_mfa_configuration + content { + enabled = lookup(software_token_mfa_configuration.value, "enabled") + } + } + + # password_policy + dynamic "password_policy" { + for_each = local.password_policy + content { + minimum_length = lookup(password_policy.value, "minimum_length") + require_lowercase = lookup(password_policy.value, "require_lowercase") + require_numbers = lookup(password_policy.value, "require_numbers") + require_symbols = lookup(password_policy.value, "require_symbols") + require_uppercase = lookup(password_policy.value, "require_uppercase") + temporary_password_validity_days = lookup(password_policy.value, "temporary_password_validity_days") + } + } + + # schema + dynamic "schema" { + for_each = var.schemas == null ? [] : var.schemas + content { + attribute_data_type = lookup(schema.value, "attribute_data_type") + developer_only_attribute = lookup(schema.value, "developer_only_attribute") + mutable = lookup(schema.value, "mutable") + name = lookup(schema.value, "name") + required = lookup(schema.value, "required") + } + } + + # schema (String) + dynamic "schema" { + for_each = var.string_schemas == null ? [] : var.string_schemas + content { + attribute_data_type = lookup(schema.value, "attribute_data_type") + developer_only_attribute = lookup(schema.value, "developer_only_attribute") + mutable = lookup(schema.value, "mutable") + name = lookup(schema.value, "name") + required = lookup(schema.value, "required") + + # string_attribute_constraints + dynamic "string_attribute_constraints" { + for_each = length(keys(lookup(schema.value, "string_attribute_constraints", {}))) == 0 ? [{}] : [lookup(schema.value, "string_attribute_constraints", {})] + content { + min_length = lookup(string_attribute_constraints.value, "min_length", null) + max_length = lookup(string_attribute_constraints.value, "max_length", null) + } + } + } + } + + # schema (Number) + dynamic "schema" { + for_each = var.number_schemas == null ? [] : var.number_schemas + content { + attribute_data_type = lookup(schema.value, "attribute_data_type") + developer_only_attribute = lookup(schema.value, "developer_only_attribute") + mutable = lookup(schema.value, "mutable") + name = lookup(schema.value, "name") + required = lookup(schema.value, "required") + + # number_attribute_constraints + dynamic "number_attribute_constraints" { + for_each = length(keys(lookup(schema.value, "number_attribute_constraints", {}))) == 0 ? [{}] : [lookup(schema.value, "number_attribute_constraints", {})] + content { + min_value = lookup(number_attribute_constraints.value, "min_value", null) + max_value = lookup(number_attribute_constraints.value, "max_value", null) + } + } + } + } + + # user_pool_add_ons + dynamic "user_pool_add_ons" { + for_each = local.user_pool_add_ons + content { + advanced_security_mode = lookup(user_pool_add_ons.value, "advanced_security_mode") + } + } + + # verification_message_template + dynamic "verification_message_template" { + for_each = local.verification_message_template + content { + default_email_option = lookup(verification_message_template.value, "default_email_option") + email_message_by_link = lookup(verification_message_template.value, "email_message_by_link") + email_subject_by_link = lookup(verification_message_template.value, "email_subject_by_link") + } + } + + dynamic "user_attribute_update_settings" { + for_each = local.user_attribute_update_settings + content { + attributes_require_verification_before_update = lookup(user_attribute_update_settings.value, "attributes_require_verification_before_update") + } + } + + # account_recovery_setting + dynamic "account_recovery_setting" { + for_each = length(var.recovery_mechanisms) == 0 ? [] : [1] + content { + # recovery_mechanism + dynamic "recovery_mechanism" { + for_each = var.recovery_mechanisms + content { + name = lookup(recovery_mechanism.value, "name") + priority = lookup(recovery_mechanism.value, "priority") + } + } + } + } + + # tags + tags = var.tags +} + +locals { + # username_configuration + # If no username_configuration is provided return a empty list + username_configuration_default = length(var.username_configuration) == 0 ? {} : { + case_sensitive = lookup(var.username_configuration, "case_sensitive", true) + } + username_configuration = length(local.username_configuration_default) == 0 ? [] : [local.username_configuration_default] + + # admin_create_user_config + # If no admin_create_user_config list is provided, build a admin_create_user_config using the default values + admin_create_user_config_default = { + allow_admin_create_user_only = lookup(var.admin_create_user_config, "allow_admin_create_user_only", null) == null ? var.admin_create_user_config_allow_admin_create_user_only : lookup(var.admin_create_user_config, "allow_admin_create_user_only") + email_message = lookup(var.admin_create_user_config, "email_message", null) == null ? (var.email_verification_message == "" || var.email_verification_message == null ? var.admin_create_user_config_email_message : var.email_verification_message) : lookup(var.admin_create_user_config, "email_message") + email_subject = lookup(var.admin_create_user_config, "email_subject", null) == null ? (var.email_verification_subject == "" || var.email_verification_subject == null ? var.admin_create_user_config_email_subject : var.email_verification_subject) : lookup(var.admin_create_user_config, "email_subject") + sms_message = lookup(var.admin_create_user_config, "sms_message", null) == null ? var.admin_create_user_config_sms_message : lookup(var.admin_create_user_config, "sms_message") + + } + + admin_create_user_config = [local.admin_create_user_config_default] + + # sms_configuration + # If no sms_configuration list is provided, build a sms_configuration using the default values + sms_configuration_default = { + external_id = lookup(var.sms_configuration, "external_id", null) == null ? var.sms_configuration_external_id : lookup(var.sms_configuration, "external_id") + sns_caller_arn = lookup(var.sms_configuration, "sns_caller_arn", null) == null ? var.sms_configuration_sns_caller_arn : lookup(var.sms_configuration, "sns_caller_arn") + } + + sms_configuration = lookup(local.sms_configuration_default, "external_id") == "" || lookup(local.sms_configuration_default, "sns_caller_arn") == "" ? [] : [local.sms_configuration_default] + + # device_configuration + # If no device_configuration list is provided, build a device_configuration using the default values + device_configuration_default = { + challenge_required_on_new_device = lookup(var.device_configuration, "challenge_required_on_new_device", null) == null ? var.device_configuration_challenge_required_on_new_device : lookup(var.device_configuration, "challenge_required_on_new_device") + device_only_remembered_on_user_prompt = lookup(var.device_configuration, "device_only_remembered_on_user_prompt", null) == null ? var.device_configuration_device_only_remembered_on_user_prompt : lookup(var.device_configuration, "device_only_remembered_on_user_prompt") + } + + device_configuration = lookup(local.device_configuration_default, "challenge_required_on_new_device") == false && lookup(local.device_configuration_default, "device_only_remembered_on_user_prompt") == false ? [] : [local.device_configuration_default] + + # email_configuration + # If no email_configuration is provided, build a email_configuration using the default values + email_configuration_default = { + configuration_set = lookup(var.email_configuration, "configuration_set", null) == null ? var.email_configuration_configuration_set : lookup(var.email_configuration, "configuration_set") + reply_to_email_address = lookup(var.email_configuration, "reply_to_email_address", null) == null ? var.email_configuration_reply_to_email_address : lookup(var.email_configuration, "reply_to_email_address") + source_arn = lookup(var.email_configuration, "source_arn", null) == null ? var.email_configuration_source_arn : lookup(var.email_configuration, "source_arn") + email_sending_account = lookup(var.email_configuration, "email_sending_account", null) == null ? var.email_configuration_email_sending_account : lookup(var.email_configuration, "email_sending_account") + from_email_address = lookup(var.email_configuration, "from_email_address", null) == null ? var.email_configuration_from_email_address : lookup(var.email_configuration, "from_email_address") + } + + email_configuration = [local.email_configuration_default] + + # password_policy + # If no password_policy is provided, build a password_policy using the default values + # If lambda_config is null + password_policy_is_null = { + minimum_length = var.password_policy_minimum_length + require_lowercase = var.password_policy_require_lowercase + require_numbers = var.password_policy_require_numbers + require_symbols = var.password_policy_require_symbols + require_uppercase = var.password_policy_require_uppercase + temporary_password_validity_days = var.password_policy_temporary_password_validity_days + } + + password_policy_not_null = var.password_policy == null ? local.password_policy_is_null : { + minimum_length = lookup(var.password_policy, "minimum_length", null) == null ? var.password_policy_minimum_length : lookup(var.password_policy, "minimum_length") + require_lowercase = lookup(var.password_policy, "require_lowercase", null) == null ? var.password_policy_require_lowercase : lookup(var.password_policy, "require_lowercase") + require_numbers = lookup(var.password_policy, "require_numbers", null) == null ? var.password_policy_require_numbers : lookup(var.password_policy, "require_numbers") + require_symbols = lookup(var.password_policy, "require_symbols", null) == null ? var.password_policy_require_symbols : lookup(var.password_policy, "require_symbols") + require_uppercase = lookup(var.password_policy, "require_uppercase", null) == null ? var.password_policy_require_uppercase : lookup(var.password_policy, "require_uppercase") + temporary_password_validity_days = lookup(var.password_policy, "temporary_password_validity_days", null) == null ? var.password_policy_temporary_password_validity_days : lookup(var.password_policy, "temporary_password_validity_days") + + } + + # Return the default values + password_policy = var.password_policy == null ? [local.password_policy_is_null] : [local.password_policy_not_null] + + # user_pool_add_ons + # If no user_pool_add_ons is provided, build a configuration using the default values + user_pool_add_ons_default = { + advanced_security_mode = lookup(var.user_pool_add_ons, "advanced_security_mode", null) == null ? var.user_pool_add_ons_advanced_security_mode : lookup(var.user_pool_add_ons, "advanced_security_mode") + } + + user_pool_add_ons = var.user_pool_add_ons_advanced_security_mode == null && length(var.user_pool_add_ons) == 0 ? [] : [local.user_pool_add_ons_default] + + # verification_message_template + # If no verification_message_template is provided, build a verification_message_template using the default values + verification_message_template_default = { + default_email_option = lookup(var.verification_message_template, "default_email_option", null) == null ? var.verification_message_template_default_email_option : lookup(var.verification_message_template, "default_email_option") + email_message_by_link = lookup(var.verification_message_template, "email_message_by_link", null) == null ? var.verification_message_template_email_message_by_link : lookup(var.verification_message_template, "email_message_by_link") + email_subject_by_link = lookup(var.verification_message_template, "email_subject_by_link", null) == null ? var.verification_message_template_email_subject_by_link : lookup(var.verification_message_template, "email_subject_by_link") + } + + verification_message_template = [local.verification_message_template_default] + + # software_token_mfa_configuration + # If no software_token_mfa_configuration is provided, build a software_token_mfa_configuration using the default values + software_token_mfa_configuration_default = { + enabled = lookup(var.software_token_mfa_configuration, "enabled", null) == null ? var.software_token_mfa_configuration_enabled : lookup(var.software_token_mfa_configuration, "enabled") + } + + software_token_mfa_configuration = (length(var.sms_configuration) == 0 || local.sms_configuration == null) && var.mfa_configuration == "OFF" ? [] : [local.software_token_mfa_configuration_default] + + # user_attribute_update_settings + # As default, all auto_verified_attributes will become attributes_require_verification_before_update + user_attribute_update_settings = var.user_attribute_update_settings == null ? (length(var.auto_verified_attributes) > 0 ? [{ attributes_require_verification_before_update = var.auto_verified_attributes }] : []) : [var.user_attribute_update_settings] +} diff --git a/aws-cognito-user-pool/outputs.tf b/aws-cognito-user-pool/outputs.tf new file mode 100644 index 0000000..ff94fbe --- /dev/null +++ b/aws-cognito-user-pool/outputs.tf @@ -0,0 +1,85 @@ +output "id" { + description = "The id of the user pool" + value = var.enabled ? aws_cognito_user_pool.pool[0].id : null +} + +output "arn" { + description = "The ARN of the user pool" + value = var.enabled ? aws_cognito_user_pool.pool[0].arn : null +} + +output "endpoint" { + description = "The endpoint name of the user pool. Example format: cognito-idp.REGION.amazonaws.com/xxxx_yyyyy" + value = var.enabled ? aws_cognito_user_pool.pool[0].endpoint : null +} + +output "creation_date" { + description = "The date the user pool was created" + value = var.enabled ? aws_cognito_user_pool.pool[0].creation_date : null +} + +output "last_modified_date" { + description = "The date the user pool was last modified" + value = var.enabled ? aws_cognito_user_pool.pool[0].last_modified_date : null +} + +output "name" { + description = "The name of the user pool" + value = var.enabled ? aws_cognito_user_pool.pool[0].name : null +} + +# +# aws_cognito_user_pool_domain +# +output "domain_aws_account_id" { + description = "The AWS account ID for the user pool owner" + value = var.enabled ? join("", aws_cognito_user_pool_domain.domain.*.aws_account_id) : null +} + +output "domain_cloudfront_distribution_arn" { + description = "The ARN of the CloudFront distribution" + value = var.enabled ? join("", aws_cognito_user_pool_domain.domain.*.cloudfront_distribution_arn) : null +} + +output "domain_s3_bucket" { + description = "The S3 bucket where the static files for this domain are stored" + value = var.enabled ? join("", aws_cognito_user_pool_domain.domain.*.s3_bucket) : null +} + +output "domain_app_version" { + description = "The app version" + value = var.enabled ? join("", aws_cognito_user_pool_domain.domain.*.version) : null +} + +# +# aws_cognito_user_pool_client +# +output "client_ids" { + description = "The ids of the user pool clients" + value = var.enabled ? aws_cognito_user_pool_client.client.*.id : null +} + +output "client_secrets" { + description = " The client secrets of the user pool clients" + value = var.enabled ? aws_cognito_user_pool_client.client.*.client_secret : null + sensitive = true +} + +output "client_ids_map" { + description = "The ids map of the user pool clients" + value = var.enabled ? { for k, v in aws_cognito_user_pool_client.client : v.name => v.id } : null +} + +output "client_secrets_map" { + description = "The client secrets map of the user pool clients" + value = var.enabled ? { for k, v in aws_cognito_user_pool_client.client : v.name => v.client_secret } : null + sensitive = true +} + +# +# aws_cognito_resource_servers +# +output "resource_servers_scope_identifiers" { + description = " A list of all scopes configured in the format identifier/scope_name" + value = var.enabled ? aws_cognito_resource_server.resource.*.scope_identifiers : null +} diff --git a/aws-cognito-user-pool/resource-server.tf b/aws-cognito-user-pool/resource-server.tf new file mode 100644 index 0000000..ec1f1e7 --- /dev/null +++ b/aws-cognito-user-pool/resource-server.tf @@ -0,0 +1,41 @@ +resource "aws_cognito_resource_server" "resource" { + count = var.enabled ? length(local.resource_servers) : 0 + name = lookup(element(local.resource_servers, count.index), "name") + identifier = lookup(element(local.resource_servers, count.index), "identifier") + + #scope + dynamic "scope" { + for_each = lookup(element(local.resource_servers, count.index), "scope") + content { + scope_name = lookup(scope.value, "scope_name") + scope_description = lookup(scope.value, "scope_description") + } + } + + user_pool_id = aws_cognito_user_pool.pool[0].id +} + +locals { + resource_server_default = [ + { + name = var.resource_server_name + identifier = var.resource_server_identifier + scope = [ + { + scope_name = var.resource_server_scope_name + scope_description = var.resource_server_scope_description + }] + } + ] + + # This parses var.user_groups which is a list of objects (map), and transforms it to a tuple of elements to avoid conflict with the ternary and local.groups_default + resource_servers_parsed = [for e in var.resource_servers : { + name = lookup(e, "name", null) + identifier = lookup(e, "identifier", null) + scope = lookup(e, "scope", []) + } + ] + + resource_servers = length(var.resource_servers) == 0 && (var.resource_server_name == null || var.resource_server_name == "") ? [] : (length(var.resource_servers) > 0 ? local.resource_servers_parsed : local.resource_server_default) + +} diff --git a/aws-cognito-user-pool/user-group.tf b/aws-cognito-user-pool/user-group.tf new file mode 100644 index 0000000..c21cdf9 --- /dev/null +++ b/aws-cognito-user-pool/user-group.tf @@ -0,0 +1,32 @@ +resource "aws_cognito_user_group" "main" { + count = var.enabled ? length(local.groups) : 0 + name = lookup(element(local.groups, count.index), "name") + description = lookup(element(local.groups, count.index), "description") + precedence = lookup(element(local.groups, count.index), "precedence") + role_arn = lookup(element(local.groups, count.index), "role_arn") + user_pool_id = aws_cognito_user_pool.pool[0].id +} + +locals { + groups_default = [ + { + name = var.user_group_name + description = var.user_group_description + precedence = var.user_group_precedence + role_arn = var.user_group_role_arn + + } + ] + + # This parses var.user_groups which is a list of objects (map), and transforms it to a tuple of elements to avoid conflict with the ternary and local.groups_default + groups_parsed = [for e in var.user_groups : { + name = lookup(e, "name", null) + description = lookup(e, "description", null) + precedence = lookup(e, "precedence", null) + role_arn = lookup(e, "role_arn", null) + } + ] + + groups = length(var.user_groups) == 0 && (var.user_group_name == null || var.user_group_name == "") ? [] : (length(var.user_groups) > 0 ? local.groups_parsed : local.groups_default) + +} diff --git a/aws-cognito-user-pool/variables.tf b/aws-cognito-user-pool/variables.tf new file mode 100644 index 0000000..1dcd888 --- /dev/null +++ b/aws-cognito-user-pool/variables.tf @@ -0,0 +1,634 @@ +# +# aws_cognito_user_pool +# +variable "enabled" { + description = "Change to false to avoid deploying any resources" + type = bool + default = true +} + +variable "user_pool_name" { + description = "The name of the user pool" + type = string +} + +variable "email_verification_message" { + description = "A string representing the email verification message" + type = string + default = null +} + +variable "email_verification_subject" { + description = "A string representing the email verification subject" + type = string + default = null +} + +# username_configuration +variable "username_configuration" { + description = "The Username Configuration. Setting `case_sensitive` specifies whether username case sensitivity will be applied for all users in the user pool through Cognito APIs" + type = map(any) + default = {} +} + +# admin_create_user_config +variable "admin_create_user_config" { + description = "The configuration for AdminCreateUser requests" + type = map(any) + default = {} +} + +variable "admin_create_user_config_allow_admin_create_user_only" { + description = "Set to True if only the administrator is allowed to create user profiles. Set to False if users can sign themselves up via an app" + type = bool + default = true +} + +variable "temporary_password_validity_days" { + description = "The user account expiration limit, in days, after which the account is no longer usable" + type = number + default = 7 +} + +variable "admin_create_user_config_email_message" { + description = "The message template for email messages. Must contain `{username}` and `{####}` placeholders, for username and temporary password, respectively" + type = string + default = "{username}, your verification code is `{####}`" +} + + +variable "admin_create_user_config_email_subject" { + description = "The subject line for email messages" + type = string + default = "Your verification code" +} + +variable "admin_create_user_config_sms_message" { + description = "- The message template for SMS messages. Must contain `{username}` and `{####}` placeholders, for username and temporary password, respectively" + type = string + default = "Your username is {username} and temporary password is `{####}`" +} + +variable "alias_attributes" { + description = "Attributes supported as an alias for this user pool. Possible values: phone_number, email, or preferred_username. Conflicts with `username_attributes`" + type = list(string) + default = null +} + +variable "username_attributes" { + description = "Specifies whether email addresses or phone numbers can be specified as usernames when a user signs up. Conflicts with `alias_attributes`" + type = list(string) + default = null +} + +variable "deletion_protection" { + description = "When active, DeletionProtection prevents accidental deletion of your user pool. Before you can delete a user pool that you have protected against deletion, you must deactivate this feature. Valid values are `ACTIVE` and `INACTIVE`." + type = string + default = "INACTIVE" +} + +variable "auto_verified_attributes" { + description = "The attributes to be auto-verified. Possible values: email, phone_number" + type = list(string) + default = [] +} + +# sms_configuration +variable "sms_configuration" { + description = "The SMS Configuration" + type = map(any) + default = {} +} + +variable "sms_configuration_external_id" { + description = "The external ID used in IAM role trust relationships" + type = string + default = "" +} + +variable "sms_configuration_sns_caller_arn" { + description = "The ARN of the Amazon SNS caller. This is usually the IAM role that you've given Cognito permission to assume" + type = string + default = "" +} + +# device_configuration +variable "device_configuration" { + description = "The configuration for the user pool's device tracking" + type = map(any) + default = {} +} + +variable "device_configuration_challenge_required_on_new_device" { + description = "Indicates whether a challenge is required on a new device. Only applicable to a new device" + type = bool + default = false +} + +variable "device_configuration_device_only_remembered_on_user_prompt" { + description = "If true, a device is only remembered on user prompt" + type = bool + default = false +} + +# email_configuration +variable "email_configuration" { + description = "The Email Configuration" + type = map(any) + default = {} +} + +variable "email_configuration_configuration_set" { + description = "The name of the configuration set" + type = string + default = null +} + +variable "email_configuration_reply_to_email_address" { + description = "The REPLY-TO email address" + type = string + default = "" +} + +variable "email_configuration_source_arn" { + description = "The ARN of the email source" + type = string + default = "" +} + +variable "email_configuration_email_sending_account" { + description = "Instruct Cognito to either use its built-in functional or Amazon SES to send out emails. Allowed values: `COGNITO_DEFAULT` or `DEVELOPER`" + type = string + default = "COGNITO_DEFAULT" +} + +variable "email_configuration_from_email_address" { + description = "Sender’s email address or sender’s display name with their email address (e.g. `john@example.com`, `John Smith ` or `\"John Smith Ph.D.\" )`. Escaped double quotes are required around display names that contain certain characters as specified in RFC 5322" + type = string + default = null +} + +# lambda_config +variable "lambda_config" { + description = "A container for the AWS Lambda triggers associated with the user pool" + type = any + default = {} +} + +variable "lambda_config_create_auth_challenge" { + description = "The ARN of the lambda creating an authentication challenge." + type = string + default = null +} + +variable "lambda_config_custom_message" { + description = "A custom Message AWS Lambda trigger." + type = string + default = null +} + +variable "lambda_config_define_auth_challenge" { + description = "Defines the authentication challenge." + type = string + default = null +} + +variable "lambda_config_post_authentication" { + description = "A post-authentication AWS Lambda trigger" + type = string + default = null +} + +variable "lambda_config_post_confirmation" { + description = "A post-confirmation AWS Lambda trigger" + type = string + default = null +} + +variable "lambda_config_pre_authentication" { + description = "A pre-authentication AWS Lambda trigger" + type = string + default = null +} +variable "lambda_config_pre_sign_up" { + description = "A pre-registration AWS Lambda trigger" + type = string + default = null +} + +variable "lambda_config_pre_token_generation" { + description = "Allow to customize identity token claims before token generation" + type = string + default = null +} + +variable "lambda_config_user_migration" { + description = "The user migration Lambda config type" + type = string + default = null +} + +variable "lambda_config_verify_auth_challenge_response" { + description = "Verifies the authentication challenge response" + type = string + default = null +} + +variable "lambda_config_kms_key_id" { + description = "The Amazon Resource Name of Key Management Service Customer master keys. Amazon Cognito uses the key to encrypt codes and temporary passwords sent to CustomEmailSender and CustomSMSSender." + type = string + default = null +} + +variable "lambda_config_custom_email_sender" { + description = "A custom email sender AWS Lambda trigger." + type = any + default = {} +} + +variable "lambda_config_custom_sms_sender" { + description = "A custom SMS sender AWS Lambda trigger." + type = any + default = {} +} + +variable "mfa_configuration" { + description = "Set to enable multi-factor authentication. Must be one of the following values (ON, OFF, OPTIONAL)" + type = string + default = "OFF" +} + +# software_token_mfa_configuration +variable "software_token_mfa_configuration" { + description = "Configuration block for software token MFA (multifactor-auth). mfa_configuration must also be enabled for this to work" + type = map(any) + default = {} +} + +variable "software_token_mfa_configuration_enabled" { + description = "If true, and if mfa_configuration is also enabled, multi-factor authentication by software TOTP generator will be enabled" + type = bool + default = false +} + +# password_policy +variable "password_policy" { + description = "A container for information about the user pool password policy" + type = object({ + minimum_length = number, + require_lowercase = bool, + require_numbers = bool, + require_symbols = bool, + require_uppercase = bool, + temporary_password_validity_days = number + }) + default = null +} + +variable "password_policy_minimum_length" { + description = "The minimum length of the password policy that you have set" + type = number + default = 8 +} + +variable "password_policy_require_lowercase" { + description = "Whether you have required users to use at least one lowercase letter in their password" + type = bool + default = true +} + +variable "password_policy_require_numbers" { + description = "Whether you have required users to use at least one number in their password" + type = bool + default = true +} + +variable "password_policy_require_symbols" { + description = "Whether you have required users to use at least one symbol in their password" + type = bool + default = true +} + +variable "password_policy_require_uppercase" { + description = "Whether you have required users to use at least one uppercase letter in their password" + type = bool + default = true +} + +variable "password_policy_temporary_password_validity_days" { + description = "The minimum length of the password policy that you have set" + type = number + default = 7 +} + +# schema +variable "schemas" { + description = "A container with the schema attributes of a user pool. Maximum of 50 attributes" + type = list(any) + default = [] +} + +variable "string_schemas" { + description = "A container with the string schema attributes of a user pool. Maximum of 50 attributes" + type = list(any) + default = [] +} + +variable "number_schemas" { + description = "A container with the number schema attributes of a user pool. Maximum of 50 attributes" + type = list(any) + default = [] +} + +# sms messages +variable "sms_authentication_message" { + description = "A string representing the SMS authentication message" + type = string + default = null +} + +variable "sms_verification_message" { + description = "A string representing the SMS verification message" + type = string + default = null +} + +# tags +variable "tags" { + description = "A mapping of tags to assign to the User Pool" + type = map(string) + default = {} +} + +# user_attribute_update_settings +variable "user_attribute_update_settings" { + description = "Configuration block for user attribute update settings. Must contain key `attributes_require_verification_before_update` with list with only valid values of `email` and `phone_number`" + type = map(list(string)) + default = null +} + +# user_pool_add_ons +variable "user_pool_add_ons" { + description = "Configuration block for user pool add-ons to enable user pool advanced security mode features" + type = map(any) + default = {} +} + +variable "user_pool_add_ons_advanced_security_mode" { + description = "The mode for advanced security, must be one of `OFF`, `AUDIT` or `ENFORCED`" + type = string + default = null +} + +# verification_message_template +variable "verification_message_template" { + description = "The verification message templates configuration" + type = map(any) + default = {} +} + +variable "verification_message_template_default_email_option" { + description = "The default email option. Must be either `CONFIRM_WITH_CODE` or `CONFIRM_WITH_LINK`. Defaults to `CONFIRM_WITH_CODE`" + type = string + default = null +} + +variable "verification_message_template_email_message_by_link" { + description = "The email message template for sending a confirmation link to the user, it must contain the `{##Click Here##}` placeholder" + type = string + default = null +} + +variable "verification_message_template_email_subject_by_link" { + description = "The subject line for the email message template for sending a confirmation link to the user" + type = string + default = null +} + +# +# aws_cognito_user_pool_domain +# +variable "domain" { + description = "Cognito User Pool domain" + type = string + default = null +} + +variable "domain_certificate_arn" { + description = "The ARN of an ISSUED ACM certificate in us-east-1 for a custom domain" + type = string + default = null +} + +# +# aws_cognito_user_pool_client +# +variable "clients" { + description = "A container with the clients definitions" + type = any + default = [] +} + +variable "client_allowed_oauth_flows" { + description = "The name of the application client" + type = list(string) + default = [] +} + +variable "client_allowed_oauth_flows_user_pool_client" { + description = "Whether the client is allowed to follow the OAuth protocol when interacting with Cognito user pools" + type = bool + default = true +} + +variable "client_allowed_oauth_scopes" { + description = "List of allowed OAuth scopes (phone, email, openid, profile, and aws.cognito.signin.user.admin)" + type = list(string) + default = [] +} + +variable "client_auth_session_validity" { + description = "Amazon Cognito creates a session token for each API request in an authentication flow. AuthSessionValidity is the duration, in minutes, of that session token. Your user pool native user must respond to each authentication challenge before the session expires. Valid values between 3 and 15. Default value is 3." + type = number + default = 3 +} + +variable "client_callback_urls" { + description = "List of allowed callback URLs for the identity providers" + type = list(string) + default = [] +} + +variable "client_default_redirect_uri" { + description = "The default redirect URI. Must be in the list of callback URLs" + type = string + default = "" +} + +variable "client_enable_token_revocation" { + description = "Whether the client token can be revoked" + type = bool + default = true +} + +variable "client_explicit_auth_flows" { + description = "List of authentication flows (ADMIN_NO_SRP_AUTH, CUSTOM_AUTH_FLOW_ONLY, USER_PASSWORD_AUTH)" + type = list(string) + default = [] +} + +variable "client_generate_secret" { + description = "Should an application secret be generated" + type = bool + default = true +} + +variable "client_logout_urls" { + description = "List of allowed logout URLs for the identity providers" + type = list(string) + default = [] +} + +variable "client_name" { + description = "The name of the application client" + type = string + default = null +} + +variable "client_read_attributes" { + description = "List of user pool attributes the application client can read from" + type = list(string) + default = [] +} + +variable "client_prevent_user_existence_errors" { + description = "Choose which errors and responses are returned by Cognito APIs during authentication, account confirmation, and password recovery when the user does not exist in the user pool. When set to ENABLED and the user does not exist, authentication returns an error indicating either the username or password was incorrect, and account confirmation and password recovery return a response indicating a code was sent to a simulated destination. When set to LEGACY, those APIs will return a UserNotFoundException exception if the user does not exist in the user pool." + type = string + default = null +} + +variable "client_supported_identity_providers" { + description = "List of provider names for the identity providers that are supported on this client" + type = list(string) + default = [] +} + +variable "client_write_attributes" { + description = "List of user pool attributes the application client can write to" + type = list(string) + default = [] +} + +variable "client_access_token_validity" { + description = "Time limit, between 5 minutes and 1 day, after which the access token is no longer valid and cannot be used. This value will be overridden if you have entered a value in `token_validity_units`." + type = number + default = 60 +} + +variable "client_id_token_validity" { + description = "Time limit, between 5 minutes and 1 day, after which the ID token is no longer valid and cannot be used. Must be between 5 minutes and 1 day. Cannot be greater than refresh token expiration. This value will be overridden if you have entered a value in `token_validity_units`." + type = number + default = 60 +} + +variable "client_refresh_token_validity" { + description = "The time limit in days refresh tokens are valid for. Must be between 60 minutes and 3650 days. This value will be overridden if you have entered a value in `token_validity_units`" + type = number + default = 30 +} + +variable "client_token_validity_units" { + description = "Configuration block for units in which the validity times are represented in. Valid values for the following arguments are: `seconds`, `minutes`, `hours` or `days`." + type = any + default = { + access_token = "minutes" + id_token = "minutes" + refresh_token = "days" + } + +} + +# +# aws_cognito_user_group +# +variable "user_groups" { + description = "A container with the user_groups definitions" + type = list(any) + default = [] +} + +variable "user_group_name" { + description = "The name of the user group" + type = string + default = null +} + +variable "user_group_description" { + description = "The description of the user group" + type = string + default = null +} + +variable "user_group_precedence" { + description = "The precedence of the user group" + type = number + default = null +} + +variable "user_group_role_arn" { + description = "The ARN of the IAM role to be associated with the user group" + type = string + default = null +} + +# +# aws_cognito_resource_server +# +variable "resource_servers" { + description = "A container with the user_groups definitions" + type = list(any) + default = [] +} + +variable "resource_server_name" { + description = "A name for the resource server" + type = string + default = null +} + +variable "resource_server_identifier" { + description = "An identifier for the resource server" + type = string + default = null +} + +variable "resource_server_scope_name" { + description = "The scope name" + type = string + default = null +} + +variable "resource_server_scope_description" { + description = "The scope description" + type = string + default = null +} + +# +# Account Recovery Setting +# +variable "recovery_mechanisms" { + description = "The list of Account Recovery Options" + type = list(any) + default = [] +} + +# +# aws_cognito_identity_provider +# +variable "identity_providers" { + description = "Cognito Pool Identity Providers" + type = list(any) + default = [] + sensitive = true +} diff --git a/aws-cognito-user-pool/versions.tf b/aws-cognito-user-pool/versions.tf new file mode 100644 index 0000000..f16bdd9 --- /dev/null +++ b/aws-cognito-user-pool/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= v0.13.7" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.38" + } + } +} diff --git a/aws-iam/modules/iam-assumable-role/main.tf b/aws-iam/modules/iam-assumable-role/main.tf index d1f8b52..4ba62b9 100644 --- a/aws-iam/modules/iam-assumable-role/main.tf +++ b/aws-iam/modules/iam-assumable-role/main.tf @@ -22,11 +22,11 @@ data "aws_iam_policy_document" "assume_role" { } dynamic "condition" { - for_each = length(local.role_sts_externalid) != 0 ? [true] : [] + for_each = length(local.role_sts_orgid) != 0 ? [true] : [] content { test = "StringEquals" variable = "aws:PrincipalOrgID" - values = local.role_sts_externalid + values = local.role_sts_orgid } }