Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 0 additions & 6 deletions terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
136 changes: 70 additions & 66 deletions terraform/main.tf
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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,
])
}
}

Expand All @@ -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"
Expand All @@ -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]
}
}
5 changes: 0 additions & 5 deletions terraform/outputs.tf
Original file line number Diff line number Diff line change
@@ -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
}
Expand Down
41 changes: 1 addition & 40 deletions terraform/variables.tf
Original file line number Diff line number Diff line change
@@ -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" {
Expand All @@ -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
Expand All @@ -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
Expand Down