diff --git a/.github/workflows/checkov.yaml b/.github/workflows/checkov.yaml new file mode 100644 index 0000000..ff1a9c6 --- /dev/null +++ b/.github/workflows/checkov.yaml @@ -0,0 +1,48 @@ +name: 'Checkov' + +on: + push: + pull_request: + + workflow_dispatch: + +permissions: + contents: read + +jobs: + scan: + name: 'Checkov' + environment: production + + permissions: + contents: read + security-events: write + actions: read + + runs-on: ubuntu-latest + + defaults: + run: + shell: bash + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Checkov Github Action + uses: bridgecrewio/checkov-action@v12 + with: + directory: terraform + quiet: true + framework: terraform + var_file: test/terraform.test.tfvars + output_format: cli,sarif + output_file_path: console,results.sarif + skip_check: CKV2_AWS_39 + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v2 + + if: success() || failure() + with: + sarif_file: results.sarif \ No newline at end of file diff --git a/.github/workflows/terraform.yaml b/.github/workflows/terraform.yaml new file mode 100644 index 0000000..851a1eb --- /dev/null +++ b/.github/workflows/terraform.yaml @@ -0,0 +1,34 @@ +name: 'Terraform' + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + terraform: + name: 'Terraform' + runs-on: ubuntu-latest + environment: production + + defaults: + run: + shell: bash + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + with: + terraform_version: 1.13.0 + + - name: Terraform Init + run: terraform -chdir=terraform init + + - name: Terraform Lint + id: lint + run: terraform fmt -check -recursive terraform/ diff --git a/.gitignore b/.gitignore index 53925a9..481002f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Local .terraform directories -**/.terraform/* -.terraform/ +terraform/.terraform/* +terraform/.terraform/ # .tfstate files *.tfstate @@ -14,8 +14,8 @@ crash.*.log # password, private keys, and other secrets. These should not be part of version # control as they are data points which are potentially sensitive and subject # to change depending on the environment. -*.tfvars -*.tfvars.json +terraform/*.tfvars +terraform/*.tfvars.json # Ignore override files as they are usually used to override resources locally and so # are not checked in diff --git a/terraform/data.tf b/terraform/data.tf index 7862d07..7ffd416 100644 --- a/terraform/data.tf +++ b/terraform/data.tf @@ -1 +1,3 @@ -data "aws_availability_zones" "available" {} \ No newline at end of file +data "aws_availability_zones" "available" {} + +data "aws_caller_identity" "current" {} diff --git a/terraform/dns.tf b/terraform/dns.tf new file mode 100644 index 0000000..c18114f --- /dev/null +++ b/terraform/dns.tf @@ -0,0 +1,112 @@ +# Optional Route53 Hosted Zone for Kubernetes Ingress +resource "aws_route53_zone" "main" { + count = var.create_dns_zone ? 1 : 0 + + name = var.dns_zone_name + + tags = merge(local.tags, { + Name = "${local.name}-dns-zone" + }) +} + +# KMS Key for DNSSEC +resource "aws_kms_key" "dnssec" { + count = var.create_dns_zone ? 1 : 0 + + provider = aws.us-east-1 + + description = "KMS key for DNSSEC signing for ${var.dns_zone_name}" + deletion_window_in_days = 7 + key_usage = "SIGN_VERIFY" + customer_master_key_spec = "ECC_NIST_P256" + + policy = jsonencode({ + Version = "2012-10-17" + 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 Route 53 DNSSEC Service" + Effect = "Allow" + Principal = { + Service = "dnssec-route53.amazonaws.com" + } + Action = [ + "kms:DescribeKey", + "kms:GetPublicKey", + "kms:Sign" + ] + Resource = "*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnLike = { + "aws:SourceArn" = "arn:aws:route53:::hostedzone/*" + } + } + } + ] + }) + + tags = merge(local.tags, { + Name = "${local.name}-dnssec-key" + }) +} + +resource "aws_kms_alias" "dnssec" { + count = var.create_dns_zone ? 1 : 0 + + provider = aws.us-east-1 + + name = "alias/${local.name}-dnssec" + target_key_id = aws_kms_key.dnssec[0].key_id +} + +resource "aws_route53_key_signing_key" "main" { + count = var.create_dns_zone ? 1 : 0 + + provider = aws.us-east-1 + + hosted_zone_id = aws_route53_zone.main[0].zone_id + name = "${local.name}-ksk" + key_management_service_arn = aws_kms_key.dnssec[0].arn +} + +resource "aws_route53_hosted_zone_dnssec" "main" { + count = var.create_dns_zone ? 1 : 0 + + hosted_zone_id = aws_route53_zone.main[0].zone_id + + depends_on = [ + aws_route53_key_signing_key.main + ] +} + +resource "aws_route53domains_registered_domain" "main" { + count = var.create_dns_zone && var.is_aws_registered_domain ? 1 : 0 + + provider = aws.us-east-1 + + domain_name = var.dns_zone_name + + name_server { + name = aws_route53_zone.main[0].name_servers[0] + } + name_server { + name = aws_route53_zone.main[0].name_servers[1] + } + name_server { + name = aws_route53_zone.main[0].name_servers[2] + } + name_server { + name = aws_route53_zone.main[0].name_servers[3] + } +} diff --git a/terraform/eks.tf b/terraform/eks.tf index 6117f34..367e4ed 100644 --- a/terraform/eks.tf +++ b/terraform/eks.tf @@ -1,7 +1,6 @@ # EKS Cluster Module module "eks" { - source = "terraform-aws-modules/eks/aws" - version = "~> 21.9.0" + source = "git::https://github.com/terraform-aws-modules/terraform-aws-eks.git?ref=c41b582" name = local.name kubernetes_version = var.kubernetes_version @@ -28,12 +27,12 @@ module "eks" { # persistent volumes aws-ebs-csi-driver = { most_recent = true - service_account_role_arn = module.ebs_csi_irsa.iam_role_arn + service_account_role_arn = module.ebs_csi_irsa.arn } # volumesnapshots snapshot-controller = { most_recent = true - service_account_role_arn = module.ebs_csi_irsa.iam_role_arn + service_account_role_arn = module.ebs_csi_irsa.arn } aws-secrets-store-csi-driver-provider = { @@ -75,10 +74,9 @@ module "eks" { } module "ebs_csi_irsa" { - source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks" - version = "~> 5.28" + source = "git::https://github.com/terraform-aws-modules/terraform-aws-iam.git//modules/iam-role-for-service-accounts?ref=7279fc4" - role_name_prefix = "${local.name}-ebs-csi-" + name = "${local.name}-ebs-csi" attach_ebs_csi_policy = true @@ -92,10 +90,9 @@ module "ebs_csi_irsa" { # AWS Load Balancer Controller IAM Role module "aws_load_balancer_controller_irsa" { - source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks" - version = "~> 5.28" + source = "git::https://github.com/terraform-aws-modules/terraform-aws-iam.git//modules/iam-role-for-service-accounts?ref=7279fc4" - role_name_prefix = "${local.name}-aws-lb-controller-" + name = "${local.name}-aws-lb-controller" attach_load_balancer_controller_policy = true @@ -113,12 +110,14 @@ module "aws_load_balancer_controller_irsa" { module "external_dns_irsa" { count = var.create_dns_zone ? 1 : 0 - source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks" - version = "~> 5.28" + source = "git::https://github.com/terraform-aws-modules/terraform-aws-iam.git//modules/iam-role-for-service-accounts?ref=7279fc4" - role_name_prefix = "${local.name}-external-dns-" + name = "${local.name}-external-dns" attach_external_dns_policy = true + external_dns_hosted_zone_arns = [ + "arn:aws:route53:::hostedzone/${aws_route53_zone.main[0].zone_id}" + ] oidc_providers = { main = { diff --git a/terraform/ingress.tf b/terraform/ingress.tf index f2e7f91..a55a54c 100644 --- a/terraform/ingress.tf +++ b/terraform/ingress.tf @@ -1,35 +1,3 @@ -# Optional Route53 Hosted Zone for Kubernetes Ingress -resource "aws_route53_zone" "main" { - count = var.create_dns_zone ? 1 : 0 - - name = var.dns_zone_name - - tags = merge(local.tags, { - Name = "${local.name}-dns-zone" - }) -} - -resource "aws_route53domains_registered_domain" "main" { - count = var.create_dns_zone && var.is_aws_registered_domain ? 1 : 0 - - provider = aws.route53domains - - domain_name = var.dns_zone_name - - name_server { - name = aws_route53_zone.main[0].name_servers[0] - } - name_server { - name = aws_route53_zone.main[0].name_servers[1] - } - name_server { - name = aws_route53_zone.main[0].name_servers[2] - } - name_server { - name = aws_route53_zone.main[0].name_servers[3] - } -} - # AWS Certificate Manager certificate resource "aws_acm_certificate" "main" { count = var.create_dns_zone ? 1 : 0 @@ -103,7 +71,7 @@ resource "helm_release" "aws_load_balancer_controller" { }, { name = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn" - value = module.aws_load_balancer_controller_irsa.iam_role_arn + value = module.aws_load_balancer_controller_irsa.arn }, { name = "region" @@ -146,7 +114,7 @@ resource "helm_release" "external_dns" { }, { name = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn" - value = module.external_dns_irsa[0].iam_role_arn + value = module.external_dns_irsa[0].arn }, { name = "domainFilters[0]" diff --git a/terraform/karpenter.tf b/terraform/karpenter.tf index e327872..b4a60b4 100644 --- a/terraform/karpenter.tf +++ b/terraform/karpenter.tf @@ -1,6 +1,5 @@ module "karpenter" { - source = "terraform-aws-modules/eks/aws//modules/karpenter" - version = "~> 21.9.0" + source = "git::https://github.com/terraform-aws-modules/terraform-aws-eks.git//modules/karpenter?ref=c41b582" cluster_name = module.eks.cluster_name namespace = "kube-system" @@ -20,14 +19,14 @@ module "karpenter" { # Install Karpenter resource "helm_release" "karpenter" { - namespace = "kube-system" - name = "karpenter" - create_namespace = true - repository = "oci://public.ecr.aws/karpenter" - chart = "karpenter" - version = "1.8.2" - wait = true - timeout = 600 + namespace = "kube-system" + name = "karpenter" + create_namespace = true + repository = "oci://public.ecr.aws/karpenter" + chart = "karpenter" + version = "1.8.2" + wait = true + timeout = 600 values = [ <<-EOT diff --git a/terraform/terraform.tf b/terraform/terraform.tf index 50bd1f3..c1f4901 100644 --- a/terraform/terraform.tf +++ b/terraform/terraform.tf @@ -34,7 +34,7 @@ provider "aws" { } provider "aws" { - alias = "route53domains" + alias = "us-east-1" region = "us-east-1" } @@ -44,7 +44,7 @@ provider "kubectl" { exec { api_version = "client.authentication.k8s.io/v1beta1" command = "aws" - args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name] + args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name] } load_config_file = false } diff --git a/terraform/vpc.tf b/terraform/vpc.tf index 76a1ec8..bc8298f 100644 --- a/terraform/vpc.tf +++ b/terraform/vpc.tf @@ -1,6 +1,5 @@ module "vpc" { - source = "terraform-aws-modules/vpc/aws" - version = "~> 6.0" + source = "git::https://github.com/terraform-aws-modules/terraform-aws-vpc.git?ref=cf73787" name = local.name cidr = local.vpc_cidr diff --git a/test/terraform.test.tfvars b/test/terraform.test.tfvars new file mode 100644 index 0000000..0890068 --- /dev/null +++ b/test/terraform.test.tfvars @@ -0,0 +1,12 @@ +# AWS Configuration +region = "eu-north-1" +environment = "staging" + +# Cluster Configuration +kubernetes_version = "1.34" + +# Node Group Configuration +instance_types = ["t3.medium", "t3.large"] +primary_min_size = 1 +primary_max_size = 2 +primary_desired_size = 1