# Terraform-провайдер

Провайдер `yuccastream/tuna` описывает ресурсы tuna кодом: домены и доменные зоны, шлюзы, эндпоинты, IP-политики, TLS-сертификаты, SSH-ключи и временные токены. Работает с Terraform и OpenTofu.

Провайдер в Terraform Registry

Документация по всем ресурсам и атрибутам — на странице [yuccastream/tuna](https://registry.terraform.io/providers/yuccastream/tuna/latest/docs) в Terraform Registry.

## Установка

Нужен Terraform 1.11 или новее: в более старых версиях не работают write-only атрибуты, а через них передаётся приватный ключ TLS-сертификата.

```hcl
terraform {
  required_version = ">= 1.11"

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

provider "tuna" {}

```

```bash
terraform init

```

В OpenTofu Registry провайдера пока нет. Для OpenTofu укажите реестр явно: `source = "registry.terraform.io/yuccastream/tuna"`.

## Аутентификация

Провайдеру нужен API-ключ. Выпустите его в [личном кабинете](https://my.tuna.am/api_keys) со скоупом `tunnels:write`: этого достаточно для всех ресурсов провайдера, полный доступ `api` не нужен. Ключ со скоупом по умолчанию `read_api` подходит только для чтения, `apply` с ним завершится ошибкой.

API-ключ нельзя выпустить через API, поэтому провайдер не управляет ключами: их создают только в личном кабинете.

Ключ передаётся переменной окружения (рекомендуется) или в блоке `provider`:

```bash
export TUNA_API_KEY="<API-ключ>"

```

```hcl
provider "tuna" {
  api_key = var.tuna_api_key
}

```

| Параметр  | Переменная окружения | Описание                                      |
| --------- | -------------------- | --------------------------------------------- |
| `api_key` | `TUNA_API_KEY`       | API-ключ                                      |
| `api_url` | `TUNA_API_URL`       | Адрес API, по умолчанию `https://api.tuna.am` |

## Ресурсы

| Ресурс                 | Что описывает                                                                                                               |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `tuna_domain`          | [Зарезервированный домен](https://tuna.am/docs/team/domains.md): поддомен встроенной зоны, своей зоны или собственный домен |
| `tuna_domain_zone`     | [Доменная зона](https://tuna.am/docs/team/domain_zones.md)                                                                  |
| `tuna_tls_certificate` | [TLS-сертификат](https://tuna.am/docs/team/tls_certificates.md) для доменной зоны                                           |
| `tuna_gateway`         | [Шлюз](https://tuna.am/docs/gateways.md) на зарезервированном домене                                                        |
| `tuna_endpoint`        | [TCP-порт](https://tuna.am/docs/team/tcp_ports.md)                                                                          |
| `tuna_ip_policy`       | [IP-политика](https://tuna.am/docs/team/ip_policies.md)                                                                     |
| `tuna_ip_policy_rule`  | Правило IP-политики                                                                                                         |
| `tuna_public_key`      | [Публичный SSH-ключ](https://tuna.am/docs/team/ssh_public_keys.md)                                                          |
| `tuna_temporal_token`  | Временный токен для запуска туннелей                                                                                        |

Источник данных `tuna_tunnels` возвращает список туннелей аккаунта.

Параметр `location` у доменов, зон и эндпоинтов принимает значения `ru` или `nl`.

Полный справочник по атрибутам — в [Terraform Registry](https://registry.terraform.io/providers/yuccastream/tuna/latest/docs).

## Сценарий: временные туннели для CI

Terraform резервирует домен и выпускает временный токен с ограничениями, а CI-задача поднимает туннель с этим токеном. Основной API-ключ в CI не попадает.

```hcl
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
}

```

Токен помечен как `sensitive`, поэтому забирайте его явно:

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

```

Проверить, что туннель поднялся, можно через источник данных:

```hcl
data "tuna_tunnels" "all" {}

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

```

## Сценарий: своя зона с сертификатом и доступом по IP

```hcl
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` — write-only атрибут: провайдер передаёт ключ в API, но не сохраняет его в state.

## Шлюз

```hcl
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` лежит [политика трафика](https://tuna.am/docs/traffic-policy.md). Домен со шлюзом занят шлюзом: туннель на нём не запустится, сервер ответит `Domain already reserved by gateway`. Для туннеля резервируйте отдельный домен.

## Изменение ресурсов

В API нет редактирования эндпоинтов, доменов, доменных зон и временных токенов, поэтому любое изменение их атрибутов (включая `alias` или `description`) пересоздаёт ресурс. У временного токена при этом меняется значение: туннели со старым токеном придётся перезапустить.

Шлюзы, IP-политики и их правила обновляются на месте. Правило пересоздаётся только при смене `ip_policy_id`.

## Импорт

Существующие ресурсы импортируются по числовому ID из личного кабинета или API:

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

```

У правила IP-политики составной ID `<ip_policy_id>/<rule_id>`:

```bash
terraform import tuna_ip_policy_rule.office_allow 123/456

```

API не возвращает приватный ключ сертификата, поэтому после импорта `tuna_tls_certificate` задайте `private_key_pem` в конфигурации.
