Terraform & OpenTofu
The Aether provider manages clusters, node pools, network policy, members,
webhooks, the registry and the billing budget. It works with Terraform 1.5+
and OpenTofu 1.6+ under the same source address, plane-shift/aether.
Every command below works with terraform or tofu.
The provider is available from its first release, v0.1.0, on the Terraform
Registry and the OpenTofu Registry. Until that release is published,
terraform init cannot download it and the registry links on this page do not
resolve.
1. Create an API token
Section titled “1. Create an API token”Create a token in the portal under Settings → API Tokens. A token
belongs to one organization, and the provider uses that organization for every
resource. Tokens are managed in the portal only; the provider has no resource
for them. Keep it out of your files: export AETHER_API_TOKEN=aether_....
2. Configure the provider
Section titled “2. Configure the provider”terraform { required_version = ">= 1.5" # OpenTofu >= 1.6 works the same way required_providers { aether = { source = "plane-shift/aether" version = "~> 0.1" } }}
variable "aether_api_token" { type = string sensitive = true default = null # unset here so the provider falls back to AETHER_API_TOKEN}
# Create an API token in the Aether portal first (Settings → API Tokens).provider "aether" { api_token = var.aether_api_token # or AETHER_API_TOKEN # endpoint defaults to https://api.aetherplatform.cloud (production); # use https://dev.api.aetherplatform.cloud for the dev environment (or AETHER_ENDPOINT).}endpoint selects the API (production by default). Resources take no
organization: it comes from the token. The region is eu-fi.
3. A cluster with node pools
Section titled “3. A cluster with node pools”data "aether_k8s_versions" "offered" {}
resource "aether_cluster" "prod" { name = "prod" region = "eu-fi" # latest is null while the platform's version window is unavailable; pin a # minor instead (e.g. "1.37") if that's not acceptable. k8s_version = data.aether_k8s_versions.offered.latest # Defaults to true: the public API endpoint is billed as one public IP (€4/month). public_endpoint = true}
# Fixed pool: a flat monthly fee for desired_nodes nodes.resource "aether_node_pool" "workers" { cluster_id = aether_cluster.prod.id name = "workers" vcpus = 4 memory_gb = 16 disk_gb = 80 desired_nodes = 3}
# Autoscaling pool: a vCPU/memory budget with max > min makes it autoscaling (billed hourly per node).resource "aether_node_pool" "burst" { cluster_id = aether_cluster.prod.id name = "burst" vcpus = 4 memory_gb = 16 disk_gb = 80 min_vcpus = 4 max_vcpus = 32 min_memory_gb = 16 max_memory_gb = 128}
data "aether_kubeconfig" "prod" { cluster_id = aether_cluster.prod.id}
output "kubeconfig" { value = data.aether_kubeconfig.prod.content sensitive = true}apply creates the cluster and pools and waits until each is running. A
cluster that ends degraded is reported as a warning.
4. Import your organization
Section titled “4. Import your organization”Your organization is created when you register, so the provider cannot create
one. Adopt it instead. The aether_organization data source exposes its id.
# Import-only: this resource cannot create an organization (see the import command below).# The slug cannot be changed from Terraform; "" clears an optional field.resource "aether_organization" "this" { name = "Example Ltd" billing_email = "billing@example.com" vat_id = "FI12345678"}terraform import aether_organization.this 00000000-0000-0000-0000-000000000000# OpenTofu: tofu import aether_organization.this 00000000-0000-0000-0000-000000000000After the import, run terraform show to read the organization’s real name,
billing_email and vat_id, then replace the placeholder values in the block
above with them before you apply. Applying with the placeholders still in
place would overwrite the organization’s real values with the example ones.
5. Read the kubeconfig
Section titled “5. Read the kubeconfig”terraform output -raw kubeconfig > kubeconfig writes the admin
kubeconfig, which has full control of the cluster. It is readable only while
the cluster is running. Your state is a secret: it holds this kubeconfig,
registry robot secrets and webhook signing secrets in plain text. Keep state in
an encrypted backend with restricted access.
What to know
Section titled “What to know”- Public endpoint:
public_endpointdefaults totrueand costs €4/month. - Destroying
aether_registrydeletes every robot account of the organization. Images are kept unlesspurge_on_destroy = true, which is irreversible. - An enabled
deletecleanup policy runs within about a minute of the apply. Start withaction = "protect"orenabled = false. aether_audit_logreads a single page (setlimit). It is not the full history.- Secrets appear once. Robot secrets and the registry credentials are returned only on create; webhook signing secrets on create and on rotation (
rotate_secret). They are empty after an import. - Some changes replace. Changing a pool’s
name,vcpus,memory_gbordisk_gb, or a member’srole, destroys and recreates it. - Destroying
aether_cluster_networkopens the public endpoint to every address.
Full reference: from the first release (v0.1.0), the provider docs will be on the Terraform Registry and the OpenTofu Registry.