From 53459fa99585294fac4db7c5f53cc5c135cb44de Mon Sep 17 00:00:00 2001 From: Patrick de Ruiter Date: Thu, 22 Jul 2021 15:09:25 +0200 Subject: [PATCH] first commit --- .gitignore | 15 ++++++++++ README.md | 6 ++++ iam.tf | 68 ++++++++++++++++++++++++++++++++++++++++++ main.tf | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++ outputs.tf | 8 +++++ variables.tf | 17 +++++++++++ versions.tf | 13 ++++++++ 7 files changed, 210 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 iam.tf create mode 100644 main.tf create mode 100644 outputs.tf create mode 100644 variables.tf create mode 100644 versions.tf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13f63cb --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +**/.idea +**/*.iml + +**/.build-harness +**/build-harness + +# Rendered yaml config +**/configmap-auth.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..97bc2dc --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# S3 Backend Module +This module will deply an s3 remote backend for Terraform + +Locking is handled by a serverless provisioned DynamoDB Table +All contents of the s3 bucket is encrypted via a KMS key and privileges are set in such a way that it only has the least ammount of privileges. + diff --git a/iam.tf b/iam.tf new file mode 100644 index 0000000..7595da3 --- /dev/null +++ b/iam.tf @@ -0,0 +1,68 @@ +data "aws_caller_identity" "current" {} + +locals { + principal_arns = var.pricipal_arns != null ? var.principal_arns : [data.aws_caller_identity.current.arn] +} + +resource "aws_iam_role" "iam_role" { + name = "${local.namespace}-tf-assume-role" + + assume_role_policy = <<-EOF + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Principal": { + "AWS": ${jsonencode(local.principal_arns)} + }, + "Effect": "Allow" + } + ] + } + EOF + + tags = { + ResourceGroup = local.namespace + } +} + +data "aws_iam_policy_document" "policy_doc" { + statement { + actions = [ + "s3:ListBucket", + ] + + resources = [ + aws_s3_bucket.s3_bucket.arn + ] + } + + statement { + actions = ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"] + + resources = [ + "${aws_s3_bucket.s3_bucket.arn}/*", + ] + } + + statement { + actions = [ + "dynamodb:GetItem", + "dynamodb:PutItem", + "dynamodb:DeleteItem" + ] + resources = [aws_dynamodb_table.dynamodb_table.arn] + } +} + +resource "aws_iam_policy" "iam_policy" { + name = "${local.namespace}-tf-policy" + path = "/" + policy = data.aws_iam_policy_document.policy_doc.json +} + +resource "aws_iam_role_policy_attachement" "policy_attach" { + role = aws_iam_role.iam_role.name + policy_arn = aws_iam_policy.iam_policy.arn +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..af02f7b --- /dev/null +++ b/main.tf @@ -0,0 +1,83 @@ +data "aws_region" "current" {} + +resource "random_string" "rand" { + lenth = 24 + special = false + upper = false +} + +locals { + namespace = substr(join("-", [var.namespace, random_string.rand.result]), 0, 24) +} + +resource "aws_resourcegroups_group" "resourcegroups_group" { + name = "${local.namespace}-group" + + resource_query { + query = <<-JSON + { + "ResourceeTypeFilters": [ + "AWS::AllSupported" + ], + "TagFilters": [ + { + "Key": "ResourceGroup", + "Values": ["${locsal.namespace}"] + } + ] + } + JSON + } +} + +resource "aws_kms_key" "kms_key" { + tags = { + ResourceGroup = local.namespace + } +} + +resource "aws_s3_bucket" "s3_bucket" { + bucket = "${local.namespace}-state-bucket" + force_destroy = var.force_destroy_state + + versioning { + enabled = true + } + + server_side_encryption_configuration { + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "aws:kms" + kms_master_key_id = aws_kms_key.kms_key.arn + } + } + } + + tags = { + ResourceGroup = local.namespace + } +} + + +resource "aws_s3_bucket_public_access_block" "s3_bucket" { + bucket = aws_s3_bucket.s3_bucket.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_dynamodb_table" "dynamodb_table" { + name = "${local.namespace}-state-lock" + hash_key = "LockID" + billing_mode = "PAY_PER_REQUEST" + attribute { + name = "LockID" + type = "S" + } + + tags = { + ResourceGroup = local.namespace + } +} diff --git a/outputs.tf b/outputs.tf new file mode 100644 index 0000000..d3125e5 --- /dev/null +++ b/outputs.tf @@ -0,0 +1,8 @@ +output "config" { + value = { + bucket = aws_s3_bucket.s3_bucket.bucket + region = data.aws_region.current.name + role_arn = aws_iam_role.iam_role.arn + dynamodb_table = aws_dynamodb_table.dynamodb_table.name + } +} diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..aac9194 --- /dev/null +++ b/variables.tf @@ -0,0 +1,17 @@ +variable "namespace" { + description = "The project namespace to use for unique resource naming" + default = "s3backend" + type = string +} + +variable "principle_arns" { + description = "A list of peincipal arns allowed to assume the IAM role" + default = null + type = list(string) +} + +variable "force_destroy_state" { + description = "Force destroy the s3 bucket containing state files?" + default = true + type = bool +} diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..8aa0f9d --- /dev/null +++ b/versions.tf @@ -0,0 +1,13 @@ +terraform { + required_version = ">= 0.15" + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 3.28" + } + random = { + source = "hashicorp/random" + version = "~> 3.0" + } + } +}