Skip to content

Commit

Permalink
Configure passage API key in AWS environments (#59)
Browse files Browse the repository at this point in the history
* Add dependency for @aws-sdk/client-secrets-manager

* Add helper function for Passage API key retrieval

* Provide Passage API key ARN to Lambda environments

* Clarifying docstrings
  • Loading branch information
TylerHendrickson authored Jan 5, 2024
1 parent 44445ed commit 194bed8
Show file tree
Hide file tree
Showing 5 changed files with 344 additions and 0 deletions.
1 change: 1 addition & 0 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@aws-sdk/client-s3": "^3.472.0",
"@aws-sdk/client-secrets-manager": "^3.478.0",
"@aws-sdk/client-ses": "^3.470.0",
"@aws-sdk/client-sqs": "^3.470.0",
"@aws-sdk/client-ssm": "^3.462.0",
Expand Down
39 changes: 39 additions & 0 deletions api/src/lib/auth.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import {
SecretsManagerClient,
GetSecretValueCommand,
} from '@aws-sdk/client-secrets-manager'

import { Decoded } from '@redwoodjs/api'
import { AuthenticationError, ForbiddenError } from '@redwoodjs/graphql-server'

Expand Down Expand Up @@ -119,3 +124,37 @@ export const requireAuth = ({ roles }: { roles?: AllowedRoles } = {}) => {
throw new ForbiddenError("You don't have access to do that.")
}
}

/**
* Gets the Passage API key to use for authenticating Passage SDK calls.
*
* @param setEnv - If true, caches the Passage API key to $PASSAGE_API_KEY environment variable.
* @param force - If true, forces retrieval of the Passage API key from AWS Secrets Manager,
* even if the $PASSAGE_API_KEY environment variable is already set. This can be useful when
* the secret API key value has changed (e.g. due to rotation). If the value returned by this
* function is rejected by a subsequent Passage API operation, it may be worth calling this function
* once more with `force = true` to attempt to retrieve a more recent, valid key, instead of
* failing immediately.
*
* @returns The Passage API key
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function getPassageAPIKey(setEnv = true, force = false): Promise<string> {
if (process.env.PASSAGE_API_KEY && !force) {
// API key is already cached in env var
return process.env.PASSAGE_API_KEY
}

const client = new SecretsManagerClient()
const resp = await client.send(
new GetSecretValueCommand({
SecretId: process.env.PASSAGE_API_KEY_SECRET_ARN,
})
)

if (setEnv) {
process.env.PASSAGE_API_KEY = resp.SecretString
}

return resp.SecretString
}
6 changes: 6 additions & 0 deletions terraform/functions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ module "lambda_function-graphql" {
actions = ["kms:Decrypt"]
resources = [data.aws_kms_key.ssm.arn]
}
GetPassageAPIKeySecretValue = {
effect = "Allow"
actions = ["secretsmanager:GetSecretValue"]
resources = [data.aws_ssm_parameter.passage_api_key_secret_arn.value]
}
}

handler = var.datadog_enabled ? local.datadog_lambda_handler : "graphql.handler"
Expand Down Expand Up @@ -194,6 +199,7 @@ module "lambda_function-graphql" {
DATABASE_SECRET_SOURCE = "ssm"
DATABASE_SECRET_SSM_PARAMETER_PATH = aws_ssm_parameter.postgres_master_password.name
DD_LAMBDA_HANDLER = "graphql.handler"
PASSAGE_API_KEY_SECRET_ARN = data.aws_ssm_parameter.passage_api_key_secret_arn.value
})

allowed_triggers = {
Expand Down
4 changes: 4 additions & 0 deletions terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ data "aws_ssm_parameter" "datadog_api_key_secret_arn" {
name = "${var.ssm_deployment_parameters_path_prefix}/datadog/api_key_secret_arn"
}

data "aws_ssm_parameter" "passage_api_key_secret_arn" {
name = "${var.ssm_deployment_parameters_path_prefix}/passage/api_key_secret_arn"
}

module "this" {
source = "cloudposse/label/null"
version = "0.25.0"
Expand Down
Loading

0 comments on commit 194bed8

Please sign in to comment.