Skip to content

cozystack/terraform-provider-cozystack

terraform-provider-cozystack

A Terraform / OpenTofu provider for Cozystack. It manages Cozystack applications through the aggregated Kubernetes API (apps.cozystack.io), so a Cozystack platform can be driven as Infrastructure as Code with the same kubeconfig you already use.

Supported resources

Every kind is served by the same aggregated API, so the provider is built to grow one kind at a time. Adding a kind is a typed model, a schema, and a one-line resource descriptor — the create/read/update/delete/import/wait logic is shared.

Kind Resource Data source
Tenant — isolated namespace under a parent tenant cozystack_tenant cozystack_tenant
Managed Redis cozystack_redis cozystack_redis
Managed Qdrant (vector database) cozystack_qdrant cozystack_qdrant
S3-compatible bucket cozystack_bucket cozystack_bucket
Managed OpenBAO (Vault-compatible) cozystack_openbao cozystack_openbao
VPN server cozystack_vpn cozystack_vpn
Managed RabbitMQ cozystack_rabbitmq cozystack_rabbitmq
Managed MariaDB cozystack_mariadb cozystack_mariadb
Managed MongoDB cozystack_mongodb cozystack_mongodb
Managed ClickHouse cozystack_clickhouse cozystack_clickhouse
Managed NATS cozystack_nats cozystack_nats
Managed OpenSearch cozystack_opensearch cozystack_opensearch
Managed PostgreSQL cozystack_postgres cozystack_postgres
HTTP cache cozystack_httpcache cozystack_httpcache
TCP load balancer cozystack_tcpbalancer cozystack_tcpbalancer
Harbor registry cozystack_harbor cozystack_harbor
Virtual private cloud cozystack_vpc cozystack_vpc
Virtual machine disk cozystack_vmdisk cozystack_vmdisk
Managed Kafka cozystack_kafka cozystack_kafka
Managed FoundationDB cozystack_foundationdb cozystack_foundationdb
Virtual machine instance cozystack_vminstance cozystack_vminstance
Managed Kubernetes cozystack_kubernetes cozystack_kubernetes

Every kind served by the aggregated apps.cozystack.io API is now covered.

Platform resources (cozystack.io group)

Beyond the namespaced tenant apps, the provider also manages the cluster-scoped platform resources in the cozystack.io group — useful for platform-as-code:

Kind Resource Data source
Package — install a package variant cozystack_package cozystack_package
PackageSource — where packages come from cozystack_package_source cozystack_package_source
ApplicationDefinition — register an app kind cozystack_application_definition cozystack_application_definition
SchedulingClass — named placement policy cozystack_scheduling_class cozystack_scheduling_class

These are cluster-scoped (imported by name, no namespace). cozystack_package is fully typed (variant, ignore_dependencies, per-component overrides). The other three are platform-definition documents whose deeply-nested, version-coupled specs are surfaced as a single normalized-JSON spec attribute (write with jsonencode, read back with jsondecode) rather than brittle per-field modeling.

Backups and dashboard

The same JSON-spec passthrough also covers the backup framework and dashboard panels:

Kind Resource Data source
Plan (typed) cozystack_backup_plan cozystack_backup_plan
RestoreJob (typed) cozystack_restore_job cozystack_restore_job
BackupClass cozystack_backup_class cozystack_backup_class
Backup cozystack_backup cozystack_backup
BackupJob cozystack_backup_job cozystack_backup_job
MarketplacePanel cozystack_marketplace_panel cozystack_marketplace_panel

backup_plan (schedule a backup) and restore_job (restore a backup) are user-authored, so they are fully typed (application_ref, backup_class_name, schedule / backup_name, target_application_ref, options). The remaining backups kinds are records or driver config and stay JSON-spec.

Tenant core resources (core.cozystack.io)

These do not follow the spec pattern, so they have purpose-built models:

Kind Resource Shape
TenantSecret cozystack_tenant_secret Secret-shaped: type + data (plaintext in, stored base64)
TenantModule cozystack_tenant_module namespaced marker (existence enables the module)
TenantNamespace cozystack_tenant_namespace cluster-scoped marker

Deliberately not exposed: the strategy.backups.cozystack.io per-engine backup strategies and the dashboard.cozystack.io UI-customization CRDs (Sidebar, Navigation, Factory, …) — platform internals shipped and reconciled by Cozystack itself, with no Infrastructure-as-Code use case.

Authentication mirrors the official kubernetes provider: config_path/config_context, host/token, cluster_ca_certificate, client_certificate/client_key, an in_cluster toggle, and an exec {} credential-plugin block for OIDC login helpers (kubectl oidc-login). OIDC via a kubeconfig already works through config_path with no extra configuration.

Referencing outputs

