From 01758c7ff77d3a1b69054c9d287ebdfbfe70f19d Mon Sep 17 00:00:00 2001 From: Daniel Pham Date: Thu, 16 Jan 2025 20:20:57 +0700 Subject: [PATCH 1/6] feat: add tf modules and dev environment --- backend/main.tf | 188 ++++++++++++ backend/outputs.tf | 14 + backend/variables.tf | 19 ++ env/dev/backend.tf | 21 ++ env/dev/main.tf | 120 ++++++++ env/dev/outputs.tf | 34 +++ env/dev/variables.tf | 131 ++++++++ modules/bastion/main.tf | 60 ++++ modules/bastion/outputs.tf | 9 + modules/bastion/variables.tf | 45 +++ modules/ecr/main.tf | 69 +++++ modules/ecr/outputs.tf | 4 + modules/ecr/variables.tf | 24 ++ modules/eks-access/main.tf | 22 ++ modules/eks-access/outputs.tf | 14 + modules/eks-access/variables.tf | 34 +++ modules/eks/main.tf | 492 ++++++++++++++++++++++++++++++ modules/eks/outputs.tf | 34 +++ modules/eks/variables.tf | 81 +++++ modules/kms/main.tf | 87 ++++++ modules/kms/outputs.tf | 9 + modules/kms/variables.tf | 14 + modules/ssm/main.tf | 27 ++ modules/ssm/outputs.tf | 14 + modules/ssm/variables.tf | 9 + modules/vpc-endpoint/main.tf | 221 ++++++++++++++ modules/vpc-endpoint/outputs.tf | 88 ++++++ modules/vpc-endpoint/variables.tf | 40 +++ modules/vpc/main.tf | 151 +++++++++ modules/vpc/outputs.tf | 29 ++ modules/vpc/variables.tf | 34 +++ templates/bootstrap.sh.tpl | 10 + templates/nodeadm.yml.tpl | 17 ++ 33 files changed, 2165 insertions(+) create mode 100644 backend/main.tf create mode 100644 backend/outputs.tf create mode 100644 backend/variables.tf create mode 100644 env/dev/backend.tf create mode 100644 env/dev/main.tf create mode 100644 env/dev/outputs.tf create mode 100644 env/dev/variables.tf create mode 100644 modules/bastion/main.tf create mode 100644 modules/bastion/outputs.tf create mode 100644 modules/bastion/variables.tf create mode 100644 modules/ecr/main.tf create mode 100644 modules/ecr/outputs.tf create mode 100644 modules/ecr/variables.tf create mode 100644 modules/eks-access/main.tf create mode 100644 modules/eks-access/outputs.tf create mode 100644 modules/eks-access/variables.tf create mode 100644 modules/eks/main.tf create mode 100644 modules/eks/outputs.tf create mode 100644 modules/eks/variables.tf create mode 100644 modules/kms/main.tf create mode 100644 modules/kms/outputs.tf create mode 100644 modules/kms/variables.tf create mode 100644 modules/ssm/main.tf create mode 100644 modules/ssm/outputs.tf create mode 100644 modules/ssm/variables.tf create mode 100644 modules/vpc-endpoint/main.tf create mode 100644 modules/vpc-endpoint/outputs.tf create mode 100644 modules/vpc-endpoint/variables.tf create mode 100644 modules/vpc/main.tf create mode 100644 modules/vpc/outputs.tf create mode 100644 modules/vpc/variables.tf create mode 100644 templates/bootstrap.sh.tpl create mode 100644 templates/nodeadm.yml.tpl diff --git a/backend/main.tf b/backend/main.tf new file mode 100644 index 0000000..aff6fdb --- /dev/null +++ b/backend/main.tf @@ -0,0 +1,188 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.83.1" + } + } + + backend "s3" { + bucket = "devopslite-tf-state" + key = "s3-backend/terraform.tfstate" + region = "us-east-1" + encrypt = true + dynamodb_table = "devopslite-tf-state" + } +} + +provider "aws" { + region = "us-east-1" +} + +data "aws_caller_identity" "current" {} + +resource "aws_s3_bucket" "tf_state_bucket" { + # checkov:skip=CKV2_AWS_62: "Ensure S3 buckets should have event notifications enabled" + # checkov:skip=CKV2_AWS_61: "Ensure that an S3 bucket has a lifecycle configuration" + # checkov:skip=CKV_AWS_144: "Ensure that S3 bucket has cross-region replication enabled" + # checkov:skip=CKV_AWS_18: "Ensure the S3 bucket has access logging enabled" + bucket = "${var.project}-tf-state" + force_destroy = true + + tags = merge( + var.default_tags, + { + Name = "${var.project}-tf-state" + } + ) +} + +resource "aws_s3_bucket_public_access_block" "tf_bucket_public_access_block" { + bucket = aws_s3_bucket.tf_state_bucket.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_ownership_controls" "tf_bucket_ownership_controls" { + depends_on = [ + aws_s3_bucket.tf_state_bucket + ] + + bucket = aws_s3_bucket.tf_state_bucket.id + + rule { + object_ownership = "BucketOwnerEnforced" + } +} + +resource "aws_s3_bucket_versioning" "tf_bucket_versioning" { + bucket = aws_s3_bucket.tf_state_bucket.id + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "tf_bucket_encryption" { + bucket = aws_s3_bucket.tf_state_bucket.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "aws:kms" + kms_master_key_id = aws_kms_key.tf_kms_key.arn + } + } +} + +resource "aws_kms_key" "tf_kms_key" { + description = "The KMS key is used to encrypt the S3 bucket as a backend for terraform" + enable_key_rotation = true + deletion_window_in_days = 7 + + tags = merge( + var.default_tags, + { + Name = "${var.project}-tf-state-key" + Bucket = aws_s3_bucket.tf_state_bucket.arn + } + ) +} + +resource "aws_kms_alias" "tf_kms_key_alias" { + name = "alias/${var.project}-${var.region}-kms-key" + target_key_id = aws_kms_key.tf_kms_key.key_id +} + +resource "aws_kms_key_policy" "tf_kms_key_policy" { + key_id = aws_kms_key.tf_kms_key.key_id + + policy = jsonencode({ + Version = "2012-10-17" + Id = "key-default-1" + Statement = [ + { + Sid = "Enable IAM User Permissions" + Effect = "Allow" + Principal = { + AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + }, + Action = "kms:*" + Resource = "*" + }, + { + Sid = "Allow administration of the key" + Effect = "Allow" + Principal = { + AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/cloud_user" + }, + Action = [ + "kms:ReplicateKey", + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ], + Resource = "*" + }, + { + Sid = "Allow use of the key" + Effect = "Allow" + Principal = { + AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/cloud_user", + Service = [ + "s3.amazonaws.com", + "dynamodb.amazonaws.com" + ] + }, + Action = [ + "kms:DescribeKey", + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey", + "kms:GenerateDataKeyWithoutPlaintext" + ], + Resource = "*" + } + ] + }) +} + +resource "aws_dynamodb_table" "terraform_dynamodb_table" { + name = "${var.project}-tf-state" + hash_key = "LockID" + billing_mode = "PAY_PER_REQUEST" + + attribute { + name = "LockID" + type = "S" + } + + point_in_time_recovery { + enabled = true + } + + server_side_encryption { + enabled = true + kms_key_arn = aws_kms_key.tf_kms_key.arn + } + + tags = merge( + var.default_tags, + { + Name = "${var.project}-tf-state" + Bucket = aws_s3_bucket.tf_state_bucket.arn + } + ) +} diff --git a/backend/outputs.tf b/backend/outputs.tf new file mode 100644 index 0000000..6948ed2 --- /dev/null +++ b/backend/outputs.tf @@ -0,0 +1,14 @@ +output "bucket_name" { + description = "S3 bucket name" + value = aws_s3_bucket.tf_state_bucket.bucket +} + +output "bucket_arn" { + description = "S3 bucket ARN" + value = aws_s3_bucket.tf_state_bucket.arn +} + +output "dynamodb_name" { + description = "DynamoDB name" + value = aws_dynamodb_table.terraform_dynamodb_table.name +} diff --git a/backend/variables.tf b/backend/variables.tf new file mode 100644 index 0000000..9791758 --- /dev/null +++ b/backend/variables.tf @@ -0,0 +1,19 @@ +variable "region" { + description = "AWS region" + default = "us-east-1" + type = string +} + +variable "project" { + description = "The project name to use for unique resource naming" + default = "devopslite" + type = string +} + +variable "default_tags" { + type = map(string) + default = { + Provisioner = "terraform" + Project = "devopslite" + } +} diff --git a/env/dev/backend.tf b/env/dev/backend.tf new file mode 100644 index 0000000..3eb8742 --- /dev/null +++ b/env/dev/backend.tf @@ -0,0 +1,21 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.83.1" + } + + tls = { + source = "hashicorp/tls" + version = "4.0.6" + } + } + + backend "s3" { + bucket = "devopslite-tf-state" + key = "dev/terraform.tfstate" + region = "us-east-1" + encrypt = true + dynamodb_table = "devopslite-tf-state" + } +} diff --git a/env/dev/main.tf b/env/dev/main.tf new file mode 100644 index 0000000..0d91403 --- /dev/null +++ b/env/dev/main.tf @@ -0,0 +1,120 @@ +provider "aws" { + region = var.aws_region +} + +module "vpc" { + source = "../../modules/vpc" + aws_region = var.aws_region + default_tags = var.default_tags + project = var.project + environment = var.environment + private_subnets_cidr = var.private_subnets_cidr + public_subnets_cidr = var.public_subnets_cidr + vpc_cidr = var.vpc_cidr +} + +module "vpc_endpoint" { + source = "../../modules/vpc-endpoint" + aws_region = var.aws_region + default_tags = var.default_tags + project = var.project + environment = var.environment + private_subnets = module.vpc.aws_subnets_private + route_table_ids = [module.vpc.private_route_table] + vpc_cidr = [module.vpc.cidr_block] + vpc_id = module.vpc.vpc_id + + depends_on = [module.vpc] +} + +module "kms" { + source = "../../modules/kms" + default_tags = var.default_tags + project = var.project + environment = var.environment +} + +module "ssm" { + source = "../../modules/ssm" + project = var.project + environment = var.environment +} + +module "bastion" { + source = "../../modules/bastion" + default_tags = var.default_tags + project = var.project + environment = var.environment + ami_id = var.bastion_ami_id + bastion_instance_profile_name = module.ssm.ssm_instance_profile_name + instance_type = var.bation_instance_type + private_subnet_id = module.vpc.aws_subnets_private[0] + vpc_cidr = [module.vpc.cidr_block] + vpc_id = module.vpc.vpc_id + + depends_on = [ + module.vpc, + module.ssm + ] +} + +module "ecr_fe" { + source = "../../modules/ecr" + default_tags = var.default_tags + project = var.project + environment = var.environment + kms_key_arn = module.kms.kms_arn + repository_name = "devopslite-fe" + + depends_on = [module.kms] +} + +module "ecr_be" { + source = "../../modules/ecr" + default_tags = var.default_tags + project = var.project + environment = var.environment + kms_key_arn = module.kms.kms_arn + repository_name = "devopslite-be" + + depends_on = [module.kms] +} + +module "eks" { + source = "../../modules/eks" + default_tags = var.default_tags + project = var.project + environment = var.environment + bastion_sg_id = module.bastion.bastion_sg_id + vpc_id = module.vpc.vpc_id + vpc_cidr = [module.vpc.cidr_block] + private_subnets = module.vpc.aws_subnets_private + eks_cluster_version = var.eks_cluster_version + kms_key_arn = module.kms.kms_arn + custom_ami_id = var.custom_ami_id + node_group_name = var.node_group_name + node_capacity_type = var.node_capacity_type + node_instance_type = var.node_instance_type + node_group_desired_capacity = var.node_group_desired_capacity + node_group_min_size = var.node_group_min_size + node_group_max_size = var.node_group_max_size + + depends_on = [ + module.vpc, + module.kms, + module.bastion + ] +} + +module "eks_access" { + source = "../../modules/eks-access" + project = var.project + environment = var.environment + access_entry_type = var.access_entry_type + access_scope_type = var.access_scope_type + kubernetes_groups = var.kubernetes_groups + policy_arn = var.policy_arn + principal_arn = var.principal_arn + + depends_on = [module.eks] +} diff --git a/env/dev/outputs.tf b/env/dev/outputs.tf new file mode 100644 index 0000000..ee2ca63 --- /dev/null +++ b/env/dev/outputs.tf @@ -0,0 +1,34 @@ +output "eks_cluster_endpoint" { + description = "The endpoint for the EKS cluster." + value = module.eks.eks_cluster_endpoint +} + +output "eks_cluster_id" { + description = "The ID of the EKS cluster." + value = module.eks.eks_cluster_id +} + +output "eks_cluster_oidc_issuer_url" { + description = "The OIDC issuer URL for the EKS cluster." + value = module.eks.eks_cluster_oidc_issuer_url +} + +output "eks_cluster_security_group_id" { + description = "The security group ID for the EKS cluster." + value = module.eks.eks_cluster_security_group_id +} + +output "eks_cluster_serviceaccount_role_arn" { + description = "The ARN of the IAM role used by service accounts in the EKS cluster." + value = module.eks.eks_cluster_serviceaccount_role_arn +} + +output "eks_node_group_arn" { + description = "The ARN of the EKS node group." + value = module.eks.eks_node_group_arn +} + +output "eks_node_group_role_arn" { + description = "The ARN of the IAM role used by the EKS node group." + value = module.eks.eks_node_group_role_arn +} diff --git a/env/dev/variables.tf b/env/dev/variables.tf new file mode 100644 index 0000000..0f5638f --- /dev/null +++ b/env/dev/variables.tf @@ -0,0 +1,131 @@ +variable "access_entry_type" { + description = "Type of access entry (STANDARD, EC2, EC2_LINUX, EC2_WINDOWS, FARGATE_LINUX)" + type = string + default = "STANDARD" +} + +variable "access_scope_type" { + description = "Type of access scope (namespace or cluster)" + type = string + default = "cluster" +} + +variable "aws_region" { + type = string + default = "us-east-1" +} + +variable "bastion_ami_id" { + description = "AMI ID for Bastion Host" + type = string + default = "ami-05576a079321f21f8" # Amazon Linux 2023 AMI +} + +variable "bation_instance_type" { + description = "Instance type for bastion host" + type = string + default = "t3.micro" +} + +variable "custom_ami_id" { + description = "Custom AMI ID for EKS nodes" + type = string + default = "ami-0476ff2866e16ac8a" +} + +variable "default_tags" { + type = map(string) + default = { + Environment = "dev" + Provisioner = "terraform" + Project = "devopslite" + } +} + +variable "eks_cluster_version" { + description = "Kubernetes version for the EKS cluster" + type = string + default = "1.31" +} + +variable "environment" { + type = string + default = "dev" +} + +variable "kubernetes_groups" { + description = "List of Kubernetes groups to grant access to the EKS cluster" + type = list(string) + default = ["admin"] +} + +variable "node_capacity_type" { + description = "Capacity type for the EKS node group (ON_DEMAND or SPOT)" + type = string + default = "ON_DEMAND" +} + +variable "node_group_desired_capacity" { + description = "Desired number of nodes in the EKS node group" + type = number + default = 2 +} + +variable "node_group_max_size" { + description = "Maximum number of nodes in the EKS node group" + type = number + default = 3 +} + +variable "node_group_min_size" { + description = "Minimum number of nodes in the EKS node group" + type = number + default = 1 +} + +variable "node_group_name" { + description = "Name of the EKS node group" + type = string + default = "ng" +} + +variable "node_instance_type" { + description = "Instance type for the EKS nodes" + type = string + default = "t3.small" +} + +variable "policy_arn" { + description = "ARN of the IAM policy to associate with the principal" + type = string + default = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy" +} + +variable "principal_arn" { + description = "ARN of the principal to grant access to the EKS cluster" + type = string + default = null +} + +variable "private_subnets_cidr" { + description = "CIDR blocks for the private subnets" + type = list(string) + default = ["172.16.10.0/24", "172.16.20.0/24", "172.16.30.0/24"] +} + +variable "project" { + type = string + default = "devopslite" +} + +variable "public_subnets_cidr" { + description = "CIDR blocks for the public subnets" + type = list(string) + default = ["172.16.1.0/24", "172.16.2.0/24", "172.16.3.0/24"] +} + +variable "vpc_cidr" { + description = "CIDR block for the VPC" + type = string + default = "172.16.0.0/16" +} diff --git a/modules/bastion/main.tf b/modules/bastion/main.tf new file mode 100644 index 0000000..c48741b --- /dev/null +++ b/modules/bastion/main.tf @@ -0,0 +1,60 @@ +data "aws_region" "current" {} + +resource "aws_security_group" "bastion_sg" { + name = "${var.project}-${var.environment}-bastion-sg" + vpc_id = var.vpc_id + description = "Security group for bastion host" + ingress { + description = "Allow SSH from VPC CIDR" + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = var.vpc_cidr + } + egress { + description = "Allow all traffic to all destinations" + from_port = 0 + to_port = 0 + protocol = -1 + cidr_blocks = ["0.0.0.0/0"] + } + tags = merge( + var.default_tags, + { + Name = "${var.project}-${var.environment}-bastion-sg" + } + ) +} + +resource "aws_instance" "bastion_host" { + # checkov:skip=CKV_AWS_126: "Ensure that detailed monitoring is enabled for EC2 instances" + ami = var.ami_id + instance_type = var.instance_type + subnet_id = var.private_subnet_id + vpc_security_group_ids = [aws_security_group.bastion_sg.id] + iam_instance_profile = var.bastion_instance_profile_name + ebs_optimized = true + + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + } + + root_block_device { + encrypted = true + } + + tags = merge( + var.default_tags, + { + Name = "${var.project}-${var.environment}-bastion-host" + } + ) + user_data = base64encode(<<-EOF + #!/bin/bash + yum install -y https://s3.${data.aws_region.current.name}.amazonaws.com/amazon-ssm-${data.aws_region.current.name}/latest/linux_amd64/amazon-ssm-agent.rpm + systemctl enable amazon-ssm-agent + systemctl start amazon-ssm-agent + EOF + ) +} diff --git a/modules/bastion/outputs.tf b/modules/bastion/outputs.tf new file mode 100644 index 0000000..9fc848e --- /dev/null +++ b/modules/bastion/outputs.tf @@ -0,0 +1,9 @@ +output "bastion_instance_id" { + value = aws_instance.bastion_host.id + description = "The ID of bastion ec2 instance" +} + +output "bastion_sg_id" { + value = aws_security_group.bastion_sg.id + description = "The ID of bastion security group" +} diff --git a/modules/bastion/variables.tf b/modules/bastion/variables.tf new file mode 100644 index 0000000..93c5bd1 --- /dev/null +++ b/modules/bastion/variables.tf @@ -0,0 +1,45 @@ +variable "ami_id" { + type = string + description = "AMI ID for Bastion Host" +} + +variable "bastion_instance_profile_name" { + type = string + description = "Name of bastion IAM Instance Profile" +} + +variable "default_tags" { + type = map(string) + default = {} + description = "The default tags to apply to resources" +} + +variable "environment" { + type = string + description = "Environment name" +} + +variable "instance_type" { + type = string + description = "Instance type for bastion host" +} + +variable "private_subnet_id" { + type = string + description = "ID of the private subnet" +} + +variable "project" { + type = string + description = "Project name" +} + +variable "vpc_cidr" { + type = list(string) + description = "VPC CIDR" +} + +variable "vpc_id" { + type = string + description = "ID of the VPC" +} diff --git a/modules/ecr/main.tf b/modules/ecr/main.tf new file mode 100644 index 0000000..8985d1e --- /dev/null +++ b/modules/ecr/main.tf @@ -0,0 +1,69 @@ +resource "aws_ecr_repository" "repository" { + name = var.repository_name + image_tag_mutability = "IMMUTABLE" + force_delete = true + + image_scanning_configuration { + scan_on_push = true + } + + encryption_configuration { + encryption_type = "KMS" + kms_key = var.kms_key_arn + } + + tags = merge( + var.default_tags, + { + Name = "${var.project}-${var.environment}-${var.repository_name}" + } + ) +} + +resource "aws_ecr_lifecycle_policy" "policy_untagged" { + repository = aws_ecr_repository.repository.name + + policy = < Date: Thu, 16 Jan 2025 20:25:01 +0700 Subject: [PATCH 2/6] chore: update AMI ID for dev environment --- env/dev/variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env/dev/variables.tf b/env/dev/variables.tf index 0f5638f..ebb1cf8 100644 --- a/env/dev/variables.tf +++ b/env/dev/variables.tf @@ -30,7 +30,7 @@ variable "bation_instance_type" { variable "custom_ami_id" { description = "Custom AMI ID for EKS nodes" type = string - default = "ami-0476ff2866e16ac8a" + default = "ami-0e28a3d4672edb444" # Get ID after Packer builds AMI } variable "default_tags" { From c92661e1b822b8a2fc1611b1b6c0955ed41786ad Mon Sep 17 00:00:00 2001 From: Daniel Pham Date: Thu, 16 Jan 2025 22:23:46 +0700 Subject: [PATCH 3/6] ci: add flow to create backend s3 bucket --- .github/workflows/create-backend.yml | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/create-backend.yml diff --git a/.github/workflows/create-backend.yml b/.github/workflows/create-backend.yml new file mode 100644 index 0000000..142a154 --- /dev/null +++ b/.github/workflows/create-backend.yml @@ -0,0 +1,50 @@ +name: Create Backend S3 Bucket + +on: + workflow_dispatch: + +permissions: read-all + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + create-backend: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Comment backend block + run: sed -i '/backend "s3"/,/}/s/^/# /' backend/main.tf + + - name: Set up Terraform + uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 + with: + terraform_version: '1.10.4' + + - name: Terraform apply + run: | + cd backend + terraform init + terraform apply -auto-approve + + - name: Uncomment backend block + run: sed -i '/backend "s3"/,/}/s/^# //' backend/main.tf + + - name: Migrate state to S3 bucket + run: terraform init -migrate-state + + slack-notify: + needs: + - terraform-check + if: always() + runs-on: ubuntu-latest + steps: + - name: Slack notification + uses: come25136/workflow-notification-for-slack@main + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} From 6abbbc7b347f2796cdce18d78330bd890ff3330d Mon Sep 17 00:00:00 2001 From: Daniel Pham Date: Thu, 16 Jan 2025 22:24:59 +0700 Subject: [PATCH 4/6] ci: fix syntax --- .github/workflows/create-backend.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-backend.yml b/.github/workflows/create-backend.yml index 142a154..c77ca94 100644 --- a/.github/workflows/create-backend.yml +++ b/.github/workflows/create-backend.yml @@ -39,7 +39,7 @@ jobs: slack-notify: needs: - - terraform-check + - create-backend if: always() runs-on: ubuntu-latest steps: From 5ca27efedd8b109e4496b2c899145b3ef639dde3 Mon Sep 17 00:00:00 2001 From: Daniel Pham Date: Thu, 16 Jan 2025 22:30:55 +0700 Subject: [PATCH 5/6] ci(fix): update IAM credentials to environment --- .github/workflows/create-backend.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/create-backend.yml b/.github/workflows/create-backend.yml index c77ca94..c069c26 100644 --- a/.github/workflows/create-backend.yml +++ b/.github/workflows/create-backend.yml @@ -9,6 +9,11 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +env: + AWS_REGION: us-east-1 + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + jobs: create-backend: runs-on: ubuntu-latest From 7eb46b831dc6705cf73b2d180c1c0daad4380191 Mon Sep 17 00:00:00 2001 From: Daniel Pham Date: Thu, 16 Jan 2025 22:33:25 +0700 Subject: [PATCH 6/6] chore: rebase main branch --- backend/main.tf | 188 ------------------------------------------- backend/outputs.tf | 14 ---- backend/variables.tf | 19 ----- 3 files changed, 221 deletions(-) delete mode 100644 backend/main.tf delete mode 100644 backend/outputs.tf delete mode 100644 backend/variables.tf diff --git a/backend/main.tf b/backend/main.tf deleted file mode 100644 index aff6fdb..0000000 --- a/backend/main.tf +++ /dev/null @@ -1,188 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "5.83.1" - } - } - - backend "s3" { - bucket = "devopslite-tf-state" - key = "s3-backend/terraform.tfstate" - region = "us-east-1" - encrypt = true - dynamodb_table = "devopslite-tf-state" - } -} - -provider "aws" { - region = "us-east-1" -} - -data "aws_caller_identity" "current" {} - -resource "aws_s3_bucket" "tf_state_bucket" { - # checkov:skip=CKV2_AWS_62: "Ensure S3 buckets should have event notifications enabled" - # checkov:skip=CKV2_AWS_61: "Ensure that an S3 bucket has a lifecycle configuration" - # checkov:skip=CKV_AWS_144: "Ensure that S3 bucket has cross-region replication enabled" - # checkov:skip=CKV_AWS_18: "Ensure the S3 bucket has access logging enabled" - bucket = "${var.project}-tf-state" - force_destroy = true - - tags = merge( - var.default_tags, - { - Name = "${var.project}-tf-state" - } - ) -} - -resource "aws_s3_bucket_public_access_block" "tf_bucket_public_access_block" { - bucket = aws_s3_bucket.tf_state_bucket.id - - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true -} - -resource "aws_s3_bucket_ownership_controls" "tf_bucket_ownership_controls" { - depends_on = [ - aws_s3_bucket.tf_state_bucket - ] - - bucket = aws_s3_bucket.tf_state_bucket.id - - rule { - object_ownership = "BucketOwnerEnforced" - } -} - -resource "aws_s3_bucket_versioning" "tf_bucket_versioning" { - bucket = aws_s3_bucket.tf_state_bucket.id - - versioning_configuration { - status = "Enabled" - } -} - -resource "aws_s3_bucket_server_side_encryption_configuration" "tf_bucket_encryption" { - bucket = aws_s3_bucket.tf_state_bucket.id - - rule { - apply_server_side_encryption_by_default { - sse_algorithm = "aws:kms" - kms_master_key_id = aws_kms_key.tf_kms_key.arn - } - } -} - -resource "aws_kms_key" "tf_kms_key" { - description = "The KMS key is used to encrypt the S3 bucket as a backend for terraform" - enable_key_rotation = true - deletion_window_in_days = 7 - - tags = merge( - var.default_tags, - { - Name = "${var.project}-tf-state-key" - Bucket = aws_s3_bucket.tf_state_bucket.arn - } - ) -} - -resource "aws_kms_alias" "tf_kms_key_alias" { - name = "alias/${var.project}-${var.region}-kms-key" - target_key_id = aws_kms_key.tf_kms_key.key_id -} - -resource "aws_kms_key_policy" "tf_kms_key_policy" { - key_id = aws_kms_key.tf_kms_key.key_id - - policy = jsonencode({ - Version = "2012-10-17" - Id = "key-default-1" - Statement = [ - { - Sid = "Enable IAM User Permissions" - Effect = "Allow" - Principal = { - AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" - }, - Action = "kms:*" - Resource = "*" - }, - { - Sid = "Allow administration of the key" - Effect = "Allow" - Principal = { - AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/cloud_user" - }, - Action = [ - "kms:ReplicateKey", - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion" - ], - Resource = "*" - }, - { - Sid = "Allow use of the key" - Effect = "Allow" - Principal = { - AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:user/cloud_user", - Service = [ - "s3.amazonaws.com", - "dynamodb.amazonaws.com" - ] - }, - Action = [ - "kms:DescribeKey", - "kms:Encrypt", - "kms:Decrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey", - "kms:GenerateDataKeyWithoutPlaintext" - ], - Resource = "*" - } - ] - }) -} - -resource "aws_dynamodb_table" "terraform_dynamodb_table" { - name = "${var.project}-tf-state" - hash_key = "LockID" - billing_mode = "PAY_PER_REQUEST" - - attribute { - name = "LockID" - type = "S" - } - - point_in_time_recovery { - enabled = true - } - - server_side_encryption { - enabled = true - kms_key_arn = aws_kms_key.tf_kms_key.arn - } - - tags = merge( - var.default_tags, - { - Name = "${var.project}-tf-state" - Bucket = aws_s3_bucket.tf_state_bucket.arn - } - ) -} diff --git a/backend/outputs.tf b/backend/outputs.tf deleted file mode 100644 index 6948ed2..0000000 --- a/backend/outputs.tf +++ /dev/null @@ -1,14 +0,0 @@ -output "bucket_name" { - description = "S3 bucket name" - value = aws_s3_bucket.tf_state_bucket.bucket -} - -output "bucket_arn" { - description = "S3 bucket ARN" - value = aws_s3_bucket.tf_state_bucket.arn -} - -output "dynamodb_name" { - description = "DynamoDB name" - value = aws_dynamodb_table.terraform_dynamodb_table.name -} diff --git a/backend/variables.tf b/backend/variables.tf deleted file mode 100644 index 9791758..0000000 --- a/backend/variables.tf +++ /dev/null @@ -1,19 +0,0 @@ -variable "region" { - description = "AWS region" - default = "us-east-1" - type = string -} - -variable "project" { - description = "The project name to use for unique resource naming" - default = "devopslite" - type = string -} - -variable "default_tags" { - type = map(string) - default = { - Provisioner = "terraform" - Project = "devopslite" - } -}