Skip to content

Commit

Permalink
secrets refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
coilysiren committed Oct 10, 2024
1 parent 9fdcccd commit 3f84d01
Show file tree
Hide file tree
Showing 15 changed files with 114 additions and 34 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,6 @@ dmypy.json

# vim
*.swp

# Terraform plan outputs
*.tfplan
17 changes: 11 additions & 6 deletions infra/api/app-config/env-config/environment-variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ locals {
# Configuration for secrets
# List of configurations for defining environment variables that pull from SSM parameter
# store. Configurations are of the format
# { name = "ENV_VAR_NAME", ssm_param_name = "/ssm/param/name" }
secrets = [
{
name = "API_AUTH_TOKEN"
ssm_param_name = "/api/${var.environment}/api-auth-token"
# {
# ENV_VAR_NAME = {
# manage_method = "generated" # or "manual" for a secret that was created and stored in SSM manually
# secret_store_name = "/ssm/param/name"
# }
# }
secrets = {
API_AUTH_TOKEN = {
manage_method = "manual"
secret_store_name = "/api/${var.environment}/api-auth-token"
}
]
}
}
2 changes: 1 addition & 1 deletion infra/api/app-config/env-config/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ output "service_config" {
var.service_override_extra_environment_variables
)

secrets = toset(local.secrets)
secrets = local.secrets
}
}

Expand Down
19 changes: 19 additions & 0 deletions infra/api/service/.terraform.lock.hcl

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

12 changes: 6 additions & 6 deletions infra/api/service/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,17 @@ module "service" {
name = secret_name
valueFrom = module.secrets[secret_name].secret_arn
}],
local.environment_config.search_config.has_search ? [{
local.environment_config.search_config != null ? [{
name = "SEARCH_USERNAME"
valueFrom = data.aws_ssm_parameter.search_username_arn.value
valueFrom = data.aws_ssm_parameter.search_username_arn[0].value
}] : [],
local.environment_config.search_config.has_search ? [{
local.environment_config.search_config != null ? [{
name = "SEARCH_PASSWORD"
valueFrom = data.aws_ssm_parameter.search_password_arn.value
valueFrom = data.aws_ssm_parameter.search_password_arn[0].value
}] : [],
local.environment_config.search_config.has_search ? [{
local.environment_config.search_config != null ? [{
name = "SEARCH_ENDPOINT"
valueFrom = data.aws_ssm_parameter.search_endpoint_arn.value
valueFrom = data.aws_ssm_parameter.search_endpoint_arn[0].value
}] : []
)
}
Expand Down
Binary file added infra/api/service/plan.out
Binary file not shown.
6 changes: 3 additions & 3 deletions infra/api/service/search.tf
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
data "aws_ssm_parameter" "search_username_arn" {
count = local.environment_config.search_config.has_search ? 1 : 0
count = local.environment_config.search_config != null ? 1 : 0
name = "/search/${local.prefix}${var.environment_name}/username"
}

data "aws_ssm_parameter" "search_password_arn" {
count = local.environment_config.search_config.has_search ? 1 : 0
count = local.environment_config.search_config != null ? 1 : 0
name = "/search/${local.prefix}${var.environment_name}/password"
}

data "aws_ssm_parameter" "search_endpoint_arn" {
count = local.environment_config.search_config.has_search ? 1 : 0
count = local.environment_config.search_config != null ? 1 : 0
name = "/search/${local.prefix}${var.environment_name}/endpoint"
}
16 changes: 16 additions & 0 deletions infra/api/service/secrets.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module "secrets" {
for_each = local.service_config.secrets

source = "../../modules/secret"

# When generating secrets and storing them in parameter store, append the
# terraform workspace to the secret store path if the environment is temporary
# to avoid conflicts with existing environments.
# Don't do this for secrets that are managed manually since the temporary
# environments will need to share those secrets.
secret_store_name = (each.value.manage_method == "generated" && local.is_temporary ?
"${each.value.secret_store_name}/${terraform.workspace}" :
each.value.secret_store_name
)
manage_method = each.value.manage_method
}
26 changes: 26 additions & 0 deletions infra/modules/secret/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
locals {
secret = var.manage_method == "generated" ? aws_ssm_parameter.secret[0] : data.aws_ssm_parameter.secret[0]
access_policy_name = "${trimprefix(replace(local.secret.name, "/", "-"), "/")}-access"
}

resource "random_password" "secret" {
count = var.manage_method == "generated" ? 1 : 0

length = 64
special = true
override_special = "!#$%&*()-_=+[]{}<>:?"
}

resource "aws_ssm_parameter" "secret" {
count = var.manage_method == "generated" ? 1 : 0

name = var.secret_store_name
type = "SecureString"
value = random_password.secret[0].result
}

data "aws_ssm_parameter" "secret" {
count = var.manage_method == "manual" ? 1 : 0

name = var.secret_store_name
}
3 changes: 3 additions & 0 deletions infra/modules/secret/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "secret_arn" {
value = local.secret.arn
}
22 changes: 22 additions & 0 deletions infra/modules/secret/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
variable "manage_method" {
type = string
description = <<EOT
Method to manage the secret. Options are 'manual' or 'generated'.
Set to 'generated' to generate a random secret.
Set to 'manual' to reference a secret that was manually created and stored in AWS parameter store.
Defaults to 'generated'."
EOT
default = "generated"
validation {
condition = can(regex("^(manual|generated)$", var.manage_method))
error_message = "Invalid manage_method. Must be 'manual' or 'generated'."
}
}

variable "secret_store_name" {
type = string
description = <<EOT
If manage_method is 'generated', path to store the secret in AWS parameter store.
If manage_method is 'manual', path to reference the secret in AWS parameter store.
EOT
}
2 changes: 1 addition & 1 deletion infra/modules/service/access-control.tf
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ data "aws_iam_policy_document" "task_executor" {
content {
sid = "SecretsAccess"
actions = ["ssm:GetParameters"]
resources = local.secret_arn_patterns
resources = [for secret in var.secrets : secret.valueFrom]
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion infra/modules/service/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ resource "aws_ecs_task_definition" "app" {
command = var.healthcheck_command
} : null,
environment = local.environment_variables,
secrets = local.secrets,
secrets = var.secrets,
portMappings = [
{
containerPort = var.container_port,
Expand Down
14 changes: 0 additions & 14 deletions infra/modules/service/secrets.tf

This file was deleted.

4 changes: 2 additions & 2 deletions infra/modules/service/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ variable "extra_environment_variables" {

variable "secrets" {
type = set(object({
name = string
ssm_param_name = string
name = string
valueFrom = string
}))
description = "List of configurations for defining environment variables that pull from SSM parameter store"
default = []
Expand Down

0 comments on commit 3f84d01

Please sign in to comment.