diff --git a/modules/common/cert_manager/standard/1.0/README.md b/modules/common/cert_manager/standard/1.0/README.md index d422c12c..d362e261 100644 --- a/modules/common/cert_manager/standard/1.0/README.md +++ b/modules/common/cert_manager/standard/1.0/README.md @@ -14,7 +14,7 @@ This module adapts to different cloud environments: - **Azure**: Uses existing DNS credentials for certificate validation - **GCP**: Integrates with Google Cloud DNS for certificate validation and supports GTS certificates -The module automatically detects the cloud provider from `var.cc_metadata.cc_tenant_provider` and configures appropriate DNS solvers and authentication mechanisms. +The module automatically detects the cloud provider from the `external_dns_details` input (if provided) or from `kubernetes_details.attributes.cloud_provider` and configures appropriate DNS solvers and authentication mechanisms. ## Nodepool Integration diff --git a/modules/common/cert_manager/standard/1.0/facets.yaml b/modules/common/cert_manager/standard/1.0/facets.yaml index cb69b427..b7b6ab39 100644 --- a/modules/common/cert_manager/standard/1.0/facets.yaml +++ b/modules/common/cert_manager/standard/1.0/facets.yaml @@ -1,6 +1,6 @@ intent: cert_manager flavor: standard -version: '1.0' +version: '2.0' description: Deploys Cert Manager for managing ssl certificates clouds: - aws @@ -30,6 +30,12 @@ inputs: type: '@facets/kubernetes_nodepool' displayName: Node Pool optional: false + external_dns_details: + type: '@facets/external_dns' + displayName: External DNS + optional: true + description: External DNS module providing DNS credentials for cert-manager DNS-01 + challenges outputs: default: type: '@facets/cert_manager' @@ -85,10 +91,12 @@ sample: flavor: standard disabled: true metadata: {} - version: '1.0' + version: '2.0' spec: cname_strategy: Follow cert_manager: {} iac: validated_files: + - main.tf - variables.tf + - outputs.tf diff --git a/modules/common/cert_manager/standard/1.0/locals.tf b/modules/common/cert_manager/standard/1.0/locals.tf index efb5f48c..15773f02 100644 --- a/modules/common/cert_manager/standard/1.0/locals.tf +++ b/modules/common/cert_manager/standard/1.0/locals.tf @@ -1,39 +1,70 @@ # Define your locals here locals { - tenant_provider = lower(try(var.cc_metadata.cc_tenant_provider, "aws")) - spec = lookup(var.instance, "spec", {}) - user_supplied_helm_values = try(local.spec.cert_manager.values, try(var.instance.advanced.cert_manager.values, {})) - cert_manager = lookup(local.spec, "cert_manager", try(var.instance.advanced.cert_manager, {})) + # Determine tenant provider from external_dns module output (primary) or kubernetes_details (cluster module output) + tenant_provider = lower( + try(var.inputs.external_dns_details.attributes.provider, + try(var.inputs.kubernetes_details.attributes.cloud_provider, "aws")) + ) + + spec = lookup(var.instance, "spec", {}) + advanced = lookup(var.instance, "advanced", {}) + + # Helm values configuration + cert_manager_advanced = lookup(local.advanced, "cert_manager", {}) + user_supplied_helm_values = lookup(local.cert_manager_advanced, "values", {}) cert_mgr_namespace = "cert-manager" - advanced = lookup(lookup(var.instance, "advanced", {}), "cert_manager", {}) - cnameStrategy = lookup(local.spec, "cname_strategy", "Follow") - disable_dns_validation = lookup(local.spec, "disable_dns_validation", lookup(local.advanced, "disable_dns_validation", false)) - user_defined_tags = try(local.cert_manager.tags, {}) - deploy_aws_resources = local.tenant_provider == "aws" ? local.disable_dns_validation ? false : true : false - dns_providers = { - aws = { + + # DNS validation settings + cnameStrategy = lookup(local.spec, "cname_strategy", "Follow") + disable_dns_validation = lookup(local.spec, "disable_dns_validation", false) + + # External DNS configuration (if provided) + external_dns = try(var.inputs.external_dns_details.attributes, null) + has_external_dns = local.external_dns != null && !local.disable_dns_validation + + # Build DNS provider configuration from external_dns input + # This creates the provider-specific configuration block for cert-manager + dns_providers = local.has_external_dns ? merge( + local.external_dns.provider == "aws" ? { route53 = { - region = try(var.cc_metadata.cc_region, null) + region = local.external_dns.region accessKeyIDSecretRef = { - key = "access-key-id" - name = local.disable_dns_validation ? "na" : kubernetes_secret.cert_manager_r53_secret[0].metadata[0].name + name = local.external_dns.secret_name + key = local.external_dns.aws_access_key_id_key + namespace = local.external_dns.secret_namespace } secretAccessKeySecretRef = { - key = "secret-access-key" - name = local.disable_dns_validation ? "na" : kubernetes_secret.cert_manager_r53_secret[0].metadata[0].name + name = local.external_dns.secret_name + key = local.external_dns.aws_secret_access_key_key + namespace = local.external_dns.secret_namespace } } - } - google = { + } : {}, + local.external_dns.provider == "gcp" ? { cloudDNS = { - project = lookup(try(data.kubernetes_secret_v1.dns[0].data, {}), "project", "") + project = local.external_dns.project_id serviceAccountSecretRef = { - key = "credentials.json" - name = local.disable_dns_validation ? "na" : kubernetes_secret.cert_manager_r53_secret[0].metadata[0].name + name = local.external_dns.secret_name + key = local.external_dns.gcp_credentials_json_key + namespace = local.external_dns.secret_namespace } } - } - } + } : {}, + local.external_dns.provider == "azure" ? { + azureDNS = { + subscriptionID = local.external_dns.subscription_id + tenantID = local.external_dns.tenant_id + clientID = local.external_dns.client_id + resourceGroupName = local.external_dns.resource_group_name + clientSecretSecretRef = { + name = local.external_dns.secret_name + key = local.external_dns.azure_credentials_json_key + namespace = local.external_dns.secret_namespace + } + } + } : {} + ) : {} + # Let's Encrypt DNS01 validation cluster issuers dns01_validations = { staging = { name = "letsencrypt-staging" @@ -41,8 +72,8 @@ locals { solvers = [ { dns01 = merge({ - cnameStrategy = "Follow" - }, lookup(local.dns_providers, local.tenant_provider, {})) + cnameStrategy = local.cnameStrategy + }, local.dns_providers) }, ] } @@ -52,12 +83,14 @@ locals { solvers = [ { dns01 = merge({ - cnameStrategy = "Follow" - }, lookup(local.dns_providers, local.tenant_provider, {})) + cnameStrategy = local.cnameStrategy + }, local.dns_providers) }, ] } } + + # Let's Encrypt HTTP01 validation cluster issuers http_validations = { staging-http01 = { name = "letsencrypt-staging-http01" @@ -68,8 +101,8 @@ locals { ingress = { podTemplate = { spec = { - nodeSelector = local.nodepool_labels - tolerations = local.nodepool_tolerations + nodeSelector = local.nodeSelector + tolerations = local.tolerations } } } @@ -86,8 +119,8 @@ locals { ingress = { podTemplate = { spec = { - nodeSelector = local.nodepool_labels - tolerations = local.nodepool_tolerations + nodeSelector = local.nodeSelector + tolerations = local.tolerations } } } @@ -96,12 +129,25 @@ locals { ] } } - environments = merge(local.http_validations, local.disable_dns_validation ? {} : local.dns01_validations) + + # Combine HTTP and DNS validations (skip DNS if disabled) + environments = merge( + local.http_validations, + local.disable_dns_validation ? {} : local.dns01_validations + ) # Nodepool configuration from inputs - nodepool_config = lookup(var.inputs, "kubernetes_node_pool_details", null) - nodepool_tolerations = lookup(local.nodepool_config, "taints", []) - nodepool_labels = lookup(local.nodepool_config, "node_selector", {}) + nodepool_config = try(var.inputs.kubernetes_node_pool_details.attributes, null) + + # Handle taints: convert null/object to empty list, ensure it's always a list + # taints can come as: null, {}, [], or list of objects with {key, value, effect} + # Check if taints exists and is a list, otherwise return empty list + # Use can() to safely check if we can convert to list (works for lists, fails for objects) + nodepool_tolerations = local.nodepool_config != null && local.nodepool_config.taints != null ? ( + can(tolist(local.nodepool_config.taints)) ? tolist(local.nodepool_config.taints) : [] + ) : [] + + nodepool_labels = local.nodepool_config != null ? try(local.nodepool_config.node_selector, {}) : {} # Use only nodepool configuration (no fallback to default tolerations) tolerations = local.nodepool_tolerations @@ -110,14 +156,5 @@ locals { # GTS and ACME configuration use_gts = lookup(local.spec, "use_gts", false) gts_private_key = lookup(local.spec, "gts_private_key", "") - acme_email = lookup(local.spec, "acme_email", "") != "" ? lookup(local.spec, "acme_email", "") : try(var.cluster.createdBy, null) -} - -data "kubernetes_secret_v1" "dns" { - count = local.tenant_provider == "aws" ? 0 : 1 - metadata { - name = "facets-tenant-dns" - namespace = "default" - } - provider = kubernetes.release-pod + acme_email = lookup(local.spec, "acme_email", "") != "" ? lookup(local.spec, "acme_email", "") : null } diff --git a/modules/common/cert_manager/standard/1.0/main.tf b/modules/common/cert_manager/standard/1.0/main.tf index 0b03b402..39654d18 100644 --- a/modules/common/cert_manager/standard/1.0/main.tf +++ b/modules/common/cert_manager/standard/1.0/main.tf @@ -1,92 +1,10 @@ # Define your terraform resources here -module "iam_user_name" { - count = local.disable_dns_validation ? 0 : 1 - source = "github.com/Facets-cloud/facets-utility-modules//name" - environment = var.environment - limit = 64 - globally_unique = false - resource_name = var.inputs.kubernetes_details.attributes.cluster_name - resource_type = "" - is_k8s = false -} - -module "iam_policy_name" { - count = local.disable_dns_validation ? 0 : 1 - source = "github.com/Facets-cloud/facets-utility-modules//name" - environment = var.environment - limit = 128 - globally_unique = false - resource_name = var.inputs.kubernetes_details.attributes.cluster_name - resource_type = "" - is_k8s = false -} - -resource "aws_iam_user" "cert_manager_iam_user" { - count = local.deploy_aws_resources ? 1 : 0 - provider = "aws3tooling" - name = lower(module.iam_user_name[0].name) - tags = merge(local.user_defined_tags, var.environment.cloud_tags) -} - -resource "aws_iam_user_policy" "cert_manager_r53_policy" { - count = local.deploy_aws_resources ? 1 : 0 - provider = "aws3tooling" - name = lower(module.iam_policy_name[0].name) - user = try(aws_iam_user.cert_manager_iam_user[0].name, "na") - policy = <= 6 ? "windos" : local.name - kubernetes_cluster_id = var.inputs.kubernetes_details.attributes.cluster_id + kubernetes_cluster_id = var.inputs.kubernetes_details.cluster_id vm_size = var.instance.spec.instance_type os_disk_size_gb = trim(var.instance.spec.disk_size, "G") os_type = local.os_type @@ -40,7 +40,7 @@ resource "azurerm_kubernetes_cluster_node_pool" "node_pool" { mode = lookup(local.aks_advanced, "mode", "User") orchestrator_version = lookup(local.aks_advanced, "orchestrator_version", null) - vnet_subnet_id = lookup(local.aks_advanced, "vnet_subnet_id", var.inputs.kubernetes_details.attributes.network_details.private_subnet_ids[0]) + vnet_subnet_id = lookup(local.aks_advanced, "vnet_subnet_id", var.inputs.kubernetes_details.network_details.private_subnet_ids[0]) eviction_policy = local.priority == "Spot" ? lookup(local.aks_advanced, "eviction_policy", "Delete") : null tags = local.tags diff --git a/modules/kubernetes_node_pool/gcp_node_fleet/1.0/gke_node_pool b/modules/kubernetes_node_pool/gcp_node_fleet/1.0/gke_node_pool deleted file mode 120000 index 6baf40b6..00000000 --- a/modules/kubernetes_node_pool/gcp_node_fleet/1.0/gke_node_pool +++ /dev/null @@ -1 +0,0 @@ -/Users/ishaankalra/Documents/Facets Work/github-repositories/facets-modules-redesign/gcp/kubernetes_node_pool/gcp/1.0 \ No newline at end of file diff --git a/outputs/external_dns/outputs.yaml b/outputs/external_dns/outputs.yaml new file mode 100644 index 00000000..c0466556 --- /dev/null +++ b/outputs/external_dns/outputs.yaml @@ -0,0 +1,48 @@ +name: '@facets/external_dns' +properties: + attributes: + type: object + properties: + secret_name: + type: string + description: Name of the Kubernetes secret containing DNS credentials + secret_namespace: + type: string + description: Namespace where the DNS credentials secret is stored + aws_access_key_id_key: + type: string + description: Secret key name for AWS access key ID (AWS only) + aws_secret_access_key_key: + type: string + description: Secret key name for AWS secret access key (AWS only) + gcp_credentials_json_key: + type: string + description: Secret key name for GCP credentials JSON (GCP only) + azure_credentials_json_key: + type: string + description: Secret key name for Azure credentials JSON (Azure only) + hosted_zone_id: + type: string + description: AWS Route53 hosted zone ID (AWS only) + region: + type: string + description: Cloud region for DNS operations + provider: + type: string + description: Cloud provider (aws, gcp, azure) + subscription_id: + type: string + description: Azure subscription ID (Azure only) + tenant_id: + type: string + description: Azure tenant ID (Azure only) + client_id: + type: string + description: Azure client ID (Azure only) + project_id: + type: string + description: GCP project ID (GCP only) + interfaces: + type: object +providers: [] +