-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add identity provider modules #650
Conversation
infra/test/infra_test.go
Outdated
@@ -132,13 +132,23 @@ func EnableDestroyService(t *testing.T, terraformOptions *terraform.Options) { | |||
}, | |||
WorkingDir: "../../", | |||
}) | |||
shell.RunCommand(t, shell.Command{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this section for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By default, deletion protection is on for cognito. This script is for CI testing the infra service layer. To be able to delete cognito, we have to explicitly disable deletion protection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, I think we can remove the sed line from infra_test.go and re-run ci-infra-service.yml in the platform-test repo to make sure it still works just leveraging the is_temporary flag. And I had some comments on getting rid of what seems like unused admin email configuration for now.
has_database = local.has_database | ||
has_incident_management_service = local.has_incident_management_service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tangential thought: i've been thinking of renaming these at some point to:
- enable_database
- enable_incident_management_service_integration
@lorenyu I think I've addressed all the comments in your previous review. Could you please take another look? Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Had a few non-blocking questions that I left as comments.
I had just one more question on the topic of testing, I see the tests that created the resources. How complicated would it be to add some minimal auth logic to the example app in platform-test that leverages the identity provider? Also, it doesn't necessarily have to be with platform-test example app — if you tested the identity provider with the rails template, I wonder if there is some evidence we can provide that this infra setup works with the rails app — maybe a link to a platform-test-rails PR (if that exists), or if you have a private test repo that's using this same infra maybe just sharing some screenshots or something from there?
email = { | ||
# When you're ready to use SES instead of the Cognito default to send emails, set this | ||
# to the SES-verified email address to be used when sending emails. | ||
sender_email = null | ||
|
||
# Configure the name that users see in the "From" section of their inbox, so that it's | ||
# clearer who the email is from. | ||
sender_display_name = null | ||
|
||
# Configure the REPLY-TO email address if it should be different from the sender. | ||
reply_to_email = null | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
idea / todo : what do you think about DRY'ing this up in the future by pulling the sender_email automatically once we have an associated notifications.tf config? e.g. something like
email = {
sender_email = var.enable_notifications ? local.notifications_config.sender_email : null
...
}
i'd also be interested in exploring the idea of just eliminating these fields altogether from identity_provider_config and just having a single email_config/notifications_config that lives separately and would be used to configure both AWS Pinpoint/SES and AWS Cognito. the idea being that in the common case you want all your service to behave consistently i.e. have the same sender_email, same sender_display_name, etc.
even though we don't have notifications yet, if we separate out the config now, we might be able to avoid moving the config around (which can trigger a breaking change for projects) when we eventually add notifications. or if you think that relies on too much guesswork, we could keep it here for now and refactor later.
thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I think that's a very good idea. Let me take a look at the SES/Pinpoint config to get a sense of how best to construct a /infra/app/app-config/env-config/notifications.tf
config file. If it's easy-ish, then I'll go ahead and lay the foundation now. If it's complicated, then I think we should plan to refactor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I cross-referenced the Cognito, SES, and Pinpoint docs and configs and did some manual testing to make sure everything would play nicely together. I have a proposed change, but I haven't had time to test it yet, so I'll re-ping once that's done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing complete in the latest version.
I think this is too complicated to add to this PR. But does bring up some good questions about how we want to make sure our test apps are exercising all of the core functionality. For instance, I could see wanting to do something similar for notifications. Should we add a follow-up issue for that?
Yes, I've been testing with the |
I'm realizing that I totally missed writing documentation for this feature, so I'll add that in, too. |
@rocketnova one thing that came up today is the notion that it would be nice to have PR environments use the same cognito pool as the default workspace, so that we can test using existing users and data rather than needing to go through the account creation flow etc on every PR. It doesn't have to be in this PR, but I think we'd want to not call the identity provider module if it's a temporary environment and instead use a data source to fetch the existing user pool. Thoughts? |
@lorenyu That's interesting. I think that can work. Let's not put it into this PR. This one basically ready to go (finishing final testing now) and I don't want to delay getting it merged in anymore. |
For future readers, here's some of the cognito application logic:
|
👍 I also added a gif and screenshot to the "Testing" portion of the PR description if that's helpful. Sorry I forgot to call that out explicitly. |
locals { | ||
# If your application should redirect users, after successful authentication, to a | ||
# page other than the homepage, specify the path fragment here. | ||
# Example: "profile" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Example: "profile" | |
# Example: "profile" | |
# docs: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html |
|
||
# If your application should redirect users, after signing out, to a page other than | ||
# the homepage, specify the path fragment here. | ||
# Example: "logout" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Example: "logout" | |
# Example: "logout" | |
# docs: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html |
} | ||
|
||
# Optionally configure email template for resetting a password. | ||
# Set any attribute to a non-null value to override AWS Cognito defaults. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Set any attribute to a non-null value to override AWS Cognito defaults. | |
# Set any attribute to a non-null value to override AWS Cognito defaults. | |
# docs: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pool-settings-message-customizations.html |
# Notifications configuration | ||
locals { | ||
notifications_config = var.enable_notifications ? { | ||
# Set to an SES-verified email address to be used when sending emails. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Set to an SES-verified email address to be used when sending emails. | |
# Set to an SES-verified email address to be used when sending emails. | |
# docs: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-email.html |
reply_to_email = local.notifications_config == null ? null : local.notifications_config.reply_to_email | ||
} | ||
|
||
module "identity_provider_client" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(non-blocking question) what's the reasoning behind splitting this up into two terraform modules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question! This work is adapted from a another project where they were already two modules. Not a great reason on its own, but it was the starting point and in combination with the following reasons, I felt it was the right choice here:
- They are configuring slightly different things: the user pool vs the app client that talks to the user pool. This PR doesn't include the following functionality, but a project could have a single user pool with multiple app clients or a project could have just a user pool without an app client. I wanted to keep the foundation flexible to accommodate that additional configuration.
- The two modules have largely distinct rather than overlapping variables. Combining them makes a larger variables file than necessary.
- If we want to combine them, it's easier to do so than to pull them apart.
Thoughts?
refresh_token_validity = 1 | ||
access_token_validity = 60 | ||
id_token_validity = 60 | ||
token_validity_units { | ||
refresh_token = "days" | ||
access_token = "minutes" | ||
id_token = "minutes" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(non-blocking question) I'm assuming you just guessed at these numbers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I brought these values over from a previous project that established these as reasonable defaults. Do you think they should be something else?
@@ -0,0 +1,37 @@ | |||
resource "aws_cognito_user_pool_client" "client" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resource "aws_cognito_user_pool_client" "client" { | |
# docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_pool_client | |
resource "aws_cognito_user_pool_client" "client" { |
This is something I like to do, especially for complex terraform resources. I still remember years ago being a terraform newbie and not knowing how to connect the configuration to the documentation
generate_secret = true | ||
allowed_oauth_flows_user_pool_client = true | ||
allowed_oauth_flows = ["code"] | ||
allowed_oauth_scopes = ["phone", "email", "openid", "profile"] | ||
explicit_auth_flows = ["ALLOW_ADMIN_USER_PASSWORD_AUTH", "ALLOW_REFRESH_TOKEN_AUTH"] | ||
|
||
# Avoid security issue where error messages indicate when a user doesn't exist | ||
prevent_user_existence_errors = "ENABLED" | ||
|
||
enable_token_revocation = true | ||
enable_propagate_additional_user_context_data = false | ||
|
||
read_attributes = ["email", "email_verified", "phone_number", "phone_number_verified", "updated_at"] | ||
write_attributes = ["email", "updated_at", "phone_number"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole section could use some inline documentation, but I don't wanna block on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably establish some guidelines on how much we want to inline document modules, which we are currently anticipating most projects should not modify, vs the /infra/app
dirs, which is where we are currently instructing template adopters to put configuration.
resource "aws_cognito_user_pool" "main" { | ||
name = var.name | ||
|
||
# Use a separate line to support automated terraform destroy commands |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Use a separate line to support automated terraform destroy commands | |
# We use a separate line here to support automated terraform destroy commands. | |
# Do not edit this line, the destroy command looks for it verbatim with `sed` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of the lines that get sed
by destroy commands have the same comment. I'm going to leave this one for now so that it's easier for us to do a comprehensive find and replace in a later PR.
@@ -18,11 +18,12 @@ backend_config_file="${environment}.s3.tfbackend" | |||
sed -i.bak 's/force_destroy = var.is_temporary/force_destroy = true/g' infra/modules/service/access-logs.tf | |||
sed -i.bak 's/force_destroy = var.is_temporary/force_destroy = true/g' infra/modules/storage/main.tf | |||
sed -i.bak 's/enable_deletion_protection = !var.is_temporary/enable_deletion_protection = false/g' infra/modules/service/load-balancer.tf | |||
sed -i.bak 's/deletion_protection = var.is_temporary ? "INACTIVE" : "ACTIVE"/deletion_protection = "INACTIVE"/g' infra/modules/identity-provider/main.tf |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels very brittle to me (...) but it's the existing pattern, so I suppose I can forgive it ^^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. Would love to adopt a more robust pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yay
Created #719 for this feature. |
Ticket
N/A
Changes
identity-provider
module to configure an AWS Cognito user poolidentity-provider-client
module to configure an AWS Cognito user pool app clientContext for reviewers
Many projects need an identity provider. This PR adds an option to the app config to allow projects to specify whether they want to enable one using AWS Cognito.
This is needed by the rails template, which comes with auth out-of-the-box.
Testing
Tested on platform-test
Using navapbc/platform-test#108
Screenshot showing the Cognito user pool:
Screenshot showing the Cognito user pool app client:
Screenshot of ECS task definition showing that the new Cognito env vars and secrets are passed through to the ECS task:
Test deploy on platform-test-rails
Using navapbc/platform-test-rails#1