From e076878e2a19a8ff343e151268be503b72cff770 Mon Sep 17 00:00:00 2001 From: Jarrod Lowe <41766555+jarrod-lowe@users.noreply.github.com> Date: Sun, 11 Aug 2024 14:27:41 +1200 Subject: [PATCH] Create dynamodb table (#17) * Create dynamodb table * ddb table codacy ignores * ddb table codacy ignores --- .gitignore | 1 + Makefile | 11 ++ terraform/environment/aws/main.tf | 19 +-- terraform/environment/aws/policy.tf | 96 ++++++++++++ terraform/environment/aws/roles.tf | 200 +++++++++---------------- terraform/environment/aws/s3.tf | 48 +++--- terraform/environment/github/main.tf | 6 +- terraform/environment/wildsea/main.tf | 40 +++-- terraform/environment/wildsea/table.tf | 27 ++++ 9 files changed, 267 insertions(+), 181 deletions(-) create mode 100644 Makefile create mode 100644 terraform/environment/aws/policy.tf create mode 100644 terraform/environment/wildsea/table.tf diff --git a/.gitignore b/.gitignore index 9b8a46e6..93aff3e1 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ override.tf.json # Ignore CLI configuration files .terraformrc terraform.rc +.validate diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..8efbbfe5 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +default: all + +TERRAFORM_ENVIRONMENTS := aws github wildsea +TERRAFOM_VALIDATE := $(addsuffix /.validate,$(addprefix terraform/environment/, $(TERRAFORM_ENVIRONMENTS))) + +all: $(TERRAFOM_VALIDATE) + +terraform/environment/%/.validate: terraform/environment/%/*.tf + cd terraform/environment/$* ; terraform fmt + cd terraform/environment/$* ; terraform validate + touch $@ diff --git a/terraform/environment/aws/main.tf b/terraform/environment/aws/main.tf index d95a9f8c..d647b3d1 100644 --- a/terraform/environment/aws/main.tf +++ b/terraform/environment/aws/main.tf @@ -1,12 +1,13 @@ data "aws_partition" "current" {} data "aws_caller_identity" "current" {} +data "aws_region" "current" {} variable "app_name" { - default = "Wildsea" + default = "Wildsea" } variable "action_prefix" { - default = "GitHubAction" + default = "GitHubAction" } variable "workspace" { @@ -32,15 +33,15 @@ variable "environment" { } terraform { - backend "s3" { - // region, bucket and key come from -backend-config - } + backend "s3" { + // region, bucket and key come from -backend-config + } } provider "aws" { - default_tags { - tags = { - Application = "Wildsea-setup-${var.environment}" - } + default_tags { + tags = { + Application = "Wildsea-setup-${var.environment}" } + } } diff --git a/terraform/environment/aws/policy.tf b/terraform/environment/aws/policy.tf new file mode 100644 index 00000000..86034a89 --- /dev/null +++ b/terraform/environment/aws/policy.tf @@ -0,0 +1,96 @@ +data "aws_iam_policy_document" "ro" { + statement { + sid = "ReadState" + actions = [ + "s3:GetObject" + ] + resources = [ + "${aws_s3_bucket.state.arn}/${var.environment}/terraform.tfstate" + ] + } + + statement { + sid = "ListState" + actions = [ + "s3:ListBucket" + ] + resources = [ + aws_s3_bucket.state.arn + ] + } + + statement { + sid = "Dynamodb" + actions = [ + "dynamodb:DescribeTable*" + ] + resources = [ + "arn:${data.aws_partition.current.id}:dynamodb:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:table/${var.app_name}-${var.environment}" + ] + } +} + +data "aws_iam_policy_document" "rw" { + statement { + sid = "WriteState" + actions = [ + "s3:PutObject" + ] + resources = [ + "${aws_s3_bucket.state.arn}/${var.environment}/terraform.tfstate" + ] + } + + statement { + sid = "Dynamodb" + actions = [ + "dynamodb:CreateTable", + "dynamodb:DeleteTable", + ] + resources = [ + "arn:${data.aws_partition.current.id}:dynamodb:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:table/${var.app_name}-${var.environment}" + ] + } +} + +data "aws_iam_policy_document" "rw_boundary" { + statement { + sid = "s3" + actions = [ + "s3:GetObject", + "s3:PutObject" + ] + resources = [ + "${aws_s3_bucket.state.arn}/${var.environment}/terraform.tfstate", + "arn:${data.aws_partition.current.id}:s3:::${var.app_name}-${var.environment}-*/*" + ] + } + + statement { + sid = "ListState" + actions = [ + "s3:ListBucket" + ] + resources = [ + "arn:${data.aws_partition.current.id}:s3:::${var.app_name}-${var.environment}-*/*" + ] + } + + statement { + sid = "Dynamodb" + actions = [ + "dynamodb:DescribeTable", + "dynamodb:CreateTable", + "dynamodb:DeleteTable", + "dynamodb:BatchGet*", + "dynamodb:GetItem", + "dynamodb:Query", + "dynamodb:DeleteItem", + "dynamodb:UpdateItem*", + "dynamodb:PutItem*", + ] + resources = [ + "arn:${data.aws_partition.current.id}:dynamodb:${data.aws_region.current.id}:${data.aws_caller_identity.current.account_id}:table/${var.app_name}-${var.environment}" + ] + } +} diff --git a/terraform/environment/aws/roles.tf b/terraform/environment/aws/roles.tf index 056cc91a..22c395ef 100644 --- a/terraform/environment/aws/roles.tf +++ b/terraform/environment/aws/roles.tf @@ -1,168 +1,110 @@ resource "aws_iam_openid_connect_provider" "oidc" { - url = "https://token.actions.githubusercontent.com" - client_id_list = [ - "sts.${data.aws_partition.current.dns_suffix}" - ] - thumbprint_list = [ - "d89e3bd43d5d909b47a18977aa9d5ce36cee184c" - ] + url = "https://token.actions.githubusercontent.com" + client_id_list = [ + "sts.${data.aws_partition.current.dns_suffix}" + ] + thumbprint_list = [ + "d89e3bd43d5d909b47a18977aa9d5ce36cee184c" + ] } resource "aws_iam_role" "ro" { - name = "${var.action_prefix}-${var.app_name}-ro-${var.environment}" - assume_role_policy = data.aws_iam_policy_document.ro_assume.json + name = "${var.action_prefix}-${var.app_name}-ro-${var.environment}" + assume_role_policy = data.aws_iam_policy_document.ro_assume.json - tags = { - Name = "${var.action_prefix}-${var.app_name}-ro-${var.environment}" - } + tags = { + Name = "${var.action_prefix}-${var.app_name}-ro-${var.environment}" + } } data "aws_iam_policy_document" "ro_assume" { - statement { - actions = ["sts:AssumeRoleWithWebIdentity"] - principals { - type = "Federated" - identifiers = [ aws_iam_openid_connect_provider.oidc.arn ] - } - condition { - test = "StringEquals" - variable = "token.actions.githubusercontent.com:aud" - values = ["sts.${data.aws_partition.current.dns_suffix}"] - } - condition { - test = "StringEquals" - variable = "token.actions.githubusercontent.com:sub" - values = ["repo:${var.workspace}/${var.repo}:environment:${var.environment}-ro"] - } + statement { + actions = ["sts:AssumeRoleWithWebIdentity"] + principals { + type = "Federated" + identifiers = [aws_iam_openid_connect_provider.oidc.arn] + } + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:aud" + values = ["sts.${data.aws_partition.current.dns_suffix}"] + } + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:sub" + values = ["repo:${var.workspace}/${var.repo}:environment:${var.environment}-ro"] } + } } resource "aws_iam_policy" "ro" { - name = aws_iam_role.ro.name - policy = data.aws_iam_policy_document.ro.json + name = aws_iam_role.ro.name + policy = data.aws_iam_policy_document.ro.json - tags = { - Name = aws_iam_role.ro.name - } + tags = { + Name = aws_iam_role.ro.name + } } resource "aws_iam_role_policy_attachment" "ro-ro" { - role = aws_iam_role.ro.name - policy_arn = aws_iam_policy.ro.arn -} - -data "aws_iam_policy_document" "ro" { - statement { - sid = "ReadState" - actions = [ - "s3:GetObject" - ] - resources = [ - "${aws_s3_bucket.state.arn}/${var.environment}/terraform.tfstate" - ] - } - - statement { - sid = "ListState" - actions = [ - "s3:ListBucket" - ] - resources = [ - aws_s3_bucket.state.arn - ] - } + role = aws_iam_role.ro.name + policy_arn = aws_iam_policy.ro.arn } resource "aws_iam_role" "rw" { - name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}" - assume_role_policy = data.aws_iam_policy_document.rw_assume.json - permissions_boundary = aws_iam_policy.rw_boundary.arn + name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}" + assume_role_policy = data.aws_iam_policy_document.rw_assume.json + permissions_boundary = aws_iam_policy.rw_boundary.arn - tags = { - Name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}" - } + tags = { + Name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}" + } } data "aws_iam_policy_document" "rw_assume" { - statement { - actions = ["sts:AssumeRoleWithWebIdentity"] - principals { - type = "Federated" - identifiers = [ aws_iam_openid_connect_provider.oidc.arn ] - } - condition { - test = "StringEquals" - variable = "token.actions.githubusercontent.com:aud" - values = ["sts.${data.aws_partition.current.dns_suffix}"] - } - condition { - test = "StringEquals" - variable = "token.actions.githubusercontent.com:sub" - values = ["repo:${var.workspace}/${var.repo}:environment:${var.environment}-rw"] - } + statement { + actions = ["sts:AssumeRoleWithWebIdentity"] + principals { + type = "Federated" + identifiers = [aws_iam_openid_connect_provider.oidc.arn] + } + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:aud" + values = ["sts.${data.aws_partition.current.dns_suffix}"] } + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:sub" + values = ["repo:${var.workspace}/${var.repo}:environment:${var.environment}-rw"] + } + } } resource "aws_iam_policy" "rw" { - name = aws_iam_role.rw.name - policy = data.aws_iam_policy_document.rw.json + name = aws_iam_role.rw.name + policy = data.aws_iam_policy_document.rw.json - tags = { - Name = aws_iam_role.rw.name - } + tags = { + Name = aws_iam_role.rw.name + } } resource "aws_iam_role_policy_attachment" "rw-ro" { - role = aws_iam_role.rw.name - policy_arn = aws_iam_policy.ro.arn + role = aws_iam_role.rw.name + policy_arn = aws_iam_policy.ro.arn } resource "aws_iam_role_policy_attachment" "rw-rw" { - role = aws_iam_role.rw.name - policy_arn = aws_iam_policy.rw.arn -} - -data "aws_iam_policy_document" "rw" { - statement { - sid = "WriteState" - actions = [ - "s3:PutObject" - ] - resources = [ - "${aws_s3_bucket.state.arn}/${var.environment}/terraform.tfstate" - ] - } + role = aws_iam_role.rw.name + policy_arn = aws_iam_policy.rw.arn } resource "aws_iam_policy" "rw_boundary" { - name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}-boundary" - policy = data.aws_iam_policy_document.rw_boundary.json + name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}-boundary" + policy = data.aws_iam_policy_document.rw_boundary.json - tags = { - Name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}-boundary" - } -} - -data "aws_iam_policy_document" "rw_boundary" { - statement { - sid = "s3" - actions = [ - "s3:GetObject", - "s3:PutObject" - ] - resources = [ - "${aws_s3_bucket.state.arn}/${var.environment}/terraform.tfstate", - "arn:${data.aws_partition.current.id}:s3:::${var.app_name}-${var.environment}-*/*" - ] - } - - statement { - sid = "ListState" - actions = [ - "s3:ListBucket" - ] - resources = [ - aws_s3_bucket.state.arn - ] - } + tags = { + Name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}-boundary" + } } diff --git a/terraform/environment/aws/s3.tf b/terraform/environment/aws/s3.tf index fc107e38..9a2ac0c9 100644 --- a/terraform/environment/aws/s3.tf +++ b/terraform/environment/aws/s3.tf @@ -1,35 +1,35 @@ import { - to = aws_s3_bucket.state - id = var.state_bucket + to = aws_s3_bucket.state + id = var.state_bucket } resource "aws_s3_bucket" "state" { - # checkov:skip=CKV_AWS_18:Access logging is overkill for us - # checkov:skip=CKV_AWS_144:Cross-Region replication not required - # checkov:skip=CKV2_AWS_62:Event notifications not required - # checkov:skip=CKV_AWS_145:AWS Key is sufficient - bucket = "terraform-state-${data.aws_caller_identity.current.account_id}" - force_destroy = false - - tags = { - Name = "terraform-state-${data.aws_caller_identity.current.account_id}" - } + # checkov:skip=CKV_AWS_18:Access logging is overkill for us + # checkov:skip=CKV_AWS_144:Cross-Region replication not required + # checkov:skip=CKV2_AWS_62:Event notifications not required + # checkov:skip=CKV_AWS_145:AWS Key is sufficient + bucket = "terraform-state-${data.aws_caller_identity.current.account_id}" + force_destroy = false + + tags = { + Name = "terraform-state-${data.aws_caller_identity.current.account_id}" + } } resource "aws_s3_bucket_lifecycle_configuration" "state" { - bucket = aws_s3_bucket.state.id - depends_on = [ aws_s3_bucket_versioning.state ] - - rule { - id = "clean" - noncurrent_version_expiration { - noncurrent_days = 30 - } - abort_incomplete_multipart_upload { - days_after_initiation = 7 - } - status = "Enabled" + bucket = aws_s3_bucket.state.id + depends_on = [aws_s3_bucket_versioning.state] + + rule { + id = "clean" + noncurrent_version_expiration { + noncurrent_days = 30 } + abort_incomplete_multipart_upload { + days_after_initiation = 7 + } + status = "Enabled" + } } resource "aws_s3_bucket_public_access_block" "state" { diff --git a/terraform/environment/github/main.tf b/terraform/environment/github/main.tf index b7362d6f..1e28527d 100644 --- a/terraform/environment/github/main.tf +++ b/terraform/environment/github/main.tf @@ -47,9 +47,9 @@ variable "environment" { } terraform { - backend "s3" { - // region, bucket and key come from -backend-config - } + backend "s3" { + // region, bucket and key come from -backend-config + } } provider "github" { diff --git a/terraform/environment/wildsea/main.tf b/terraform/environment/wildsea/main.tf index 4b1419dc..ee702487 100644 --- a/terraform/environment/wildsea/main.tf +++ b/terraform/environment/wildsea/main.tf @@ -1,32 +1,40 @@ -resource "null_resource" "test" {} - variable "aws_account" { - description = "ID of the AWS Account" - type = string - sensitive = true + description = "ID of the AWS Account" + type = string + sensitive = true } variable "aws_region" { - description = "AWS Region name" - type = string - sensitive = true + description = "AWS Region name" + type = string + sensitive = true } variable "state_bucket" { - description = "Name of the S3 state bucket" - type = string + description = "Name of the S3 state bucket" + type = string } variable "environment" { - description = "Name of the Environment" - type = string + description = "Name of the Environment" + type = string +} + +locals { + app_name = "Wildsea" + prefix = "${local.app_name}-${var.environment}" } terraform { - backend "s3" { - // region, bucket and key come from -backend-config - } + backend "s3" { + // region, bucket and key come from -backend-config + } } provider "aws" { -} \ No newline at end of file + default_tags { + tags = { + Application = local.prefix + } + } +} diff --git a/terraform/environment/wildsea/table.tf b/terraform/environment/wildsea/table.tf new file mode 100644 index 00000000..1f88ceae --- /dev/null +++ b/terraform/environment/wildsea/table.tf @@ -0,0 +1,27 @@ +# nosemgrep: aws-dynamodb-table-unencrypted // AWS Key is fine +resource "aws_dynamodb_table" "table" { + # checkov:skip=CKV_AWS_119:AWS Key is fine + name = local.prefix + billing_mode = "PAY_PER_REQUEST" + deletion_protection_enabled = true + hash_key = "PK" + range_key = "SK" + + attribute { + name = "PK" + type = "S" + } + + attribute { + name = "SK" + type = "S" + } + + point_in_time_recovery { + enabled = true + } + + tags = { + Name = local.prefix + } +}