Skip to content

Prepare for integration with infra template #40

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

Merged
merged 11 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ If you have previously installed this template and would like to update your pro
1. Run the [update script](./template-only-bin/update-template) in your project's root directory and pass in the branch, commit hash, or release that you want to update to, followed by the name of your application directory (e.g. `app-rails`).

```bash
curl https://raw.githubusercontent.com/navapbc/template-application-rails/main/template-only-bin/download-and-install-template | bash -s -- <commit_hash> <app_name>
curl https://raw.githubusercontent.com/navapbc/template-application-rails/main/template-only-bin/update-template | bash -s -- <commit_hash> <app_name>
```

This script will:
Expand Down
3 changes: 3 additions & 0 deletions app-rails/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ db-up: ## Run just the database container
db-migrate: ## Run database migrations
$(RAILS_RUN_CMD) db:migrate

db-rollback: ## Rollback a database migration
$(RAILS_RUN_CMD) db:rollback

db-test-prepare: ## Prepare the test database
$(RAILS_RUN_CMD) db:test:prepare

Expand Down
26 changes: 13 additions & 13 deletions app-rails/app/adapters/auth/cognito_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def initialize(client: Aws::CognitoIdentityProvider::Client.new)
def create_account(email, password)
begin
response = @client.sign_up(
client_id: ENV["AWS_COGNITO_CLIENT_ID"],
client_id: ENV["COGNITO_CLIENT_ID"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if this is the right rails way, but could we set this client_id, along with the user_pool_id, from the ENV at the top of the class and reuse the variable, instead of resetting it in each method to be more DRY?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good change, but I'd like to break it out into a separate issue.

secret_hash: get_secret_hash(email),
username: email,
password: password,
Expand Down Expand Up @@ -47,7 +47,7 @@ def create_account(email, password)
def forgot_password(email)
begin
response = @client.forgot_password(
client_id: ENV["AWS_COGNITO_CLIENT_ID"],
client_id: ENV["COGNITO_CLIENT_ID"],
secret_hash: get_secret_hash(email),
username: email
)
Expand All @@ -64,7 +64,7 @@ def forgot_password(email)
def confirm_forgot_password(email, code, password)
begin
@client.confirm_forgot_password(
client_id: ENV["AWS_COGNITO_CLIENT_ID"],
client_id: ENV["COGNITO_CLIENT_ID"],
secret_hash: get_secret_hash(email),
username: email,
confirmation_code: code,
Expand All @@ -84,7 +84,7 @@ def confirm_forgot_password(email, code, password)
def change_email(uid, new_email)
begin
response = @client.admin_update_user_attributes(
user_pool_id: ENV["AWS_COGNITO_USER_POOL_ID"],
user_pool_id: ENV["COGNITO_USER_POOL_ID"],
username: uid,
user_attributes: [
{
Expand Down Expand Up @@ -114,8 +114,8 @@ def change_email(uid, new_email)
def initiate_auth(email, password)
begin
response = @client.admin_initiate_auth(
user_pool_id: ENV["AWS_COGNITO_USER_POOL_ID"],
client_id: ENV["AWS_COGNITO_CLIENT_ID"],
user_pool_id: ENV["COGNITO_USER_POOL_ID"],
client_id: ENV["COGNITO_CLIENT_ID"],
auth_flow: "ADMIN_USER_PASSWORD_AUTH",
auth_parameters: {
"USERNAME" => email,
Expand Down Expand Up @@ -151,7 +151,7 @@ def initiate_auth(email, password)
def resend_verification_code(email)
begin
@client.resend_confirmation_code(
client_id: ENV["AWS_COGNITO_CLIENT_ID"],
client_id: ENV["COGNITO_CLIENT_ID"],
secret_hash: get_secret_hash(email),
username: email
)
Expand All @@ -163,8 +163,8 @@ def resend_verification_code(email)
def respond_to_auth_challenge(code, challenge = {})
begin
response = @client.admin_respond_to_auth_challenge(
client_id: ENV["AWS_COGNITO_CLIENT_ID"],
user_pool_id: ENV["AWS_COGNITO_USER_POOL_ID"],
client_id: ENV["COGNITO_CLIENT_ID"],
user_pool_id: ENV["COGNITO_USER_POOL_ID"],
challenge_name: "SOFTWARE_TOKEN_MFA",
session: challenge[:session],
challenge_responses: {
Expand All @@ -184,7 +184,7 @@ def respond_to_auth_challenge(code, challenge = {})
def verify_account(email, code)
begin
@client.confirm_sign_up(
client_id: ENV["AWS_COGNITO_CLIENT_ID"],
client_id: ENV["COGNITO_CLIENT_ID"],
secret_hash: get_secret_hash(email),
username: email,
confirmation_code: code
Expand Down Expand Up @@ -242,7 +242,7 @@ def verify_software_token(code, access_token)
def disable_software_token(uid)
begin
@client.admin_set_user_mfa_preference(
user_pool_id: ENV["AWS_COGNITO_USER_POOL_ID"],
user_pool_id: ENV["COGNITO_USER_POOL_ID"],
username: uid,
software_token_mfa_settings: {
enabled: false,
Expand All @@ -265,8 +265,8 @@ def get_auth_result(response)
end

def get_secret_hash(username)
message = username + ENV["AWS_COGNITO_CLIENT_ID"]
key = ENV["AWS_COGNITO_CLIENT_SECRET"]
message = username + ENV["COGNITO_CLIENT_ID"]
key = ENV["COGNITO_CLIENT_SECRET"]
Base64.strict_encode64(OpenSSL::HMAC.digest("sha256", key, message))
end

Expand Down
2 changes: 1 addition & 1 deletion app-rails/config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
config.cache_store = :null_store
end

config.active_storage.service = ENV["AWS_BUCKET_NAME"] ? :amazon : :local
config.active_storage.service = ENV["BUCKET_NAME"] ? :amazon : :local

config.action_mailer.delivery_method = ENV["SES_EMAIL"] ? :sesv2 : :letter_opener

Expand Down
5 changes: 5 additions & 0 deletions app-rails/config/environments/production.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true

# Exclude healthcheck endpoint from force SSL since healthchecks should not go through
# the reverse proxy.
# See https://api.rubyonrails.org/classes/ActionDispatch/SSL.html
config.ssl_options = { redirect: { exclude: -> request { /health/.match?(request.path) } } }

# Log to STDOUT by default
config.logger = ActiveSupport::Logger.new(STDOUT)
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
Expand Down
2 changes: 1 addition & 1 deletion app-rails/config/storage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ local:

amazon:
service: S3
bucket: <%= ENV.fetch("AWS_BUCKET_NAME") { nil } %>
bucket: <%= ENV.fetch("BUCKET_NAME") { nil } %>


# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
Expand Down

This file was deleted.

3 changes: 1 addition & 2 deletions app-rails/db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions app-rails/local.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ AWS_DEFAULT_REGION=<FILL ME IN>
# Auth
############################

AWS_COGNITO_USER_POOL_ID=<FILL ME IN>
AWS_COGNITO_CLIENT_ID=<FILL ME IN>
AWS_COGNITO_CLIENT_SECRET=<FILL ME IN>
COGNITO_USER_POOL_ID=<FILL ME IN>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you also mean to remove AWS from line 23, in AWS_BUCKET_NAME=<FILL ME IN> because you refer to `ENV["BUCKET_NAME"] elsewhere?

Also, maybe take it out of the AWS Services section.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Thank you!

COGNITO_CLIENT_ID=<FILL ME IN>
COGNITO_CLIENT_SECRET=<FILL ME IN>

############################
# Database
Expand All @@ -37,4 +37,4 @@ AWS_COGNITO_CLIENT_SECRET=<FILL ME IN>
DB_HOST=127.0.0.1
DB_NAME=app_rails
DB_USER=app_rails
DB_PASSWORD=secret123
DB_PASSWORD=secret123
3 changes: 1 addition & 2 deletions docs/app-rails/technical-foundation.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ We have are using [UUIDs for primary keys](https://guides.rubyonrails.org/active

- ⚠️ Using ActiveRecord functions like `Foo.first` and `Foo.last` have unreliable results
- Generating new models or scaffolds requires passing the `--primary-key-type=uuid` flag. For instance, `make rails-generate GENERATE_COMMAND="model Foo --primary-key-type=uuid"`
- `pgcrypto` is a required dependency

#### Enums

Expand All @@ -61,7 +60,7 @@ To preview email views in the browser, visit: `/rails/mailers`

To test AWS SES email sending locally:

1. Set the `AWS_*` env var in your `.env` file
1. Set the "AWS services" env var in your `.env` file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

env vars?
env variables?
Since it is multiple vars, it's something someone might get tripped up on if they see it singular here.

If aws bucket (now just bucket) is moved out of AWS services section, is it needed here for SES to work properly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe so.

1. Set the `SES_EMAIL` env var to a verified sending identity
1. Restart the server

Expand Down
43 changes: 43 additions & 0 deletions template-only-docs/Deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Deployment to cloud environments

## Requirements

- External service access: The application must be able to make network calls to the public internet.
- AWS Cognito: The application comes with AWS Cognito enabled by default, so AWS Cognito must be set up before deploying the application.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AWS Cognito has a lot of settings/defaults, and it's not clear from this how to set up a cognito user pool to satisfy the application. A terrafrom module would go a long way to describing what an example cognito/user pool config should look like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I'll make a note.

- Custom domain name with HTTPS support: AWS Cognito requires HTTPS for callback urls to function.
- Access to write to temporary directory: Rails needs to be able to write out temporary files.
- Environment variables: You must provide the application with the environment variables listed in [local.env.example](/app-rails/local.env.example).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to say more about this specifically for cloud deployments? I know we're setting them as aws secrets and importing them to the ecs containers via the task definition, but if I'm using this repo and not using the infra template, that context would be really helpful.

- Secrets: You must provide the application with a secret `SECRET_KEY_BASE`. For more information, see the [Rails Guide on Security](https://guides.rubyonrails.org/v7.1/security.html#environmental-security).

## Deploying using the Platform Infrastructure Template

*Note: The following will be true once https://github.com/navapbc/template-infra/pull/650 is merged.*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it belongs in a release note, and not a deployment.md file? Hopefully it won't be an issue for long.


This template can be deployed using the [Nava Platform Infrastructure Template](https://github.com/navapbc/template-infra). Using the infrastructure template will handle creating and configuring all of the resources required in AWS.

While following the [infrastructure template installation instructions](https://github.com/navapbc/template-infra?tab=readme-ov-file#installation) and [setup instructions](https://github.com/navapbc/template-infra/blob/main/infra/README.md), use the following configuration:

1. Rename `/infra/app` to `/infra/<APP_NAME>` so that it matches the directory name of your application. By default, this is `app-rails`.
1. In `/infra/<APP_NAME>/app-config/main.tf`:
1. Set `has_external_non_aws_service` to `true`.
2. Set `enable_identity_provider` to `true`.
1. In `/infra/<APP_NAME>/app-config/<ENVIRONMENT>.tf`:
1. Set the `domain_name`.
2. Set `enable_https` to `true`.
3. Set `enable_command_execution` to `true`: This is necessary temporarily until a temporary file system can be enabled. Otherwise, ECS will run with read-only root filesystem, which will cause rails to error.
1. In `/infra/<APP_NAME>/app-config/env-config/environment-variables.tf`:
1. Add an entry to `secrets`:
```terraform
SECRET_KEY_BASE = {
manage_method = "generated"
secret_store_name = "/${var.app_name}-${var.environment}/service/rails-secret-key-base"
}
```
1. In `/infra/networks/main.tf`:
1. Modify the `app_config` module to change the path to match the directory name of your application. By default, this is `app-rails`.
```terraform
module "app_config" {
source = "../<APP_NAME>/app-config"
}
```
1. Follow the infrastructure template instructions to configure [custom domains](https://github.com/navapbc/template-infra/blob/main/docs/infra/set-up-custom-domains.md) and [https support](https://github.com/navapbc/template-infra/blob/main/docs/infra/https-support.md).
Loading