From e223cecc4c5770b82ff7fb187e1c1efd06d6c16d Mon Sep 17 00:00:00 2001 From: Thomas Sibley Date: Thu, 26 Oct 2023 13:30:04 -0700 Subject: [PATCH] Explicitly configure AWS region Make it explicit in our config, code, and documentation. This became newly and implicitly necessary with the upgrade from the v2 to v3 SDK in b326340b. I didn't notice in development, however, because region was implicitly sourced from the default profile in my personal AWS config file. That config file isn't available in production, of course, and this resulted in some requests 500-ing with "region not set" errors upon deploy to Heroku. I likely could have noticed had I tried the Heroku review app for the original changes. --- docs/infrastructure.md | 3 +++ docs/production.rst | 39 ++++++++++++++++++++++++++++---------- env/outputs.tf | 5 +++++ env/production/config.json | 1 + src/aws.js | 9 +++++++++ src/config.js | 15 +++++++++++++++ 6 files changed, 62 insertions(+), 10 deletions(-) diff --git a/docs/infrastructure.md b/docs/infrastructure.md index 65012b596..51613aa5d 100644 --- a/docs/infrastructure.md +++ b/docs/infrastructure.md @@ -46,6 +46,9 @@ Deploys to the production app are performed by manually [promoting](https://devc - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` are tied to the `nextstrain.org` AWS IAM user. These credentials allow the backend web server limited access to private S3 buckets. + - `AWS_REGION` should be set to the region containing S3 buckets. + This is `us-east-1` for production and testing. + - `REDIS_URL` is provided by the Heroku Redis add-on. It should not be modified directly. Our [authentication handlers](../src/authn/index.js) rewrite it at server start to use a secure TLS connection. diff --git a/docs/production.rst b/docs/production.rst index 854e2184c..00aab0db0 100644 --- a/docs/production.rst +++ b/docs/production.rst @@ -73,28 +73,47 @@ The Node.js server should not be directly accessible on the network. It should only be accessible via the reverse proxy. -S3 -== - -Amazon S3 or an alternative S3-compatible object store is required for -Nextstrain Groups data storage. +AWS configuration +================= -The `GROUPS_BUCKET` environment variable or config file field may be used to -override the default bucket name of `nextstrain-groups`. +AWS credentials and a region must be configured for access to services like S3 +and Cognito (if using). The standard AWS credential sources are used, e.g. environment variables, -credential and profile files, instance metadata, etc. Environment variables -are the typical choice, including: +shared credential and config files, instance metadata, etc. Environment +variables are the typical choice, including: .. parsed-literal:: AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY *AWS_SESSION_TOKEN* - *AWS_REGION* Variable names in italics may not be necessary for all configurations. +Region may be configured with:: + + AWS_REGION + +set in the environment or config file. If not set, the standard AWS config +file, if any, is consulted. + +See the AWS SDK for JS v3 documentation for details on the standard +configuration methods for credentials_ and region_. + +.. _credentials: https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html +.. _region: https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html + + +S3 +== + +Amazon S3 or an alternative S3-compatible object store is required for +Nextstrain Groups data storage. + +The `GROUPS_BUCKET` environment variable or config file field may be used to +override the default bucket name of `nextstrain-groups`. + If using an alternative S3-compatible object store, point the server at its endpoint with:: diff --git a/env/outputs.tf b/env/outputs.tf index e657c7587..f52d611d5 100644 --- a/env/outputs.tf +++ b/env/outputs.tf @@ -1,6 +1,11 @@ # These outputs are shared by all Terraform configurations (production and # testing environments) via symlinks. They correspond to required environment # variables for the nextstrain.org server. +data "aws_region" "current" {} + +output "AWS_REGION" { + value = data.aws_region.current.name +} output "COGNITO_USER_POOL_ID" { value = module.cognito.COGNITO_USER_POOL_ID diff --git a/env/production/config.json b/env/production/config.json index e3bc3d870..d27393b06 100644 --- a/env/production/config.json +++ b/env/production/config.json @@ -1,4 +1,5 @@ { + "AWS_REGION": "us-east-1", "OIDC_IDP_URL": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_Cg5rcTged", "OAUTH2_CLIENT_ID": "rki99ml8g2jb9sm1qcq9oi5n", "OAUTH2_CLI_CLIENT_ID": "2vmc93kj4fiul8uv40uqge93m5", diff --git a/src/aws.js b/src/aws.js index 6293df595..06e96cb54 100644 --- a/src/aws.js +++ b/src/aws.js @@ -6,6 +6,8 @@ import { NodeHttpHandler } from "@smithy/node-http-handler"; import { ProxyAgent } from "proxy-agent"; +import { AWS_REGION } from "./config.js"; + const agent = new ProxyAgent(); /** @@ -14,10 +16,17 @@ const agent = new ProxyAgent(); * AWS SDK v3 doesn't have the concept of a global config like v2 did, so this * is it. * + * A region is set to {@link config.AWS_REGION}, which itself comes from the + * AWS_REGION environment variable or our own config file. It may be null, in + * which case the AWS SDK's logic for determining region is used and in + * practice that means the standard AWS config file. See + * {@link https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-region.html}. + * * HTTP and HTTPS agents are configured to use a proxy agent based on the * environment (e.g. http_proxy), if any. */ export const clientConfig = { + region: AWS_REGION, requestHandler: new NodeHttpHandler({ httpAgent: agent, httpsAgent: agent, diff --git a/src/config.js b/src/config.js index 7e679ed76..5db4bd8aa 100644 --- a/src/config.js +++ b/src/config.js @@ -127,6 +127,21 @@ function configPath(value) { } +/** + * AWS region to use for services where it's not otherwise specified. + * + * Currently, this should be the region where the S3 buckets live as the region + * for the Cognito user pool is embedded in its id. + * + * If unspecified, then the AWS SDK's own logic for determining region is used. + * In practice, that means the standard AWS config file (since the SDK also + * looks at the AWS_REGION environment variable). + * + * @type string + */ +export const AWS_REGION = fromEnvOrConfig("AWS_REGION", null); + + /** * Id of our Cognito user pool. *