diff --git a/terraform/README.md b/terraform/README.md index 832c5b4..f3e9551 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -10,9 +10,3 @@ Terraform is responsible to: - Create IAM user for CDK to manage AWS resources - Create IAM role for Lambda function to assume and run as - Create DynamoDB tables - -### Note about DynamoDB tables -This repo is coded in a way to create the necessary tables and use the default names based on `app_name` and -`app_env`. However, if this is being deployed into an environment with existing tables, the table names can be -overwritten using the `api_key_table`, `totp_table`, and `webauthn_table` variables, as well as the -`create_api_key_table`, `create_totp_key_table`, and `create_webauthn_table` variables set to `false`. diff --git a/terraform/main.tf b/terraform/main.tf index 601e3b9..1ece7bd 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -1,42 +1,37 @@ locals { stage_for_api = var.app_env == "dev" ? var.app_env : var.app_environment api_name = "${var.app_name}-${local.stage_for_api}" + aws_account = data.aws_caller_identity.this.account_id } -/* - * Module docs: https://registry.terraform.io/modules/silinternational/serverless-user/aws/latest - * Create IAM user with permissions to create lambda function, API gateway, etc. -*/ -module "serverless-user" { - source = "silinternational/serverless-user/aws" - version = "~> 0.4.2" - - app_name = "${var.app_name}-${var.app_env}" - aws_region_policy = "*" - enable_api_gateway = true - extra_policies = [jsonencode({ +data "aws_caller_identity" "this" {} + +# CDK IAM user +resource "aws_iam_user" "cdk" { + name = "${var.app_name}-cdk" +} + +resource "aws_iam_access_key" "cdk" { + user = aws_iam_user.cdk.name +} + +resource "aws_iam_policy" "cdk" { + name = "${var.app_name}-cdk" + description = "CDK deployment policy" + + policy = jsonencode({ Version = "2012-10-17" - Statement = [ - { - Effect = "Allow" - Action = [ - "sts:AssumeRole", - ] - Resource = "arn:aws:iam::*:role/cdk-*" - }, - { - Effect = "Allow" - Action = [ - "ec2:CreateTags", - "ec2:DeleteTags", - "iam:getRolePolicy", - "logs:FilterLogEvents", - "apigateway:UpdateRestApiPolicy", - ] - Resource = "*" - } - ] - })] + Statement = [{ + Effect = "Allow" + Action = "sts:AssumeRole" + Resource = "arn:aws:iam::*:role/cdk-*" + }] + }) +} + +resource "aws_iam_user_policy_attachment" "cdk" { + user = aws_iam_user.cdk.name + policy_arn = aws_iam_policy.cdk.arn } // Set up custom domain name for easier fail-over. @@ -73,23 +68,17 @@ resource "aws_iam_role" "lambdaRole" { }) } -locals { - api_key_table = try(var.api_key_table, one(aws_dynamodb_table.apiKeyTable[*].name)) - totp_table = try(var.totp_table, one(aws_dynamodb_table.totp[*].name)) - webauthn_table = try(var.webauthn_table, one(aws_dynamodb_table.webauthnTable[*].name)) -} - data "template_file" "lambdaRolePolicy" { template = file("${path.module}/lambda-role-policy.json") vars = { - aws_account = var.aws_account_id + aws_account = local.aws_account app_name = var.app_name app_env = var.app_env - table_arns = join(",", compact([ - local.api_key_table == null ? null : "\"arn:aws:dynamodb:*:${var.aws_account_id}:table/${local.api_key_table}\"", - local.webauthn_table == null ? null : "\"arn:aws:dynamodb:*:${var.aws_account_id}:table/${local.webauthn_table}\"", - local.totp_table == null ? null : "\"arn:aws:dynamodb:*:${var.aws_account_id}:table/${local.totp_table}\"", - ])) + table_arns = join(",", [ + aws_dynamodb_table.api_key.arn, + aws_dynamodb_table.totp.arn, + aws_dynamodb_table.webauthn.arn, + ]) } } @@ -99,30 +88,36 @@ resource "aws_iam_role_policy" "lambdaRolePolicy" { policy = data.template_file.lambdaRolePolicy.rendered } -// Create DynamoDB tables -resource "aws_dynamodb_table" "apiKeyTable" { - count = var.create_api_key_table ? 1 : 0 - name = "${var.app_name}-${var.app_env}-api-key" - billing_mode = "PAY_PER_REQUEST" - hash_key = "value" +// DynamoDB tables +resource "aws_dynamodb_table" "api_key" { + name = "mfa-api_${var.app_env}_api-key_global" + billing_mode = "PAY_PER_REQUEST" + hash_key = "value" + deletion_protection_enabled = true + stream_enabled = true attribute { name = "value" type = "S" } - tags = { - app_name = var.app_name - app_env = var.app_env + point_in_time_recovery { + enabled = true + } + + replica { + region_name = var.aws_region_secondary + } + + lifecycle { + ignore_changes = [replica] } } resource "aws_dynamodb_table" "totp" { - count = var.create_totp_table ? 1 : 0 - - name = "${var.app_name}_${var.app_env}_totp_global" - hash_key = "uuid" + name = "mfa-api_${var.app_env}_totp_global" billing_mode = "PAY_PER_REQUEST" + hash_key = "uuid" deletion_protection_enabled = true stream_enabled = true stream_view_type = "NEW_IMAGE" @@ -145,19 +140,28 @@ resource "aws_dynamodb_table" "totp" { } } -resource "aws_dynamodb_table" "webauthnTable" { - count = var.create_webauthn_table ? 1 : 0 - name = "${var.app_name}-${var.app_env}-webauthn" - billing_mode = "PAY_PER_REQUEST" - hash_key = "uuid" +resource "aws_dynamodb_table" "webauthn" { + name = "mfa-api_${var.app_env}_u2f_global" + hash_key = "uuid" + billing_mode = "PAY_PER_REQUEST" + deletion_protection_enabled = true + stream_enabled = true + stream_view_type = "NEW_IMAGE" attribute { name = "uuid" type = "S" } - tags = { - app_name = var.app_name - app_env = var.app_env + point_in_time_recovery { + enabled = true + } + + replica { + region_name = var.aws_region_secondary + } + + lifecycle { + ignore_changes = [replica] } } diff --git a/terraform/outputs.tf b/terraform/outputs.tf index db863d8..08f4dc7 100644 --- a/terraform/outputs.tf +++ b/terraform/outputs.tf @@ -1,8 +1,3 @@ -output "serverless_user_key_secret" { - value = "${module.serverless-user.aws_access_key_id},${module.serverless-user.aws_secret_access_key}" - sensitive = true -} - output "lambda_role_arn" { value = aws_iam_role.lambdaRole.arn } diff --git a/terraform/variables.tf b/terraform/variables.tf index d51077d..ddca815 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -1,7 +1,7 @@ variable "app_name" { type = string description = "A short name for this application, example: backup-service" - default = "serverless-mfa-api-go" + default = "twosv-api" } variable "app_env" { @@ -14,11 +14,6 @@ variable "aws_access_key_id" { description = "Access Key ID for user with permissions to create resources for CDK" } -variable "aws_account_id" { - type = string - description = "AWS Account ID for use in IAM policy resource references" -} - variable "aws_region" { description = "Primary AWS region where this lambda will be deployed" type = string @@ -34,40 +29,6 @@ variable "aws_secret_access_key" { description = "Secret access Key ID for user with permissions to create resources for CDK" } -variable "api_key_table" { - type = string - description = "Override api key table name" - default = "" -} - -variable "create_api_key_table" { - type = bool - default = true -} - -variable "totp_table" { - description = "Override totp table name" - type = string - default = null -} - -variable "create_totp_table" { - description = "enable the creation of a DynamoDB table for TOTP credentials" - type = bool - default = false -} - -variable "webauthn_table" { - type = string - description = "Override webauthn table name" - default = "" -} - -variable "create_webauthn_table" { - type = bool - default = true -} - variable "cloudflare_token" { description = "The Cloudflare limited access API token" type = string