Skip to main content

Terraform provider

The yuccastream/tuna provider manages tuna resources as code: domains and domain zones, gateways, endpoints, IP policies, TLS certificates, SSH keys and temporal tokens. It works with Terraform and OpenTofu.

The provider is in the Terraform Registry

The reference for all resources and attributes is on the yuccastream/tuna page in the Terraform Registry.

Installation​

Terraform 1.11 or newer is required: older versions do not support write-only attributes, which are used to pass the TLS certificate private key.

terraform {
required_version = ">= 1.11"

required_providers {
tuna = {
source = "yuccastream/tuna"
}
}
}

provider "tuna" {}
terraform init

The provider is not in the OpenTofu Registry yet. With OpenTofu, set the registry explicitly: source = "registry.terraform.io/yuccastream/tuna".

Authentication​

The provider needs an API key. Issue one in the dashboard with the tunnels:write scope: it covers every resource of the provider, full api access is not needed. A key with the default read_api scope is read-only, apply will fail with it.

API keys cannot be issued through the API, so the provider does not manage them: create keys in the dashboard only.

Pass the key via an environment variable (recommended) or in the provider block:

export TUNA_API_KEY="<API key>"
provider "tuna" {
api_key = var.tuna_api_key
}
ArgumentEnvironment variableDescription
api_keyTUNA_API_KEYAPI key
api_urlTUNA_API_URLAPI address, https://api.tuna.am by default

Resources​

ResourceManages
tuna_domainReserved domain: a subdomain of a built-in zone, of your own zone, or a custom domain
tuna_domain_zoneDomain zone
tuna_tls_certificateTLS certificate for a domain zone
tuna_gatewayGateway on a reserved domain
tuna_endpointTCP port
tuna_ip_policyIP policy
tuna_ip_policy_ruleIP policy rule
tuna_public_keyPublic SSH key
tuna_temporal_tokenTemporal token for running tunnels

The tuna_tunnels data source returns the tunnels of the account.

The location argument of domains, zones and endpoints accepts ru or nl.

The full attribute reference is in the Terraform Registry.

Scenario: temporal tunnels for CI​

Terraform reserves a domain and issues a limited temporal token, and a CI job starts a tunnel with that token. The main API key never reaches CI.

resource "tuna_domain" "preview" {
subdomain = "myapp-preview"
location = "ru"
}

resource "tuna_temporal_token" "ci" {
description = "CI preview"
duration = "24h"
allow_http = true
allow_tcp = false
limit_by_active_tunnels = 5
limit_by_created_tunnels = 100
}

output "ci_tunnel_token" {
value = tuna_temporal_token.ci.token
sensitive = true
}

The token is marked sensitive, so read it explicitly:

terraform apply
export TUNA_TOKEN="$(terraform output -raw ci_tunnel_token)"
tuna http 8080 --subdomain=myapp-preview

Check that the tunnel is up with the data source:

data "tuna_tunnels" "all" {}

output "active_tunnels" {
value = [for t in data.tuna_tunnels.all.tunnels : t.public_url if t.active]
}

Scenario: own zone with a certificate and IP access​

resource "tuna_tls_certificate" "wildcard" {
description = "wildcard for tunnels.example.com"
certificate_pem = file("${path.module}/cert.pem")
private_key_pem = file("${path.module}/key.pem")
}

resource "tuna_domain_zone" "example" {
domain = "tunnels.example.com"
location = "ru"
tls_certificate_id = tuna_tls_certificate.wildcard.id
}

resource "tuna_domain" "app" {
subdomain = "app"
location = "ru"
domain_zone_id = tuna_domain_zone.example.id
}

resource "tuna_ip_policy" "office" {
name = "office-only"
active = true
}

resource "tuna_ip_policy_rule" "office_allow" {
ip_policy_id = tuna_ip_policy.office.id
name = "office"
cidr = "203.0.113.0/24"
action = "allow"
}

private_key_pem is a write-only attribute: the provider sends the key to the API but does not store it in state.

Gateway​

resource "tuna_domain" "api" {
subdomain = "myapp-api"
location = "ru"
}

resource "tuna_gateway" "api" {
domain_id = tuna_domain.api.id
policy = file("${path.module}/policy.yaml")
}

policy.yaml holds a traffic policy. A domain with a gateway is taken by the gateway: a tunnel on it will not start, the server responds with Domain already reserved by gateway. Reserve a separate domain for the tunnel.

Changing resources​

The API cannot edit endpoints, domains, domain zones and temporal tokens, so any change of their attributes (including alias or description) recreates the resource. A temporal token also gets a new value: tunnels started with the old token have to be restarted.

Gateways, IP policies and their rules are updated in place. A rule is recreated only when ip_policy_id changes.

Import​

Existing resources are imported by their numeric ID from the dashboard or the API:

terraform import tuna_domain.app 123
terraform import tuna_gateway.api 123

An IP policy rule has a composite ID <ip_policy_id>/<rule_id>:

terraform import tuna_ip_policy_rule.office_allow 123/456

The API does not return the certificate private key, so after importing tuna_tls_certificate set private_key_pem in the configuration.