You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AGENTS.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -122,6 +122,8 @@ When a provider does not support a required behaviour (e.g. private nodes), appl
122
122
123
123
- The `kubeconfig` output MUST be constructed from the host and credentials returned directly by the cluster resource. These credentials are valid for the duration of the Terraform run and are used by any Terraform provider that configures itself from the kubeconfig output (e.g. the `kbst/kustomization` or `kubernetes` provider). No additional credential exchange or IAM assumption step is performed by the module itself — CI/CD pipelines are expected to handle role assumption or workload identity federation before invoking Terraform.
124
124
- Where a provider exposes a control to disable static local accounts or long-lived credential issuance on the cluster resource (e.g. `local_account_disabled` on AKS, `issue_client_certificate = false` on GKE), that control MUST be set to disable static credentials.
125
+
- Cluster modules MUST NOT define a `kubernetes` or any other provider block inside the module. Providers MUST be configured by the caller. Defining a provider block inside a child module is an anti-pattern in OpenTofu/Terraform.
126
+
- Cluster modules MUST NOT contain `kubernetes_*` resources. Any Kubernetes-API-level bootstrapping that a cluster requires (e.g. RBAC bindings, ConfigMaps) MUST be performed by the caller, not by the cluster module itself.
Copy file name to clipboardExpand all lines: DEVIATIONS.md
+11-11Lines changed: 11 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -49,9 +49,9 @@ When a divergence is resolved, remove its entry from this file.
49
49
50
50
> **Divergence — `aws/cluster/node-pool`:** Tagging and Labelling — the node-pool `labels` configuration attribute is not applied to the Kubernetes node object's `.metadata.labels`; EKS node group labels are set on the cloud API only, violating the rule that node labels MUST be applied to both the cloud API and the Kubernetes node object. Planned resolution: apply labels to both APIs.
51
51
52
-
> **Divergence — `aws/cluster`:** Human User Authentication — the `cluster_aws_auth_map_roles` and `cluster_aws_auth_map_users` configuration attributes allow arbitrary IAM-to-RBAC mappings to be injected into the `aws-auth` ConfigMap via the module, making the module a conduit for cluster-level RBAC bindings for named human users, which AGENTS.md reserves for platform service modules or the platform operator. Planned resolution: remove `cluster_aws_auth_map_roles` and `cluster_aws_auth_map_users` from the module interface.
52
+
> **Divergence — `aws/cluster`:** Human User Authentication — the `cluster_aws_auth_map_roles` and `cluster_aws_auth_map_users` configuration attributes allow arbitrary IAM-to-RBAC mappings to be injected into the `aws-auth` ConfigMap via the module, making the module a conduit for cluster-level RBAC bindings for named human users, which AGENTS.md reserves for platform service modules or the platform operator. Planned resolution: investigate if we can remove `cluster_aws_auth_map_roles` and `cluster_aws_auth_map_users` from the module interface - this depends on whether AWS offers an alternative now; an alternative is preferrable because the in-module kubernetes provider for this configmap is an anti-pattern and it would be overall beneficial to clean this up.
53
53
54
-
> **Divergence — `google/cluster`:** Networking — `google_compute_network` is created with `auto_create_subnetworks = true`, which auto-creates unmanaged subnets across all GCP regions rather than the module provisioning its own explicit, Terraform-managed subnet resources. Planned resolution: set `auto_create_subnetworks = false` and add explicit `google_compute_subnetwork` resources in `network.tf`.
54
+
> **Divergence — `google/cluster`:** Networking — `google_compute_network` is created with `auto_create_subnetworks = true`, which auto-creates unmanaged subnets across all GCP regions rather than the module provisioning its own explicit, Terraform-managed subnet resources. Planned resolution: set `auto_create_subnetworks = false` and add explicit `google_compute_subnetwork` resources in `network.tf`; to do this in a backwards compatbiel way, it may be necessary to make this conditional on a variable so existing clusters can keep using the current subnetworks.
55
55
56
56
> **Divergence — `google/cluster`:** Tagging and Labelling — `google_container_cluster` has no `resource_labels` block, and `google_compute_network`, `google_compute_router`, `google_compute_address`, and `google_dns_managed_zone` resources in `network.tf` and `ingress.tf` have no labels from the `common/metadata` output, violating the rule that all cloud resources MUST be tagged/labelled using the metadata module output. Planned resolution: add `resource_labels` (or equivalent) referencing `module.cluster_metadata.labels` to all cloud resources.
57
57
@@ -65,22 +65,28 @@ When a divergence is resolved, remove its entry from this file.
65
65
66
66
> **Divergence — `google/cluster/node-pool`:** Node Pool Lifecycle — `machine_type` defaults to `""` (empty string) via `try(coalesce(local.cfg.machine_type, null), "")`, which the GCP provider interprets as a provider-level default, violating the rule that instance type must always be user-provided with no module default. Planned resolution: remove the empty-string default in the v1 release (covered by the existing "All cluster and node-pool modules" divergence but noted here for the specific empty-string mechanism).
67
67
68
-
> **Divergence — `google/cluster`:** Cluster Module Outputs — the cluster module exposes a `default_ingress_ip` output beyond the four required outputs, without a compelling provider-specific justification. Planned resolution: evaluate for removal.
68
+
> **Divergence — `google/cluster`:** Cluster Module Outputs — the cluster module exposes a `default_ingress_ip` output beyond the four required outputs, without a compelling provider-specific justification. Planned resolution: keep for historical reasons to avoid braking change for existing users, document exception.
69
69
70
-
> **Divergence — `google/cluster/node-pool`:** Node-Pool Module Outputs — the node-pool module exposes an `id` output beyond the single required `current_config` output, without a compelling provider-specific justification. Planned resolution: evaluate for removal.
70
+
> **Divergence — `google/cluster/node-pool`:** Node-Pool Module Outputs — the node-pool module exposes an `id` output beyond the single required `current_config` output, without a compelling provider-specific justification. Planned resolution: keep for historical reasons to avoid braking change for existing users, document exception.
71
71
72
72
> **Divergence — `google/cluster`:** Required File Layout — `provider.tf` contains the data source `data.google_client_config.default`, which is used by both `kubeconfig.tf` and the kubernetes provider alias block in the same file; per the data source placement rule, a data source used by multiple resources belongs in `data_sources.tf`, not co-located with a provider block. Planned resolution: move the data source to `data_sources.tf`.
73
73
74
74
> **Divergence — `scaleway/cluster`:** Configuration Inheritance — `precondition` lifecycle blocks are absent from `scaleway_k8s_cluster` for required attributes (`region`, `cluster_version`), violating the rule that required attributes with no module default must be guarded by a precondition on the primary resource. Planned resolution: add preconditions.
75
75
76
76
> **Divergence — `scaleway/cluster/node-pool`:** Configuration Inheritance — `precondition` lifecycle blocks are absent from `scaleway_k8s_pool` for required attributes (`zones`, `node_type`, `min_size`, `max_size`), violating the rule that required attributes with no module default must be guarded by a precondition on the primary resource. Planned resolution: add preconditions.
77
77
78
-
> **Divergence — `scaleway/cluster`:** Networking — nodes are assigned public IPs by default (`public_ip_disabled` defaults to `false` in `node_pool.tf`), violating the rule that nodes MUST be configured with private IPs only by default. Planned resolution: flip the default to `true`.
78
+
> **Divergence — `scaleway/cluster`:** Networking — nodes are assigned public IPs by default (`public_ip_disabled` defaults to `false` in `node_pool.tf`), violating the rule that nodes MUST be configured with private IPs only by default. Planned resolution: flip the default to `true` and add any additional resources that need to be created; if these additioanl resources are only required in one or the other case make them conditional.
79
79
80
80
> **Divergence — `scaleway/cluster/node-pool`:** Tagging and Labelling — the node-pool module exposes no configuration attribute for Kubernetes node labels; node labels can only be approximated by encoding them as Scaleway tag strings, with no guarantee that they are applied to the Kubernetes node object's `.metadata.labels`, violating the rule that node labels MUST be applied to both the cloud API and the Kubernetes node object. Planned resolution: add a dedicated node label attribute once the Scaleway provider exposes first-class Kubernetes node label support.
81
81
82
82
> **Divergence — `scaleway/cluster`:** Cluster API Authentication — `scaleway_k8s_cluster.current.kubeconfig[0].token` is a long-lived static admin token issued by the cluster resource; Scaleway does not expose a control to disable static credential issuance on the cluster resource, so this cannot currently be resolved, but it diverges from the rule that static long-lived credentials must be disabled where the provider exposes such a control. Planned resolution: revisit when the Scaleway provider exposes a control to disable static token issuance.
83
83
84
+
> **Divergence — `google/cluster`:** Cluster API Authentication — `provider.tf` defines a `kubernetes` provider alias (`kubernetes.gke`) configured inside the module using a short-lived GCP access token, violating the rule that cluster modules MUST NOT define a `kubernetes` provider block inside the module. The provider block is consumed by `cluster_role_binding.tf` within the same module. Planned resolution: remove the `kubernetes` provider block and `cluster_role_binding.tf` from the module; move any required bootstrapping to the caller.
85
+
86
+
> **Divergence — `google/cluster`:** Cluster API Authentication — `cluster_role_binding.tf` provisions a `kubernetes_cluster_role_binding` resource inside the cluster module, violating the rule that cluster modules MUST NOT contain `kubernetes_*` resources. Planned resolution: investigate how to implement the `kubernetes_cluster_role_binding` resource requirement differently; move the RBAC bootstrapping to the caller.
87
+
88
+
> **Divergence — `aws/cluster`:** Cluster API Authentication — `aws_iam_authenticator.tf` provisions a `kubernetes_config_map` resource inside the cluster module, violating the rule that cluster modules MUST NOT contain `kubernetes_*` resources. The `aws-auth` ConfigMap write depends on an implicit `kubernetes` provider passed in by the caller. Planned resolution: remove the `kubernetes_config_map` resource from the module; the `aws-auth` ConfigMap is managed by EKS automatically for standard node group IAM roles.
89
+
84
90
> **Divergence — `scaleway/cluster`:** Monitoring and Logging — the Scaleway provider exposes no managed logging or monitoring resource on `scaleway_k8s_cluster`, so the module cannot enable cloud provider logging and monitoring by default, violating the rule that every cluster module MUST enable cloud provider managed logging and monitoring by default. Planned resolution: enable if and when the Scaleway provider exposes managed logging or monitoring support.
85
91
86
92
## Provider-Specific Exceptions
@@ -98,9 +104,3 @@ When an exception becomes unnecessary (e.g. a refactor removes the underlying co
98
104
### Entries
99
105
100
106
> **Exception — `aws/cluster/node-pool`:**`cluster_default_node_pool_name` and `cluster_default_node_pool_subnet_ids` — the node-pool module for extra node pools determines subnets from the default node pool's subnet IDs by default; when provisioning the default node pool itself these variables are required to break the circular dependency.
101
-
102
-
> **Exception — `azurerm/cluster`:**`provider.tf` — the AKS cluster module requires a `kubernetes` provider alias configured with static client certificate credentials from `kube_config`; because provider blocks cannot be placed in any of the standard required files, a dedicated `provider.tf` is the only viable location for this alias configuration.
103
-
104
-
> **Exception — `google/cluster`:**`provider.tf` — the GKE cluster module requires a `kubernetes` provider alias configured with a short-lived GCP access token obtained from `data.google_client_config.default`; because provider blocks cannot be placed in any of the standard required files, a dedicated `provider.tf` is the only viable location for this alias configuration.
105
-
106
-
> **Exception — `google/cluster`:**`cluster_role_binding.tf` — on GKE, a freshly-created cluster grants no Kubernetes RBAC permissions to any GCP IAM identity by default; the `kubernetes_cluster_role_binding` that grants `cluster-admin` to the currently-authenticated GCP service account (the CI/CD automation identity) is required to bootstrap RBAC so that the `kubernetes` and `kbst/kustomization` providers can operate against the cluster during the same Terraform run, directly supporting the Cluster API Authentication requirement.
0 commit comments