Recently i made a change to our GKE kubernets cluster resource in Terraform. This change prompted a lot of data source to be re-read by Terraform that I couldn’t explain, and any resources that depended on those data sources, to be replaced/modified. It was a LOT of resources. I started to explore dependencies with the terraform graph
tool, and got stuck with data sources that are very simple, but for some reason depend on other resources that i have no way of explaining.
Does anyone have an idea why data sources in Terraform can depend on resources they aren’t referencing (in)directly? How could I explore the source of this dependency further? Initially i thought it might be a count
I had on the cluster and some of the other resources to introduce an if
condition on the resources. I since removed that count
statement (it really over complicated it anyway) just to see if that changed anything, but it didn’t. The gke cluster resource is pasted at the end for reference.
I am running terraform 1.8.5 with google provider 5.11.0
I am picking one of the data sources as an example.
I have a data.cloudflare_zone
datasource like this:
data "cloudflare_zone" "my-app" {
name = local.tld
}
locals {
tld = "my-app.co.uk"
}
If I explore the dependencies with terraform graph
it shows these dependencies:
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.google_container_node_pool.primary_preemptible_nodes";
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.google_project_iam_member.artifactregistryReader";
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.google_project_iam_member.logWriter";
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.google_project_iam_member.metricWriter";
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.google_project_iam_member.monitoringViewer";
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.google_project_iam_member.resourceMetadataWriter";
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.kubernetes_cluster_role_binding.gcp_admins";
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.kubernetes_deployment.my-app-debug";
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.kubernetes_role_binding.developers";
For some reason the datasource depends on the gke cluster resource in another module, and also on a bunch of unrelated IAM membership resources.
If i check the data source with terraform plan
this is the json it shows (no references
or depends_on
entries).
{
"address": "module.my-app-api.data.cloudflare_zone.my-app",
"mode": "data",
"type": "cloudflare_zone",
"name": "my-app",
"provider_name": "registry.terraform.io/cloudflare/cloudflare",
"schema_version": 0,
"values": {
"account_id": ",<redacted>",
"id": "<redacted>",
"name": "my-app.co.uk",
"name_servers": [
"danica.ns.cloudflare.com",
"khalid.ns.cloudflare.com"
],
"paused": false,
"plan": "Free Website",
"status": "active",
"vanity_name_servers": [],
"zone_id": "<redacted>"
},
"sensitive_values": {
"name_servers": [
false,
false
],
"vanity_name_servers": []
}
},
If i then further dive into the gke cluster resource and see what else depends on it, it turns out there are a ton of other data sources that depend on that cluster, that are equally hard to explain:
"module.my-app-api.data.cloudflare_zone.my-app" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.data.google_artifact_registry_repository.my-app-docker" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.data.google_iam_policy.cloud_run_service" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.data.google_iam_policy.create_superuser_execute" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.data.google_iam_policy.django_migration_job_execute" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.data.google_iam_policy.sentry_version_job_execute" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.data.google_secret_manager_secret_version_access.common-data-token" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.data.google_secret_manager_secret_version_access.eccolab-secret" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.data.google_secret_manager_secret_version_access.geocodify_api_key" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.google_secret_manager_secret.config" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.google_secret_manager_secret.kube-config" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.google_secret_manager_secret.sentry_auth_token" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.google_service_account.eventarc" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.google_service_account.service-account" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.random_password.db-password" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.random_password.django-secret" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api.sentry_project.my-app-api" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.data.cloudflare_zone.my-app" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.data.google_artifact_registry_repository.my-app-docker" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.data.google_iam_policy.cloud_run_service" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.data.google_iam_policy.create_superuser_execute" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.data.google_iam_policy.django_migration_job_execute" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.data.google_iam_policy.sentry_version_job_execute" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.data.google_secret_manager_secret_version_access.common-data-token" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.data.google_secret_manager_secret_version_access.eccolab-secret" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.data.google_secret_manager_secret_version_access.geocodify_api_key" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.google_secret_manager_secret.config" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.google_secret_manager_secret.kube-config" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.google_secret_manager_secret.sentry_auth_token" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.google_service_account.eventarc" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.google_service_account.service-account" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.random_password.db-password" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.random_password.django-secret" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-api-v2.sentry_project.my-app-api" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners.data.google_iam_policy.dead-letter-subscription" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners.data.google_iam_policy.dead-letter-topic" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners.google_pubsub_topic.dead-letter" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners.google_pubsub_topic.home-my-app-response" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners.google_pubsub_topic.retrofit-planner-response" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners.google_service_account.gcp_service_account" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners.kubernetes_deployment.home-my-app-debug" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners.kubernetes_deployment.retrofit-planner-debug" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners.kubernetes_role.job_runner" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners-v2.data.google_iam_policy.dead-letter-subscription" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners-v2.data.google_iam_policy.dead-letter-topic" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners-v2.google_pubsub_topic.dead-letter" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners-v2.google_pubsub_topic.home-my-app-response" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners-v2.google_pubsub_topic.retrofit-planner-response" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners-v2.google_service_account.gcp_service_account" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners-v2.kubernetes_deployment.home-my-app-debug" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners-v2.kubernetes_deployment.retrofit-planner-debug" -> "module.k8s_cluster.google_container_cluster.cluster";
"module.my-app-runners-v2.kubernetes_role.job_runner" -> "module.k8s_cluster.google_container_cluster.cluster";
The gke cluster resource for reference:
resource "google_container_cluster" "cluster" {
name = var.cluster_name
location = var.region
network = var.vpc
networking_mode = "VPC_NATIVE"
subnetwork = var.vpc_subnet
datapath_provider = "ADVANCED_DATAPATH"
enable_intranode_visibility = true
node_locations = [
"europe-north1-a",
"europe-north1-b",
"europe-north1-c",
]
maintenance_policy {
recurring_window {
# critical security updates are still applied outside this window
start_time = "2023-07-03T00:00:00Z"
end_time = "2023-07-03T06:00:00Z"
recurrence = "FREQ=DAILY"
}
}
addons_config {
dns_cache_config {
enabled = false
}
horizontal_pod_autoscaling {
disabled = false
}
http_load_balancing {
disabled = false
}
network_policy_config {
disabled = true
}
}
authenticator_groups_config {
security_group = "gke-security-groups@my-app.co.uk"
}
binary_authorization {
evaluation_mode = "DISABLED"
}
timeouts {}
cluster_autoscaling {
enabled = false
}
project = var.project_id
resource_labels = {
"env" = "production"
}
database_encryption {
state = "DECRYPTED"
}
default_snat_status {
disabled = false
}
dns_config {
cluster_dns = "CLOUD_DNS"
cluster_dns_domain = "cluster.local"
cluster_dns_scope = "CLUSTER_SCOPE"
}
gateway_api_config {
channel = "CHANNEL_STANDARD"
}
ip_allocation_policy {
stack_type = "IPV4"
pod_cidr_overprovision_config {
disabled = false
}
}
deletion_protection = false
private_cluster_config {
enable_private_nodes = true
enable_private_endpoint = false
master_ipv4_cidr_block = "<redacted>"
master_global_access_config {
enabled = false
}
}
initial_node_count = 1
remove_default_node_pool = true
logging_config {
enable_components = [
"SYSTEM_COMPONENTS",
"WORKLOADS",
"SCHEDULER",
]
}
master_auth {
client_certificate_config {
issue_client_certificate = false
}
}
monitoring_config {
enable_components = [
"SYSTEM_COMPONENTS",
"SCHEDULER",
"POD",
"DEPLOYMENT",
"HPA",
"STATEFULSET",
"DAEMONSET",
]
advanced_datapath_observability_config {
enable_metrics = true
}
managed_prometheus {
enabled = true
}
}
network_policy {
enabled = false
provider = "PROVIDER_UNSPECIFIED"
}
notification_config {
pubsub {
enabled = true
topic = "projects/${var.project_id}/topics/kubernetes-alerts"
}
}
release_channel {
channel = "REGULAR"
}
security_posture_config {
mode = "BASIC"
vulnerability_mode = "VULNERABILITY_BASIC"
}
service_external_ips_config {
enabled = false
}
workload_identity_config {
workload_pool = "${var.project_id}.svc.id.goog"
}
}