@ariestools/cli 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +51 -11
  2. package/dist/bin/aries.mjs +95560 -254131
  3. package/dist/bin/daemons/chain-server.mjs +9862 -12
  4. package/dist/bin/daemons/dapp-server.mjs +55 -56
  5. package/dist/bin/daemons/datalake-dev.mjs +10967 -4724
  6. package/dist/node/datalake.mjs +7 -5
  7. package/dist/terraform/cluster-aws/cluster.tf +61 -0
  8. package/dist/terraform/cluster-aws/encryption.tofu.example +37 -0
  9. package/dist/terraform/cluster-aws/iam.tf +81 -0
  10. package/dist/terraform/cluster-aws/irsa_ebs_csi.tf +37 -0
  11. package/dist/terraform/cluster-aws/kubeconfig.tf +49 -0
  12. package/dist/terraform/cluster-aws/network.tf +108 -0
  13. package/dist/terraform/cluster-aws/nodegroup.tf +42 -0
  14. package/dist/terraform/cluster-aws/outputs.tf +80 -0
  15. package/dist/terraform/cluster-aws/providers.tf +7 -0
  16. package/dist/terraform/cluster-aws/terraform.tfvars.example +21 -0
  17. package/dist/terraform/cluster-aws/variables.tf +120 -0
  18. package/dist/terraform/cluster-aws/versions.tf +18 -0
  19. package/dist/terraform/cluster-azure/cluster.tf +83 -0
  20. package/dist/terraform/cluster-azure/encryption.tofu.example +37 -0
  21. package/dist/terraform/cluster-azure/identity.tf +9 -0
  22. package/dist/terraform/cluster-azure/kubeconfig.tf +18 -0
  23. package/dist/terraform/cluster-azure/network.tf +23 -0
  24. package/dist/terraform/cluster-azure/outputs.tf +69 -0
  25. package/dist/terraform/cluster-azure/providers.tf +16 -0
  26. package/dist/terraform/cluster-azure/terraform.tfvars.example +24 -0
  27. package/dist/terraform/cluster-azure/variables.tf +126 -0
  28. package/dist/terraform/cluster-azure/versions.tf +14 -0
  29. package/dist/terraform/cluster-gcp/cluster.tf +71 -0
  30. package/dist/terraform/cluster-gcp/encryption.tofu.example +35 -0
  31. package/dist/terraform/cluster-gcp/kubeconfig.tf +47 -0
  32. package/dist/terraform/cluster-gcp/network.tf +47 -0
  33. package/dist/terraform/cluster-gcp/outputs.tf +70 -0
  34. package/dist/terraform/cluster-gcp/providers.tf +14 -0
  35. package/dist/terraform/cluster-gcp/terraform.tfvars.example +17 -0
  36. package/dist/terraform/cluster-gcp/variables.tf +86 -0
  37. package/dist/terraform/cluster-gcp/versions.tf +14 -0
  38. package/dist/terraform/serverless-aws/alb.tf +127 -0
  39. package/dist/terraform/serverless-aws/database.tf +70 -0
  40. package/dist/terraform/serverless-aws/dns.tf +80 -0
  41. package/dist/terraform/serverless-aws/ecr.tf +63 -0
  42. package/dist/terraform/serverless-aws/ecs.tf +199 -0
  43. package/dist/terraform/serverless-aws/encryption.tofu.example +38 -0
  44. package/dist/terraform/serverless-aws/iam.tf +68 -0
  45. package/dist/terraform/serverless-aws/network.tf +190 -0
  46. package/dist/terraform/serverless-aws/outputs.tf +64 -0
  47. package/dist/terraform/serverless-aws/providers.tf +19 -0
  48. package/dist/terraform/serverless-aws/storage.tf +51 -0
  49. package/dist/terraform/serverless-aws/terraform.tfvars.example +19 -0
  50. package/dist/terraform/serverless-aws/variables.tf +151 -0
  51. package/dist/terraform/serverless-aws/versions.tf +14 -0
  52. package/package.json +23 -20