The aggregated API is write-oriented: it takes a spec and returns a thin status. The connection details you actually want to reference — endpoints, credentials, a child cluster's kubeconfig, a VM's IP — are materialised by the underlying charts as Secrets, Services, and KubeVirt status. The provider reads those and exposes them as computed (sensitive where appropriate) attributes:

  • cozystack_kubernetes.<x>.kubeconfig — admin kubeconfig of the provisioned cluster, for chaining the kubernetes/helm providers into it.
  • cozystack_postgres.<x>.endpoints{ host, read_host, port } from the CNPG rw/ro Services.
  • cozystack_bucket.<x>.credentials["<user>"]{ endpoint, bucket_name, region, access_key, secret_key } per user.
  • cozystack_vminstance.<x>.ip_address / .ip_addresses — guest addresses from the backing VirtualMachineInstance.

These are populated asynchronously, after the application is ready. Set wait_for_ready = true on the resource you consume so they are available on first apply rather than on a later refresh.

Keeping secrets out of state

To avoid persisting secrets in state, the provider offers modern Terraform secret handling:

  • Ephemeral resources (ephemeral "cozystack_kubernetes", ephemeral "cozystack_tenant_secret") fetch a cluster kubeconfig or a tenant secret at apply time, usable to configure downstream providers, without ever writing the value to state.
  • Write-only inputscozystack_tenant_secret accepts data_wo (write-only, sent on apply but never stored; bump data_wo_version to push changes) alongside the state-persisted data.
resource "cozystack_kubernetes" "app" {
  name           = "app"
  namespace      = "tenant-root"
  node_groups    = { md0 = { min_replicas = 1, max_replicas = 3 } }
  wait_for_ready = true
}

provider "kubernetes" {
  alias = "app"
  # chain straight into the cluster this provider just created
  # (parse cozystack_kubernetes.app.kubeconfig with the helm/kubernetes provider's
  #  config_path written from it, or your preferred kubeconfig wiring)
}

The names of these backing Secrets/Services are chart conventions (postgres-<name>-rw, bucket-<name>-<user>, kubernetes-<name>-admin-kubeconfig), pinned to the supported Cozystack version — not part of the stable aggregated-API contract.

Requirements

  • Terraform >= 1.0 or OpenTofu >= 1.6
  • A running Cozystack cluster and a kubeconfig (or bearer token) that can reach its API

Usage

terraform {
  required_providers {
    cozystack = {
      source = "cozystack/cozystack"
    }
  }
}

provider "cozystack" {
  config_path    = "~/.kube/config"
  config_context = "my-cozystack-cluster"
}

resource "cozystack_tenant" "team_a" {
  name      = "team-a"
  namespace = "tenant-root"

  monitoring = true
  ingress    = true
}

resource "cozystack_redis" "cache" {
  name      = "cache"
  namespace = cozystack_tenant.team_a.status_namespace

  replicas = 2
  version  = "v8"
}

Resources are namespaced by tenant, so other applications reference a tenant's status_namespace to deploy inside it.

Authentication

Connection settings mirror the official kubernetes provider, so existing kubeconfig and environment conventions transfer directly. Every provider attribute is optional and falls back to a KUBE_* environment variable: config_path (KUBE_CONFIG_PATH, then KUBECONFIG), config_context (KUBE_CTX), host (KUBE_HOST), token (KUBE_TOKEN), cluster_ca_certificate (KUBE_CLUSTER_CA_CERT_DATA), and insecure (KUBE_INSECURE). Set in_cluster = true to use a pod's service account instead of a kubeconfig.

Local install

Until a release is published to the registry, build the provider and point Terraform/OpenTofu at it with a dev override:

make install   # go install into $GOBIN
# ~/.terraformrc  (or a file referenced by TF_CLI_CONFIG_FILE)
provider_installation {
  dev_overrides {
    "registry.terraform.io/cozystack/cozystack" = "/path/to/your/gobin"
  }
  direct {}
}

Development

make build   # build the provider binary
make test    # unit tests with the race detector
make lint    # golangci-lint
make docs    # regenerate docs/ with tfplugindocs

Acceptance tests create and destroy real applications and need a reachable Cozystack cluster:

KUBECONFIG=/path/to/kubeconfig KUBE_CTX=my-context make testacc

The acceptance harness drives the Terraform CLI; the testacc target points TF_ACC_TERRAFORM_PATH at tofu automatically so it runs against OpenTofu when Terraform is not installed.

See CONTRIBUTING.md for the full workflow and SECURITY.md for vulnerability reporting and credential-handling guidance.

License

BSD-3-Clause

About

Terraform/OpenTofu provider for managing Cozystack applications via the apps.cozystack.io aggregated API

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages