feature/tofu #15
Reference in New Issue
Block a user
Delete Branch "feature/tofu"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
@thomas.solbjor her er "import" av tofu fra ditt repo med justeringer for å tilpasse patterns her. Også minimalisert til å kun opprette cluster, ingen managed services som postgres etc. Ta en titt.
Inline review
@@ -17,2 +17,3 @@bash.exe.stackdumpbash.exe.stackdumpEmpty line with trailing space should be cleaned up.
#ai-review-inline
Inline review
@@ -0,0 +21,4 @@}output "kubeconfig" {value = module.cluster.kubeconfigKubeconfig should not be exposed as a Terraform output as it contains sensitive cluster credentials that could be logged or stored insecurely.
#ai-review-inline
Inline review
@@ -0,0 +2,4 @@# NEVER commit aks.env to git!# RequiredAZURE_TENANT_ID=your-azure-tenant-idExample file contains placeholder values that could be mistaken for real credentials.
#ai-review-inline
@@ -0,0 +3,4 @@# RequiredAZURE_TENANT_ID=your-azure-tenant-idAZURE_SUBSCRIPTION_ID=your-azure-subscription-idExample file contains placeholder values that could be mistaken for real credentials.
#ai-review-inline
@@ -0,0 +1,9 @@# GCP GKE credentials — copy to gke.env and fill in values# NEVER commit gke.env to git!Remove empty line with trailing comment marker to clean up the example file format.
#ai-review-inline
@@ -0,0 +4,4 @@# RequiredGCP_PROJECT_ID=your-gcp-project-idGCP_REGION=europe-west4Remove empty line with trailing comment marker to clean up the example file format.
#ai-review-inline
@@ -0,0 +2,4 @@# NEVER commit upc.env to git!# RequiredUPCLOUD_TOKEN=your-upcloud-api-tokenExample credential files should use placeholder values that cannot be mistaken for real tokens.
#ai-review-inline
Inline review
Inline review
@@ -0,0 +2,4 @@# NEVER commit aks.env to git!# RequiredAZURE_TENANT_ID=your-azure-tenant-idExample file contains placeholder values that could be mistaken for real credentials.
#ai-review-inline
@@ -0,0 +3,4 @@# RequiredAZURE_TENANT_ID=your-azure-tenant-idAZURE_SUBSCRIPTION_ID=your-azure-subscription-idExample file contains placeholder values that could be mistaken for real credentials.
#ai-review-inline
@@ -0,0 +1,9 @@# GCP GKE credentials — copy to gke.env and fill in values# NEVER commit gke.env to git!Remove empty line with trailing comment marker to clean up the example file format.
#ai-review-inline
@@ -0,0 +4,4 @@# RequiredGCP_PROJECT_ID=your-gcp-project-idGCP_REGION=europe-west4Remove empty line with trailing comment marker to clean up the example file format.
#ai-review-inline
@@ -0,0 +2,4 @@# NEVER commit upc.env to git!# RequiredUPCLOUD_TOKEN=your-upcloud-api-tokenExample credential files should use placeholder values that cannot be mistaken for real tokens.
#ai-review-inline
Inline review
Inline review
Inline review
@@ -0,0 +6,4 @@resource_group_name = "clst-dev-rg"# AKS — small dev nodesaks_node_vm_size = "Standard_B2s"Standard_B2s is a burstable instance type which may not provide consistent performance for AKS workloads.
#ai-review-inline
@@ -0,0 +7,4 @@# AKS — small dev nodesaks_node_vm_size = "Standard_B2s"aks_node_count = 2Two nodes provides no redundancy; consider at least 3 nodes for high availability.
#ai-review-inline
Inline review
Inline review
@@ -0,0 +27,4 @@output "kubeconfig" {description = "Kubeconfig for the AKS cluster"value = azurerm_kubernetes_cluster.main.kube_config_rawExposing raw kubeconfig as output can lead to credential leakage in Terraform state and logs.
#ai-review-inline
Inline review
@@ -0,0 +7,4 @@# AKS — general-purpose nodes for productionaks_node_vm_size = "Standard_D4s_v3"aks_node_count = 3Production AKS cluster has only 3 nodes which may not provide sufficient availability for production workloads.
#ai-review-inline
Inline review
@@ -0,0 +4,4 @@required_providers {azurerm = {source = "hashicorp/azurerm"version = "~> 4.0"Use a more specific version constraint to ensure reproducible deployments and avoid potential breaking changes.
#ai-review-inline
Inline review
@@ -0,0 +12,4 @@node_count = 2node_min_count = 1node_max_count = 4kubernetes_version = "1.30"Kubernetes version should be pinned to a specific patch version for reproducibility and security patching control.
#ai-review-inline
Inline review
@@ -0,0 +37,4 @@# ─── AKS Cluster ──────────────────────────────────────────────────────resource "azurerm_kubernetes_cluster" "main" {AKS cluster lacks essential security configurations like private cluster mode and authorized IP ranges.
#ai-review-inline
@@ -0,0 +45,4 @@kubernetes_version = var.aks_kubernetes_versiontags = var.tagsdefault_node_pool {Default node pool lacks resource limits (max_count) and auto-scaling, which can lead to unbounded resource consumption.
#ai-review-inline
@@ -0,0 +61,4 @@type = "SystemAssigned"}network_profile {Network profile is missing pod_cidr and service_cidr configuration, which may cause IP allocation conflicts.
#ai-review-inline
Inline review
Inline review
Inline review
@@ -0,0 +6,4 @@}tls = {source = "hashicorp/tls"version = "~> 4.0"Consider using a more specific version constraint to ensure reproducible builds and avoid unexpected updates.
#ai-review-inline
Inline review
@@ -0,0 +6,4 @@}tls = {source = "hashicorp/tls"version = "~> 4.0"Consider using a more specific version constraint to ensure reproducible builds and avoid unexpected updates.
#ai-review-inline
Inline review
@@ -0,0 +18,4 @@variable "vnet_address_space" {description = "Address space for the virtual network"type = stringdefault = "10.100.0.0/16"Consider using a smaller default CIDR range to avoid potential IP conflicts with on-premises networks.
#ai-review-inline
@@ -0,0 +24,4 @@variable "aks_subnet_cidr" {description = "CIDR block for the AKS node subnet"type = stringdefault = "10.100.0.0/22"Default subnet CIDR should align with the updated VNet address space if changed.
#ai-review-inline
@@ -0,0 +30,4 @@variable "aks_node_vm_size" {description = "VM size for AKS worker nodes (e.g., Standard_B2s, Standard_D4s_v3)"type = string}Consider adding validation to restrict to supported Azure VM sizes for better cost control and compatibility.
#ai-review-inline
@@ -0,0 +35,4 @@variable "aks_node_count" {description = "Number of AKS worker nodes"type = number}Consider adding validation to ensure node count is within reasonable bounds (1-100).
#ai-review-inline
@@ -0,0 +2,4 @@required_providers {aws = {source = "hashicorp/aws"version = "~> 5.0"Consider using a more specific version constraint to ensure reproducible builds and avoid unexpected updates.
#ai-review-inline
Inline review
@@ -0,0 +18,4 @@variable "vnet_address_space" {description = "Address space for the virtual network"type = stringdefault = "10.100.0.0/16"Consider using a smaller default CIDR range to avoid potential IP conflicts with on-premises networks.
#ai-review-inline
@@ -0,0 +24,4 @@variable "aks_subnet_cidr" {description = "CIDR block for the AKS node subnet"type = stringdefault = "10.100.0.0/22"Default subnet CIDR should align with the updated VNet address space if changed.
#ai-review-inline
@@ -0,0 +30,4 @@variable "aks_node_vm_size" {description = "VM size for AKS worker nodes (e.g., Standard_B2s, Standard_D4s_v3)"type = string}Consider adding validation to restrict to supported Azure VM sizes for better cost control and compatibility.
#ai-review-inline
@@ -0,0 +35,4 @@variable "aks_node_count" {description = "Number of AKS worker nodes"type = number}Consider adding validation to ensure node count is within reasonable bounds (1-100).
#ai-review-inline
@@ -0,0 +2,4 @@required_providers {aws = {source = "hashicorp/aws"version = "~> 5.0"Consider using a more specific version constraint to ensure reproducible builds and avoid unexpected updates.
#ai-review-inline
Inline review
Inline review
Inline review
@@ -0,0 +12,4 @@node_count = 3node_min_count = 3node_max_count = 6kubernetes_version = "1.30"Kubernetes version should be pinned to a specific patch version (e.g., '1.30.6') to ensure consistent deployments and avoid unexpected upgrades.
#ai-review-inline
Inline review
@@ -0,0 +47,4 @@variable "aks_node_vm_size" {description = "VM size for AKS worker nodes"type = stringdefault = "Standard_B2s"VM size Standard_B2s may be too small for production workloads and could cause resource constraints.
#ai-review-inline
@@ -0,0 +53,4 @@variable "aks_node_count" {description = "Number of AKS worker nodes"type = numberdefault = 2Node count of 2 provides no high availability; consider at least 3 nodes for production resilience.
#ai-review-inline
@@ -0,0 +64,4 @@variable "domain" {description = "Public domain name — must have an existing Azure DNS zone"type = stringDomain variable lacks a default value and has no validation, which could cause deployment failures.
#ai-review-inline
@@ -0,0 +117,4 @@kubernetes_version = var.aks_kubernetes_versiontags = var.tagsdefault_node_pool {Default node pool is missing enable_auto_scaling and lacks resource limits which could cause node exhaustion.
#ai-review-inline
Inline review
Inline review
@@ -0,0 +47,4 @@variable "aks_node_vm_size" {description = "VM size for AKS worker nodes"type = stringdefault = "Standard_B2s"VM size Standard_B2s may be too small for production workloads and could cause resource constraints.
#ai-review-inline
@@ -0,0 +53,4 @@variable "aks_node_count" {description = "Number of AKS worker nodes"type = numberdefault = 2Node count of 2 provides no high availability; consider at least 3 nodes for production resilience.
#ai-review-inline
@@ -0,0 +64,4 @@variable "domain" {description = "Public domain name — must have an existing Azure DNS zone"type = stringDomain variable lacks a default value and has no validation, which could cause deployment failures.
#ai-review-inline
@@ -0,0 +117,4 @@kubernetes_version = var.aks_kubernetes_versiontags = var.tagsdefault_node_pool {Default node pool is missing enable_auto_scaling and lacks resource limits which could cause node exhaustion.
#ai-review-inline
Inline review
Inline review
@@ -0,0 +43,4 @@})}# NAT Gateway (single, in first public subnet — use one per AZ for prod HA)Using a single NAT Gateway creates a single point of failure; consider one NAT Gateway per AZ for production high availability.
#ai-review-inline
@@ -0,0 +121,4 @@vpc_config {subnet_ids = concat(aws_subnet.private[*].id, aws_subnet.public[*].id)endpoint_private_access = trueendpoint_public_access = truePublic API endpoint access should be restricted to specific CIDR blocks for security.
#ai-review-inline
@@ -0,0 +185,4 @@node_role_arn = aws_iam_role.eks_nodes.arnsubnet_ids = aws_subnet.private[*].idinstance_types = [var.node_instance_type]Node instance types should be configurable as a list to support multiple instance types for better availability and cost optimization.
#ai-review-inline
Inline review
@@ -0,0 +43,4 @@})}# NAT Gateway (single, in first public subnet — use one per AZ for prod HA)Using a single NAT Gateway creates a single point of failure; consider one NAT Gateway per AZ for production high availability.
#ai-review-inline
@@ -0,0 +121,4 @@vpc_config {subnet_ids = concat(aws_subnet.private[*].id, aws_subnet.public[*].id)endpoint_private_access = trueendpoint_public_access = truePublic API endpoint access should be restricted to specific CIDR blocks for security.
#ai-review-inline
@@ -0,0 +185,4 @@node_role_arn = aws_iam_role.eks_nodes.arnsubnet_ids = aws_subnet.private[*].idinstance_types = [var.node_instance_type]Node instance types should be configurable as a list to support multiple instance types for better availability and cost optimization.
#ai-review-inline
Inline review
@@ -0,0 +43,4 @@})}# NAT Gateway (single, in first public subnet — use one per AZ for prod HA)Using a single NAT Gateway creates a single point of failure; consider one NAT Gateway per AZ for production high availability.
#ai-review-inline
@@ -0,0 +121,4 @@vpc_config {subnet_ids = concat(aws_subnet.private[*].id, aws_subnet.public[*].id)endpoint_private_access = trueendpoint_public_access = truePublic API endpoint access should be restricted to specific CIDR blocks for security.
#ai-review-inline
@@ -0,0 +185,4 @@node_role_arn = aws_iam_role.eks_nodes.arnsubnet_ids = aws_subnet.private[*].idinstance_types = [var.node_instance_type]Node instance types should be configurable as a list to support multiple instance types for better availability and cost optimization.
#ai-review-inline
Inline review
@@ -0,0 +194,4 @@}update_config {max_unavailable = 1Consider using
max_unavailable_percentageinstead of a fixed number for better scaling flexibility.#ai-review-inline
Inline review
@@ -0,0 +8,4 @@# GKE — small dev nodesnode_machine_type = "e2-standard-2"node_count = 2deletion_protection = falseDeletion protection disabled in dev environment creates risk of accidental cluster deletion.
#ai-review-inline
Inline review
@@ -0,0 +2,4 @@required_providers {aws = {source = "hashicorp/aws"version = "~> 5.0"Use exact version pinning instead of pessimistic version constraint for better reproducibility in production environments.
#ai-review-inline
@@ -0,0 +6,4 @@}tls = {source = "hashicorp/tls"version = "~> 4.0"Use exact version pinning instead of pessimistic version constraint for better reproducibility in production environments.
#ai-review-inline
Inline review
Inline review
@@ -0,0 +15,4 @@}variable "project_id" {description = "GCP project ID for the dev environment"Variable lacks validation to ensure it follows GCP project ID naming rules (6-30 chars, lowercase, numbers, hyphens).
#ai-review-inline
Inline review
@@ -0,0 +8,4 @@# GKE — general-purpose nodes for productionnode_machine_type = "e2-standard-4"node_count = 3deletion_protection = trueConsider enabling deletion protection for production clusters to prevent accidental deletion.
#ai-review-inline
Inline review
@@ -0,0 +2,4 @@required_providers {google = {source = "hashicorp/google"version = "~> 6.0"Consider pinning to a more specific version range to avoid potential breaking changes from minor version updates.
#ai-review-inline
Inline review
@@ -0,0 +56,4 @@# ─── Required APIs ────────────────────────────────────────────────────resource "google_project_service" "compute" {project = var.project_idVariable 'project_id' is referenced but not defined in this file.
#ai-review-inline
@@ -0,0 +93,4 @@project = var.project_idname = "${var.prefix}-subnet"ip_cidr_range = "10.110.0.0/22"region = var.regionVariable 'region' is referenced but not defined in this file.
#ai-review-inline
@@ -0,0 +183,4 @@resource "google_project_iam_member" "external_dns_dns_admin" {project = var.project_idrole = "roles/dns.admin"The 'roles/dns.admin' role is overly permissive and grants broad DNS management access.
#ai-review-inline
Inline review
@@ -0,0 +56,4 @@# ─── Required APIs ────────────────────────────────────────────────────resource "google_project_service" "compute" {project = var.project_idVariable 'project_id' is referenced but not defined in this file.
#ai-review-inline
@@ -0,0 +93,4 @@project = var.project_idname = "${var.prefix}-subnet"ip_cidr_range = "10.110.0.0/22"region = var.regionVariable 'region' is referenced but not defined in this file.
#ai-review-inline
@@ -0,0 +183,4 @@resource "google_project_iam_member" "external_dns_dns_admin" {project = var.project_idrole = "roles/dns.admin"The 'roles/dns.admin' role is overly permissive and grants broad DNS management access.
#ai-review-inline
Inline review
Inline review
@@ -0,0 +64,4 @@variable "domain" {description = "Public domain name — must have an existing Route53 hosted zone"type = stringMissing validation for domain variable - should ensure it's a valid FQDN.
#ai-review-inline
@@ -0,0 +195,4 @@vpc_config {subnet_ids = concat(aws_subnet.private[*].id, aws_subnet.public[*].id)endpoint_private_access = trueEKS endpoint_public_access enabled - consider restricting public access with public_access_cidrs for better security.
#ai-review-inline
@@ -0,0 +257,4 @@node_role_arn = aws_iam_role.eks_nodes.arnsubnet_ids = aws_subnet.private[*].idinstance_types = [var.node_instance_type]Node group using only one instance type - consider adding a secondary type for better availability.
#ai-review-inline
@@ -0,0 +328,4 @@statement {effect = "Allow"actions = ["route53:ListHostedZones", "route53:ListResourceRecordSets", "route53:ListTagsForResource"]resources = ["*"]Route53 IAM policy uses wildcard resource for list operations - consider scoping to specific hosted zones if possible.
#ai-review-inline
Inline review
@@ -0,0 +64,4 @@variable "domain" {description = "Public domain name — must have an existing Route53 hosted zone"type = stringMissing validation for domain variable - should ensure it's a valid FQDN.
#ai-review-inline
@@ -0,0 +195,4 @@vpc_config {subnet_ids = concat(aws_subnet.private[*].id, aws_subnet.public[*].id)endpoint_private_access = trueEKS endpoint_public_access enabled - consider restricting public access with public_access_cidrs for better security.
#ai-review-inline
@@ -0,0 +257,4 @@node_role_arn = aws_iam_role.eks_nodes.arnsubnet_ids = aws_subnet.private[*].idinstance_types = [var.node_instance_type]Node group using only one instance type - consider adding a secondary type for better availability.
#ai-review-inline
@@ -0,0 +328,4 @@statement {effect = "Allow"actions = ["route53:ListHostedZones", "route53:ListResourceRecordSets", "route53:ListTagsForResource"]resources = ["*"]Route53 IAM policy uses wildcard resource for list operations - consider scoping to specific hosted zones if possible.
#ai-review-inline
Inline review
Inline review
@@ -0,0 +64,4 @@variable "domain" {description = "Public domain name — must have an existing Route53 hosted zone"type = stringMissing validation for domain variable - should ensure it's a valid FQDN.
#ai-review-inline
@@ -0,0 +195,4 @@vpc_config {subnet_ids = concat(aws_subnet.private[*].id, aws_subnet.public[*].id)endpoint_private_access = trueEKS endpoint_public_access enabled - consider restricting public access with public_access_cidrs for better security.
#ai-review-inline
@@ -0,0 +257,4 @@node_role_arn = aws_iam_role.eks_nodes.arnsubnet_ids = aws_subnet.private[*].idinstance_types = [var.node_instance_type]Node group using only one instance type - consider adding a secondary type for better availability.
#ai-review-inline
@@ -0,0 +328,4 @@statement {effect = "Allow"actions = ["route53:ListHostedZones", "route53:ListResourceRecordSets", "route53:ListTagsForResource"]resources = ["*"]Route53 IAM policy uses wildcard resource for list operations - consider scoping to specific hosted zones if possible.
#ai-review-inline
Inline review
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }output "project_id" { value = var.project_id }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }output "project_id" { value = var.project_id }output "region" { value = var.region }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }output "project_id" { value = var.project_id }output "region" { value = var.region }output "external_dns_gsa_email" { value = google_service_account.external_dns.email }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
Inline review
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }output "project_id" { value = var.project_id }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }output "project_id" { value = var.project_id }output "region" { value = var.region }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }output "project_id" { value = var.project_id }output "region" { value = var.region }output "external_dns_gsa_email" { value = google_service_account.external_dns.email }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
Inline review
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }output "project_id" { value = var.project_id }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }output "project_id" { value = var.project_id }output "region" { value = var.region }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
@@ -0,0 +1,4 @@output "cluster_name" { value = google_container_cluster.main.name }output "project_id" { value = var.project_id }output "region" { value = var.region }output "external_dns_gsa_email" { value = google_service_account.external_dns.email }Output value should be wrapped in quotes for consistency with Terraform string outputs.
#ai-review-inline
Inline review
Inline review
@@ -0,0 +10,4 @@}provider "upcloud" {# Set via environment variables: UPCLOUD_USERNAME, UPCLOUD_PASSWORDProvider authentication should reference environment variables explicitly or use a more secure method than username/password.
#ai-review-inline
Inline review
@@ -0,0 +25,4 @@resource "google_compute_subnetwork" "main" {project = var.project_idname = "${var.prefix}-subnet"ip_cidr_range = "10.100.0.0/22"Hardcoded CIDR range should be configurable via variable to support different network architectures.
#ai-review-inline
@@ -0,0 +32,4 @@# Secondary ranges required for GKE VPC-native clustersecondary_ip_range {range_name = "pods"ip_cidr_range = "10.200.0.0/14" # /14 = ~262k pod IPsHardcoded pod CIDR range should be configurable via variable for flexibility across environments.
#ai-review-inline
@@ -0,0 +37,4 @@secondary_ip_range {range_name = "services"ip_cidr_range = "10.204.0.0/20" # /20 = ~4k service IPsHardcoded service CIDR range should be configurable via variable for flexibility across environments.
#ai-review-inline
@@ -0,0 +91,4 @@cluster = google_container_cluster.main.namenode_count = var.node_countnode_config {Missing security hardening options like boot disk encryption and security group configuration.
#ai-review-inline
@@ -0,0 +100,4 @@}oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform",OAuth scope 'cloud-platform' is overly broad and grants excessive permissions - use specific scopes instead.
#ai-review-inline
Inline review
Inline review
Inline review
Inline review
Inline review
@@ -0,0 +35,4 @@name = "${var.prefix}-${var.cluster_name}"zone = var.zonenetwork = upcloud_network.kubernetes.idcontrol_plane_ip_filter = var.control_plane_ip_filterConsider making control plane IP filter more restrictive than default to limit management access.
#ai-review-inline
Inline review
@@ -0,0 +35,4 @@name = "${var.prefix}-${var.cluster_name}"zone = var.zonenetwork = upcloud_network.kubernetes.idcontrol_plane_ip_filter = var.control_plane_ip_filterConsider making control plane IP filter more restrictive than default to limit management access.
#ai-review-inline
Inline review
@@ -0,0 +37,4 @@network = upcloud_network.kubernetes.idcontrol_plane_ip_filter = var.control_plane_ip_filterprivate_node_groups = truePrivate node groups is a good security practice for isolating worker nodes from public internet.
#ai-review-inline
@@ -0,0 +35,4 @@variable "control_plane_ip_filter" {description = "CIDRs allowed to access the K8s API"type = list(string)default = ["0.0.0.0/0"]Default control plane access allows all IPs (0.0.0.0/0), which exposes the Kubernetes API to the entire internet - this is a significant security risk.
#ai-review-inline
Inline review
@@ -0,0 +7,4 @@node_count = 3network_cidr = "10.100.0.0/24"control_plane_ip_filter = ["0.0.0.0/0"] # TODO: restrict to known CIDRsControl plane access is exposed to the entire internet (0.0.0.0/0), which is a critical security risk for production.
#ai-review-inline
Inline review
@@ -0,0 +10,4 @@}provider "upcloud" {# Set via environment variables: UPCLOUD_USERNAME, UPCLOUD_PASSWORDAuthentication credentials should be explicitly documented or validated to ensure they're properly set via environment variables.
#ai-review-inline
Inline review
@@ -0,0 +47,4 @@variable "control_plane_ip_filter" {description = "CIDRs allowed to access the K8s API"type = list(string)default = ["0.0.0.0/0"]Control plane API is exposed to the entire internet with 0.0.0.0/0 CIDR which creates a security risk.
#ai-review-inline
Inline review
@@ -0,0 +10,4 @@}provider "upcloud" {# Set via environment variables: UPCLOUD_USERNAME, UPCLOUD_PASSWORDDocument the required environment variables in a README or use Terraform variables with descriptions instead of relying solely on comments.
#ai-review-inline
Inline review
@@ -0,0 +4,4 @@SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"# Delegate to setup-cluster.sh with --destroy flagexec "$SCRIPT_DIR/setup-cluster.sh" "$@" --destroyUsing exec with user-provided arguments ($@) before --destroy creates a command injection risk if malicious arguments are passed.
#ai-review-inline
Inline review
@@ -0,0 +30,4 @@case "$PLATFORM" inaks)cd "$TOFU_DIR"RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "$CLUSTER-rg")Command substitution with 'tofu output' could fail silently; add error handling or validation for the fallback values.
#ai-review-inline
@@ -0,0 +36,4 @@;;eks)cd "$TOFU_DIR"NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "$CLUSTER")Command substitution with 'tofu output' could fail silently; add error handling or validation for the fallback values.
#ai-review-inline
@@ -0,0 +42,4 @@;;gke)cd "$TOFU_DIR"NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "$CLUSTER")Command substitution with 'tofu output' could fail silently; add error handling or validation for the fallback values.
#ai-review-inline
@@ -0,0 +44,4 @@cd "$TOFU_DIR"NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "$CLUSTER")REGION=$(tofu output -raw region 2>/dev/null || echo "${GCP_REGION:-europe-west4}")PROJECT=$(tofu output -raw project_id 2>/dev/null || echo "${GCP_PROJECT_ID:-}")Missing validation for required GCP_PROJECT_ID variable; script could fail with empty project ID.
#ai-review-inline
@@ -0,0 +50,4 @@;;upc)cd "$TOFU_DIR"CLUSTER_ID=$(tofu output -raw cluster_id 2>/dev/null || echo "${UPCLOUD_CLUSTER_ID:-}")Missing validation for required UPCLOUD_CLUSTER_ID variable; script could fail with empty cluster ID.
#ai-review-inline
Inline review
Inline review
Inline review
@@ -0,0 +30,4 @@case "$PLATFORM" inaks)cd "$TOFU_DIR"RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "$CLUSTER-rg")Command substitution with 'tofu output' could fail silently; add error handling or validation for the fallback values.
#ai-review-inline
@@ -0,0 +36,4 @@;;eks)cd "$TOFU_DIR"NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "$CLUSTER")Command substitution with 'tofu output' could fail silently; add error handling or validation for the fallback values.
#ai-review-inline
@@ -0,0 +42,4 @@;;gke)cd "$TOFU_DIR"NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "$CLUSTER")Command substitution with 'tofu output' could fail silently; add error handling or validation for the fallback values.
#ai-review-inline
@@ -0,0 +44,4 @@cd "$TOFU_DIR"NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "$CLUSTER")REGION=$(tofu output -raw region 2>/dev/null || echo "${GCP_REGION:-europe-west4}")PROJECT=$(tofu output -raw project_id 2>/dev/null || echo "${GCP_PROJECT_ID:-}")Missing validation for required GCP_PROJECT_ID variable; script could fail with empty project ID.
#ai-review-inline
@@ -0,0 +50,4 @@;;upc)cd "$TOFU_DIR"CLUSTER_ID=$(tofu output -raw cluster_id 2>/dev/null || echo "${UPCLOUD_CLUSTER_ID:-}")Missing validation for required UPCLOUD_CLUSTER_ID variable; script could fail with empty cluster ID.
#ai-review-inline
Inline review
Inline review
@@ -0,0 +118,4 @@if [[ -f "$CLUSTER_CONFIG" ]]; thenecho " Loading cluster config from clusters/$CLUSTER.yaml"if command -v yq >/dev/null 2>&1; theneval "$(yq -r 'to_entries[] | "export CLUSTER_\(.key)=\"\(.value)\""' "$CLUSTER_CONFIG")"Potential command injection vulnerability when using yq with user-controlled cluster config.
#ai-review-inline
@@ -0,0 +184,4 @@echo " Saved from tofu output"elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")Unquoted variable substitution could lead to command injection if cluster name contains special characters.
#ai-review-inline
@@ -0,0 +185,4 @@elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +190,4 @@fi;;eks)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +195,4 @@aws eks update-kubeconfig --name "$NAME" --region "$REGION" --kubeconfig "$KUBECONFIG_FILE";;gke)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
Inline review
@@ -0,0 +118,4 @@if [[ -f "$CLUSTER_CONFIG" ]]; thenecho " Loading cluster config from clusters/$CLUSTER.yaml"if command -v yq >/dev/null 2>&1; theneval "$(yq -r 'to_entries[] | "export CLUSTER_\(.key)=\"\(.value)\""' "$CLUSTER_CONFIG")"Potential command injection vulnerability when using yq with user-controlled cluster config.
#ai-review-inline
@@ -0,0 +184,4 @@echo " Saved from tofu output"elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")Unquoted variable substitution could lead to command injection if cluster name contains special characters.
#ai-review-inline
@@ -0,0 +185,4 @@elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +190,4 @@fi;;eks)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +195,4 @@aws eks update-kubeconfig --name "$NAME" --region "$REGION" --kubeconfig "$KUBECONFIG_FILE";;gke)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
Inline review
@@ -0,0 +118,4 @@if [[ -f "$CLUSTER_CONFIG" ]]; thenecho " Loading cluster config from clusters/$CLUSTER.yaml"if command -v yq >/dev/null 2>&1; theneval "$(yq -r 'to_entries[] | "export CLUSTER_\(.key)=\"\(.value)\""' "$CLUSTER_CONFIG")"Potential command injection vulnerability when using yq with user-controlled cluster config.
#ai-review-inline
@@ -0,0 +184,4 @@echo " Saved from tofu output"elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")Unquoted variable substitution could lead to command injection if cluster name contains special characters.
#ai-review-inline
@@ -0,0 +185,4 @@elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +190,4 @@fi;;eks)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +195,4 @@aws eks update-kubeconfig --name "$NAME" --region "$REGION" --kubeconfig "$KUBECONFIG_FILE";;gke)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
Inline review
@@ -0,0 +118,4 @@if [[ -f "$CLUSTER_CONFIG" ]]; thenecho " Loading cluster config from clusters/$CLUSTER.yaml"if command -v yq >/dev/null 2>&1; theneval "$(yq -r 'to_entries[] | "export CLUSTER_\(.key)=\"\(.value)\""' "$CLUSTER_CONFIG")"Potential command injection vulnerability when using yq with user-controlled cluster config.
#ai-review-inline
@@ -0,0 +184,4 @@echo " Saved from tofu output"elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")Unquoted variable substitution could lead to command injection if cluster name contains special characters.
#ai-review-inline
@@ -0,0 +185,4 @@elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +190,4 @@fi;;eks)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +195,4 @@aws eks update-kubeconfig --name "$NAME" --region "$REGION" --kubeconfig "$KUBECONFIG_FILE";;gke)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
Inline review
@@ -0,0 +118,4 @@if [[ -f "$CLUSTER_CONFIG" ]]; thenecho " Loading cluster config from clusters/$CLUSTER.yaml"if command -v yq >/dev/null 2>&1; theneval "$(yq -r 'to_entries[] | "export CLUSTER_\(.key)=\"\(.value)\""' "$CLUSTER_CONFIG")"Potential command injection vulnerability when using yq with user-controlled cluster config.
#ai-review-inline
@@ -0,0 +184,4 @@echo " Saved from tofu output"elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")Unquoted variable substitution could lead to command injection if cluster name contains special characters.
#ai-review-inline
@@ -0,0 +185,4 @@elseecho " Fetching from Azure CLI..."RG=$(tofu output -raw resource_group_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}-rg")NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +190,4 @@fi;;eks)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
@@ -0,0 +195,4 @@aws eks update-kubeconfig --name "$NAME" --region "$REGION" --kubeconfig "$KUBECONFIG_FILE";;gke)NAME=$(tofu output -raw cluster_name 2>/dev/null || echo "${CLUSTER_clusterName:-$CLUSTER}")Unquoted variable substitution could lead to command injection.
#ai-review-inline
This PR adds extensive OpenTofu infrastructure provisioning capabilities to the Kubernetes GitOps platform, introducing multi-cloud cluster provisioning automation.
What changed: Added comprehensive OpenTofu infrastructure-as-code modules and scripts for provisioning Kubernetes clusters across Azure AKS, AWS EKS, GCP GKE, and UpCloud platforms.
Affected services/namespaces: No direct Kubernetes namespace changes - this adds infrastructure provisioning layer that creates clusters where GitOps applications will be deployed. The infrastructure provisions clusters that will host namespaces like argocd, external-dns, cert-manager, etc.
Infrastructure impact: Major infrastructure addition - introduces automated cluster provisioning with configurable node counts, VM sizes, networking (VPCs/VNets with subnets), and resource scaling. AKS dev uses 2x Standard_B2s nodes, prod uses 3x Standard_D4s_v3 nodes. EKS dev uses 2x t3.medium, prod 3x m5.xlarge with auto-scaling 1-4/3-6 nodes. Includes workload identity/IRSA configurations for cloud-native authentication.
Security notes: Contains cloud provider credential configurations in git-ignored .env files, implements workload identity for keyless service access (Azure managed identity, AWS IRSA, GCP workload identity), and includes RBAC roles for external-dns DNS management. The credential handling requires extra review attention - ensure .env files remain git-ignored and follow least-privilege principles for cloud service account permissions.
#ai-review-summary
WIP: feature/tofuto feature/tofu