@@ -0,0 +1,18 @@
1
+ terraform {
2
+ required_version = ">= 1.6.0"
3
+
4
+ required_providers {
5
+ aws = {
6
+ source = "hashicorp/aws"
7
+ version = "~> 5.70"
8
+ }
9
+ tls = {
10
+ source = "hashicorp/tls"
11
+ version = "~> 4.0"
12
+ }
13
+ local = {
14
+ source = "hashicorp/local"
15
+ version = "~> 2.5"
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,83 @@
1
+ resource "azurerm_kubernetes_cluster" "main" {
2
+ name = local.cluster_name
3
+ resource_group_name = azurerm_resource_group.main.name
4
+ location = azurerm_resource_group.main.location
5
+ dns_prefix = local.cluster_name
6
+ kubernetes_version = length(var.k8s_version) > 0 ? var.k8s_version : null
7
+
8
+ tags = local.common_tags
9
+
10
+ # System node pool — runs kube-system workloads (CoreDNS, metrics-server,
11
+ # CSI controllers, etc.). One node is enough for shared-cluster workloads
12
+ # in MVP; scale up via the auto_scaling block on the user pool below.
13
+ default_node_pool {
14
+ name = "system"
15
+ vm_size = var.system_node_vm_size
16
+ node_count = 1
17
+ vnet_subnet_id = azurerm_subnet.nodes.id
18
+
19
+ only_critical_addons_enabled = true # taint: CriticalAddonsOnly=true:NoSchedule
20
+
21
+ upgrade_settings {
22
+ max_surge = "10%"
23
+ }
24
+ }
25
+
26
+ # System-assigned managed identity. The principal id below is what we'd
27
+ # grant RBAC to if the cluster needed read-only access to a key vault, etc.
28
+ identity {
29
+ type = "SystemAssigned"
30
+ }
31
+
32
+ # CNI Overlay mode — pod IPs come from `pod_cidr` rather than the VNet,
33
+ # which means we don't burn IPv4 space on pod density. Service IPs come
34
+ # from `service_cidr`.
35
+ network_profile {
36
+ network_plugin = "azure"
37
+ network_plugin_mode = "overlay"
38
+ pod_cidr = var.pod_cidr
39
+ service_cidr = var.service_cidr
40
+ dns_service_ip = var.dns_service_ip
41
+ load_balancer_sku = "standard"
42
+ }
43
+
44
+ # Workload Identity Federation (IRSA equivalent). Both flags must be on
45
+ # for pods to assume Azure SPs via service-account annotations.
46
+ oidc_issuer_enabled = true
47
+ workload_identity_enabled = true
48
+
49
+ # Local accounts stay enabled in MVP — that's what makes
50
+ # `kube_admin_config_raw` work without `kubelogin`. Production should
51
+ # disable this and switch to AAD-backed kubeconfig.
52
+ local_account_disabled = false
53
+
54
+ # AKS clusters get auto-upgrade by default in patch channel. Surface it
55
+ # so the operator knows.
56
+ automatic_upgrade_channel = "patch"
57
+
58
+ role_based_access_control_enabled = true
59
+ }
60
+
61
+ # User node pool — where the service plane (and large-tier datalake
62
+ # workloads) actually run. Autoscaling on, taint-free so pods land here
63
+ # rather than the tainted system pool.
64
+ resource "azurerm_kubernetes_cluster_node_pool" "user" {
65
+ name = "user"
66
+ kubernetes_cluster_id = azurerm_kubernetes_cluster.main.id
67
+ vm_size = var.node_vm_size
68
+ vnet_subnet_id = azurerm_subnet.nodes.id
69
+
70
+ auto_scaling_enabled = true
71
+ min_count = var.node_min_count
72
+ max_count = var.node_max_count
73
+
74
+ node_labels = {
75
+ "aries.xylabs.com/pool" = "shared"
76
+ }
77
+
78
+ upgrade_settings {
79
+ max_surge = "33%"
80
+ }
81
+
82
+ tags = local.common_tags
83
+ }
@@ -0,0 +1,37 @@
1
+ # OpenTofu state encryption — opt-in.
2
+ #
3
+ # Encrypts `terraform.tfstate` and any saved plan files at rest using
4
+ # AES-GCM with a key derived from `var.tfstate_passphrase` via PBKDF2.
5
+ #
6
+ # To enable:
7
+ # 1. cp encryption.tofu.example encryption.tofu (in the working dir)
8
+ # 2. export TF_VAR_tfstate_passphrase='at-least-16-characters'
9
+ # 3. tofu init -reconfigure
10
+ #
11
+ # Notes:
12
+ # - This file uses the `.tofu` extension so Terraform does NOT load it.
13
+ # Only OpenTofu engages encryption. Terraform users skip this block.
14
+ # - AKS state contains the kubelet identity object id, OIDC issuer URL,
15
+ # and (when `kube_admin_config_raw` is used) the cluster's admin
16
+ # certificate bundle. Keep it encrypted for anything beyond throwaway
17
+ # staging.
18
+
19
+ terraform {
20
+ encryption {
21
+ key_provider "pbkdf2" "default" {
22
+ passphrase = var.tfstate_passphrase
23
+ }
24
+
25
+ method "aes_gcm" "default" {
26
+ keys = key_provider.pbkdf2.default
27
+ }
28
+
29
+ state {
30
+ method = method.aes_gcm.default
31
+ }
32
+
33
+ plan {
34
+ method = method.aes_gcm.default
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,9 @@
1
+ # System-assigned managed identity for the cluster. AKS uses this to call
2
+ # Azure APIs (e.g., manage the load balancer for ingress-nginx Services,
3
+ # attach managed disks for PVCs). Equivalent to the EKS cluster role.
4
+ #
5
+ # We declare the identity inline on the cluster resource (`identity` block)
6
+ # rather than as a separate resource — that's the simpler pattern for the
7
+ # common case. Workload Identity Federation (the IRSA-equivalent for pods)
8
+ # is enabled via `workload_identity_enabled` on the cluster resource and
9
+ # bound per-pod via service-account annotations in the service plane.
@@ -0,0 +1,18 @@
1
+ # Render the cluster's admin kubeconfig into the working dir. AKS produces
2
+ # two kubeconfigs:
3
+ #
4
+ # - `kube_admin_config_raw` — local-account auth with embedded certs.
5
+ # Works out of the box without `kubelogin` or `az` exec plugins.
6
+ # - `kube_config_raw` — Azure AD auth via `kubelogin`. Requires the
7
+ # AAD-RBAC block on the cluster and `kubelogin` on the user's PATH.
8
+ #
9
+ # MVP uses the admin kubeconfig. Production should flip
10
+ # `local_account_disabled = true` on the cluster and switch to
11
+ # `kube_config_raw` plus a `kubelogin` install.
12
+
13
+ resource "local_sensitive_file" "kubeconfig" {
14
+ filename = "${path.cwd}/kubeconfig"
15
+ content = azurerm_kubernetes_cluster.main.kube_admin_config_raw
16
+ file_permission = "0600"
17
+ directory_permission = "0700"
18
+ }
@@ -0,0 +1,23 @@
1
+ resource "azurerm_resource_group" "main" {
2
+ name = local.resource_group_name
3
+ location = var.location
4
+ tags = local.common_tags
5
+ }
6
+
7
+ # Dedicated VNet for the cluster. We use Azure CNI Overlay mode (set on the
8
+ # AKS cluster) so pod IPs come from `pod_cidr` rather than the VNet — the
9
+ # subnet only needs to fit nodes, not pods.
10
+ resource "azurerm_virtual_network" "main" {
11
+ name = "${local.name_prefix}-vnet"
12
+ resource_group_name = azurerm_resource_group.main.name
13
+ location = azurerm_resource_group.main.location
14
+ address_space = [var.vnet_cidr]
15
+ tags = local.common_tags
16
+ }
17
+
18
+ resource "azurerm_subnet" "nodes" {
19
+ name = "nodes"
20
+ resource_group_name = azurerm_resource_group.main.name
21
+ virtual_network_name = azurerm_virtual_network.main.name
22
+ address_prefixes = [var.node_subnet_cidr]
23
+ }
@@ -0,0 +1,69 @@
1
+ output "cluster_name" {
2
+ description = "AKS cluster name."
3
+ value = azurerm_kubernetes_cluster.main.name
4
+ }
5
+
6
+ output "cluster_id" {
7
+ description = "Fully-qualified AKS cluster resource id."
8
+ value = azurerm_kubernetes_cluster.main.id
9
+ }
10
+
11
+ output "cluster_fqdn" {
12
+ description = "Public FQDN of the cluster's API server."
13
+ value = azurerm_kubernetes_cluster.main.fqdn
14
+ }
15
+
16
+ output "resource_group_name" {
17
+ description = "Resource group containing the cluster."
18
+ value = azurerm_resource_group.main.name
19
+ }
20
+
21
+ output "oidc_issuer_url" {
22
+ description = "OIDC issuer URL — used to federate Microsoft Entra Workload IDs onto Kubernetes ServiceAccounts."
23
+ value = azurerm_kubernetes_cluster.main.oidc_issuer_url
24
+ }
25
+
26
+ output "kubelet_identity_object_id" {
27
+ description = "Object id of the kubelet identity (used when granting AcrPull etc. for ACR integration)."
28
+ value = azurerm_kubernetes_cluster.main.kubelet_identity[0].object_id
29
+ }
30
+
31
+ output "vnet_id" {
32
+ description = "Dedicated VNet id."
33
+ value = azurerm_virtual_network.main.id
34
+ }
35
+
36
+ output "node_subnet_id" {
37
+ description = "Subnet id the node pools live in."
38
+ value = azurerm_subnet.nodes.id
39
+ }
40
+
41
+ output "kubeconfig_path" {
42
+ description = "Path to the rendered kubeconfig (relative to the working dir)."
43
+ value = local_sensitive_file.kubeconfig.filename
44
+ }
45
+
46
+ output "location" {
47
+ description = "Azure region the cluster lives in."
48
+ value = var.location
49
+ }
50
+
51
+ output "subscription_id" {
52
+ description = "Azure subscription id."
53
+ value = var.subscription_id
54
+ }
55
+
56
+ # Tier-2 → Tier-3 hand-off shape. The CLI projects this into ~/.aries/cluster/<name>/cluster.yaml.
57
+ output "service_target" {
58
+ description = "ServiceTarget(kubernetes) shape consumed by the Tier-3 service plane."
59
+ value = {
60
+ kind = "kubernetes"
61
+ cloud = "azure"
62
+ cluster_name = azurerm_kubernetes_cluster.main.name
63
+ region = var.location
64
+ namespace = "aries-datalake"
65
+ ingress_class = "nginx"
66
+ storage_class = "managed-csi"
67
+ kubeconfig = local_sensitive_file.kubeconfig.filename
68
+ }
69
+ }
@@ -0,0 +1,16 @@
1
+ # Auth: the provider uses your active `az login` session by default.
2
+ # Set `ARM_*` env vars (ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID,
3
+ # ARM_SUBSCRIPTION_ID) to override with a service principal in CI.
4
+ #
5
+ # The `features {}` block is required by azurerm even when empty.
6
+
7
+ provider "azurerm" {
8
+ subscription_id = var.subscription_id
9
+ tenant_id = var.tenant_id != "" ? var.tenant_id : null
10
+
11
+ features {
12
+ resource_group {
13
+ prevent_deletion_if_contains_resources = false
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,24 @@
1
+ subscription_id = "" # required — `az account show --query id -o tsv`
2
+ # tenant_id = "" # leave empty to use the tenant from `az login`
3
+
4
+ location = "eastus"
5
+ environment = "staging"
6
+ project = "aries-datalake"
7
+
8
+ # cluster_name and resource_group_name default to the project+environment.
9
+ # cluster_name = "aries-datalake-staging"
10
+ # resource_group_name = "aries-datalake-staging-rg"
11
+
12
+ # k8s_version = "1.31" # leave empty for the AKS regional default
13
+
14
+ # vnet_cidr = "10.45.0.0/16"
15
+ # node_subnet_cidr = "10.45.0.0/22"
16
+ # pod_cidr = "10.244.0.0/16"
17
+ # service_cidr = "10.0.0.0/16"
18
+ # dns_service_ip = "10.0.0.10"
19
+
20
+ # node_vm_size = "Standard_D2s_v5" # ~ t3.medium / e2-standard-2
21
+ # system_node_vm_size = "Standard_D2s_v5"
22
+ # node_count = 2
23
+ # node_min_count = 1
24
+ # node_max_count = 4
@@ -0,0 +1,126 @@
1
+ variable "subscription_id" {
2
+ type = string
3
+ description = "Azure subscription id the cluster lives in."
4
+ }
5
+
6
+ variable "tenant_id" {
7
+ type = string
8
+ description = "Azure tenant id. Leave empty to use the tenant from your active `az login`."
9
+ default = ""
10
+ }
11
+
12
+ variable "location" {
13
+ type = string
14
+ description = "Azure region. Mirrors the `region` knob in cluster-aws / cluster-gcp."
15
+ default = "eastus"
16
+ }
17
+
18
+ variable "environment" {
19
+ type = string
20
+ description = "Environment name (staging, prod, etc.). Goes into resource tags + names."
21
+ default = "staging"
22
+ }
23
+
24
+ variable "project" {
25
+ type = string
26
+ description = "Project tag (analog of AWS `Project`)."
27
+ default = "aries-datalake"
28
+ }
29
+
30
+ variable "cluster_name" {
31
+ type = string
32
+ description = "AKS cluster name. Defaults to `${var.project}-${var.environment}`."
33
+ default = ""
34
+ }
35
+
36
+ variable "resource_group_name" {
37
+ type = string
38
+ description = "Resource group name. Defaults to `<cluster_name>-rg`. Always created by this module."
39
+ default = ""
40
+ }
41
+
42
+ variable "k8s_version" {
43
+ type = string
44
+ description = "Kubernetes version. Leave empty to pull the AKS default for the region."
45
+ default = ""
46
+ }
47
+
48
+ variable "vnet_cidr" {
49
+ type = string
50
+ description = "VNet CIDR block. Must not overlap compute-aws (10.42), cluster-aws (10.43), cluster-gcp (10.44) if you ever peer them."
51
+ default = "10.45.0.0/16"
52
+ }
53
+
54
+ variable "node_subnet_cidr" {
55
+ type = string
56
+ description = "Subnet CIDR within the VNet that hosts AKS nodes."
57
+ default = "10.45.0.0/22"
58
+ }
59
+
60
+ variable "pod_cidr" {
61
+ type = string
62
+ description = "Overlay CIDR for pod IPs (CNI Overlay mode). Doesn't need to live inside the VNet."
63
+ default = "10.244.0.0/16"
64
+ }
65
+
66
+ variable "service_cidr" {
67
+ type = string
68
+ description = "Kubernetes Services CIDR."
69
+ default = "10.0.0.0/16"
70
+ }
71
+
72
+ variable "dns_service_ip" {
73
+ type = string
74
+ description = "kube-dns IP — must be inside service_cidr."
75
+ default = "10.0.0.10"
76
+ }
77
+
78
+ variable "node_vm_size" {
79
+ type = string
80
+ description = "VM SKU for the default node pool. Standard_D2s_v5 ≈ t3.medium ≈ e2-standard-2."
81
+ default = "Standard_D2s_v5"
82
+ }
83
+
84
+ variable "node_count" {
85
+ type = number
86
+ description = "Starting node count for the default user pool."
87
+ default = 2
88
+ }
89
+
90
+ variable "node_min_count" {
91
+ type = number
92
+ description = "Autoscaler floor for the default user pool."
93
+ default = 1
94
+ }
95
+
96
+ variable "node_max_count" {
97
+ type = number
98
+ description = "Autoscaler ceiling for the default user pool."
99
+ default = 4
100
+ }
101
+
102
+ variable "system_node_vm_size" {
103
+ type = string
104
+ description = "VM SKU for the system node pool (kube-system workloads)."
105
+ default = "Standard_D2s_v5"
106
+ }
107
+
108
+ variable "tfstate_passphrase" {
109
+ type = string
110
+ description = "Passphrase for OpenTofu state encryption. See encryption.tofu.example."
111
+ default = ""
112
+ sensitive = true
113
+ }
114
+
115
+ locals {
116
+ cluster_name = length(var.cluster_name) > 0 ? var.cluster_name : "${var.project}-${var.environment}"
117
+ resource_group_name = length(var.resource_group_name) > 0 ? var.resource_group_name : "${local.cluster_name}-rg"
118
+ name_prefix = "${var.project}-${var.environment}-cluster"
119
+
120
+ common_tags = {
121
+ project = var.project
122
+ environment = var.environment
123
+ component = "cluster"
124
+ managed-by = "opentofu"
125
+ }
126
+ }
@@ -0,0 +1,14 @@
1
+ terraform {
2
+ required_version = ">= 1.6.0"
3
+
4
+ required_providers {
5
+ azurerm = {
6
+ source = "hashicorp/azurerm"
7
+ version = "~> 4.10"
8
+ }
9
+ local = {
10
+ source = "hashicorp/local"
11
+ version = "~> 2.5"
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,71 @@
1
+ resource "google_container_cluster" "main" {
2
+ name = local.cluster_name
3
+ location = var.region
4
+
5
+ network = google_compute_network.main.id
6
+ subnetwork = google_compute_subnetwork.main.id
7
+
8
+ # Autopilot: Google manages nodes, scales pools, autoscales node count,
9
+ # and enforces opinionated security defaults. Less knob surface, less to
10
+ # break — right call for "Atlas-style hosted datalake". Switch to
11
+ # Standard mode if a customer needs custom node-pool isolation that
12
+ # Autopilot's per-pod scheduling can't satisfy.
13
+ enable_autopilot = true
14
+
15
+ ip_allocation_policy {
16
+ cluster_secondary_range_name = "pods"
17
+ services_secondary_range_name = "services"
18
+ }
19
+
20
+ release_channel {
21
+ channel = var.release_channel
22
+ }
23
+
24
+ # Workload Identity is on by default in Autopilot — pods assume a GCP
25
+ # service account via the `iam.gke.io/gcp-service-account` annotation on
26
+ # their KSA. Equivalent to AWS IRSA. The service plane will use this in
27
+ # phase 6 when the data plane talks to GCS for the archive tier.
28
+ workload_identity_config {
29
+ workload_pool = "${var.project_id}.svc.id.goog"
30
+ }
31
+
32
+ # Master endpoint stays public for now — same posture as cluster-aws.
33
+ # Tighten via master_authorized_networks_config below or flip to
34
+ # `enable_private_endpoint = true` when PrivateLink/IAP work lands.
35
+ master_authorized_networks_config {
36
+ dynamic "cidr_blocks" {
37
+ for_each = var.master_authorized_networks
38
+ content {
39
+ cidr_block = cidr_blocks.value.cidr_block
40
+ display_name = cidr_blocks.value.display_name
41
+ }
42
+ }
43
+ }
44
+
45
+ # Surface control-plane logs & metrics to Cloud Logging / Monitoring so
46
+ # the SRE team isn't blind on day 1. Autopilot bills for these by default.
47
+ logging_config {
48
+ enable_components = ["SYSTEM_COMPONENTS", "WORKLOADS"]
49
+ }
50
+
51
+ monitoring_config {
52
+ enable_components = ["SYSTEM_COMPONENTS"]
53
+ managed_prometheus {
54
+ enabled = true
55
+ }
56
+ }
57
+
58
+ # Deletion protection defaults on for prod environments. Staging users
59
+ # can flip via the environment label.
60
+ deletion_protection = var.environment == "prod"
61
+
62
+ resource_labels = {
63
+ component = "cluster"
64
+ }
65
+ }
66
+
67
+ # Look up the project number — Workload Identity bindings use it in the
68
+ # `serviceAccount:<project>.svc.id.goog[<namespace>/<ksa>]` subject form.
69
+ data "google_project" "main" {
70
+ project_id = var.project_id
71
+ }
@@ -0,0 +1,35 @@
1
+ # OpenTofu state encryption — opt-in.
2
+ #
3
+ # Encrypts `terraform.tfstate` and any saved plan files at rest using
4
+ # AES-GCM with a key derived from `var.tfstate_passphrase` via PBKDF2.
5
+ #
6
+ # To enable:
7
+ # 1. cp encryption.tofu.example encryption.tofu (in the working dir)
8
+ # 2. export TF_VAR_tfstate_passphrase='at-least-16-characters'
9
+ # 3. tofu init -reconfigure
10
+ #
11
+ # Notes:
12
+ # - This file uses the `.tofu` extension so Terraform does NOT load it.
13
+ # Only OpenTofu engages encryption. Terraform users skip this block.
14
+ # - GKE state contains the cluster CA bundle and project number — keep
15
+ # it encrypted for anything beyond throwaway staging.
16
+
17
+ terraform {
18
+ encryption {
19
+ key_provider "pbkdf2" "default" {
20
+ passphrase = var.tfstate_passphrase
21
+ }
22
+
23
+ method "aes_gcm" "default" {
24
+ keys = key_provider.pbkdf2.default
25
+ }
26
+
27
+ state {
28
+ method = method.aes_gcm.default
29
+ }
30
+
31
+ plan {
32
+ method = method.aes_gcm.default
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,47 @@
1
+ # Render a kubeconfig into the working dir. The `exec` block delegates
2
+ # auth to `gke-gcloud-auth-plugin`, which is the supported way to talk to
3
+ # GKE after kubectl 1.26+. Users must install it once:
4
+ #
5
+ # gcloud components install gke-gcloud-auth-plugin
6
+ #
7
+ # Like the EKS kubeconfig, this carries no long-lived secrets — the plugin
8
+ # refreshes tokens from the user's gcloud auth state on every call.
9
+
10
+ locals {
11
+ kubeconfig_yaml = yamlencode({
12
+ apiVersion = "v1"
13
+ kind = "Config"
14
+ current-context = "aries-${local.cluster_name}"
15
+ clusters = [{
16
+ name = "aries-${local.cluster_name}"
17
+ cluster = {
18
+ server = "https://${google_container_cluster.main.endpoint}"
19
+ "certificate-authority-data" = google_container_cluster.main.master_auth[0].cluster_ca_certificate
20
+ }
21
+ }]
22
+ contexts = [{
23
+ name = "aries-${local.cluster_name}"
24
+ context = {
25
+ cluster = "aries-${local.cluster_name}"
26
+ user = "aries-${local.cluster_name}"
27
+ }
28
+ }]
29
+ users = [{
30
+ name = "aries-${local.cluster_name}"
31
+ user = {
32
+ exec = {
33
+ apiVersion = "client.authentication.k8s.io/v1beta1"
34
+ command = "gke-gcloud-auth-plugin"
35
+ provideClusterInfo = true
36
+ }
37
+ }
38
+ }]
39
+ })
40
+ }
41
+
42
+ resource "local_sensitive_file" "kubeconfig" {
43
+ filename = "${path.cwd}/kubeconfig"
44
+ content = local.kubeconfig_yaml
45
+ file_permission = "0600"
46
+ directory_permission = "0700"
47
+ }
@@ -0,0 +1,47 @@
1
+ resource "google_compute_network" "main" {
2
+ name = "${local.name_prefix}-vpc"
3
+ auto_create_subnetworks = false
4
+ routing_mode = "REGIONAL"
5
+ }
6
+
7
+ # One regional subnet with secondary IP ranges for pods + services — this
8
+ # is the VPC-native ("alias-IP") setup GKE Autopilot requires. Public IPs
9
+ # never get assigned to pods; egress goes through Cloud NAT below.
10
+ resource "google_compute_subnetwork" "main" {
11
+ name = "${local.name_prefix}-subnet"
12
+ network = google_compute_network.main.id
13
+ region = var.region
14
+ ip_cidr_range = var.vpc_cidr
15
+
16
+ private_ip_google_access = true
17
+
18
+ secondary_ip_range {
19
+ range_name = "pods"
20
+ ip_cidr_range = var.pods_cidr
21
+ }
22
+ secondary_ip_range {
23
+ range_name = "services"
24
+ ip_cidr_range = var.services_cidr
25
+ }
26
+ }
27
+
28
+ resource "google_compute_router" "main" {
29
+ name = "${local.name_prefix}-router"
30
+ network = google_compute_network.main.id
31
+ region = var.region
32
+ }
33
+
34
+ # Autopilot nodes have no external IPs by default — they need NAT to pull
35
+ # container images, reach external APIs, etc.
36
+ resource "google_compute_router_nat" "main" {
37
+ name = "${local.name_prefix}-nat"
38
+ router = google_compute_router.main.name
39
+ region = var.region
40
+ nat_ip_allocate_option = "AUTO_ONLY"
41
+ source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
42
+
43
+ log_config {
44
+ enable = true
45
+ filter = "ERRORS_ONLY"
46
+ }
47
+ }