
# Provider OpenTofu e Terraform

Il provider `keenauth/keenauth` gestisce la configurazione di un ambiente KeenAuth come codice. Chiama l'API di gestione, usa il protocollo plugin 6 e funziona con OpenTofu e Terraform. Non è ancora pubblicato in un registro dei provider.

## Autenticazione e destinazione

Il provider gestisce l'ambiente a cui appartiene la sua credenziale. Per gestire più ambienti, configura un alias del provider per ogni ambiente. L'autenticazione avviene in esattamente uno dei due modi: con una chiave API di gestione, oppure senza chiave come applicazione `management` con `private_key_jwt`. Impostarli entrambi è un errore.

| Impostazione | Variabile d'ambiente | Descrizione |
|---|---|---|
| `api_key` | `KEENAUTH_API_KEY` | Chiave API di gestione. Preferisci la variabile d'ambiente. La chiave non viene mai scritta nei file di stato o di piano. |
| `client_id` | `KEENAUTH_CLIENT_ID` | ID (`app_…`) di un'applicazione `management`, al posto di `api_key`. Richiede `private_key` e `issuer`. |
| `private_key` | `KEENAUTH_PRIVATE_KEY` | Chiave privata PEM PKCS#8 la cui chiave pubblica è registrata sull'applicazione: EC P-256, EC P-384, Ed25519 o RSA di almeno 2048 bit. Preferisci la variabile d'ambiente. Non viene mai scritta nello stato. |
| `private_key_algorithm` | | `PS256` (predefinito) o `RS256`, solo per una chiave RSA. |
| `issuer` | `KEENAUTH_ISSUER` | L'host predefinito dell'ambiente, `https://<environment>.<region>.keenauth.app`. Il provider ottiene il token da `<issuer>/oauth2/token`. |
| `scopes` | | Autorizzazioni da richiedere con `client_id`. Se omesso, si applicano gli scope predefiniti della concessione. |
| `region` | `KEENAUTH_REGION` | `eu` (predefinito) o `us`. L'indirizzo API è `https://api.eu.keenauth.com/v1` / `https://api.us.keenauth.com/v1`. |
| `base_url` | `KEENAUTH_BASE_URL` | Indirizzo API esplicito. Sono accettati solo `https://<host>.keenauth.com/v1` e gli indirizzi di loopback per i test locali. |

```terraform
terraform {
  required_providers {
    keenauth = { source = "keenauth/keenauth" }
  }
}

provider "keenauth" {
  region = "eu"
}
```

### Autenticazione senza chiave con `private_key_jwt`

1. Crea un'applicazione con `app_type = "management"` e un record `keenauth_management_client` con le autorizzazioni di cui la configurazione ha bisogno.
2. Registra la chiave pubblica di una coppia di chiavi sull'applicazione (`POST /v1/applications/{application_id}/credentials` con `type: public_key`, tramite la CLI o la dashboard).
3. Fornisci al provider l'ID dell'applicazione, la chiave privata e l'issuer:

```shell
export KEENAUTH_CLIENT_ID="app_..."
export KEENAUTH_PRIVATE_KEY="$(cat ops-automation.pk8.pem)"
export KEENAUTH_ISSUER="https://acme.eu.keenauth.app"
tofu plan
```

Per ogni token di gestione il provider firma un client assertion (RFC 7523) valido per 60 secondi: `iss` e `sub` sono l'ID client, `aud` è l'issuer, `jti` è casuale e `kid` è il thumbprint RFC 7638 della chiave. Scambia l'assertion con la concessione `client_credentials` per un token di 10 minuti e ne ottiene uno nuovo un minuto prima che quello vecchio scada. Il token non può mai avere più autorizzazioni del record `keenauth_management_client` dell'applicazione. Gli endpoint che accettano solo una chiave API, come i client di gestione, richiedono un alias del provider configurato con `api_key`.

## Risorse

| Nome | Tipo | Cosa gestisce |
|---|---|---|
| `keenauth_application` | risorsa | Un'applicazione (client OAuth 2.0 / OpenID Connect). |
| `keenauth_connection` | risorsa | Una connessione di accesso: database, senza password, passkey, social o enterprise. |
| [`keenauth_connection_oidc_config`](/docs/terraform/connection-oidc-config) | risorsa | La configurazione della relying party di una connessione OIDC enterprise, con un client secret write-only (OpenTofu o Terraform 1.11+). Importa con l'ID della connessione. La distruzione lo rimuove solo dallo stato. |
| [`keenauth_environment_settings`](/docs/terraform/environment-settings) | risorsa | Impostazioni dell'ambiente: lingue, sessioni, registrazione, notifiche, recupero, MFA, primi fattori. Una per ambiente. |
| [`keenauth_attack_protection`](/docs/terraform/attack-protection) | risorsa | Protezione dagli attacchi: forza bruta, limitazione per IP, credential stuffing, bot, password compromesse, registrazione, frode SMS, policy di rischio. Una per ambiente. |
| [`keenauth_branding`](/docs/terraform/branding) | risorsa | Il tema dell'ambiente della bozza di branding. Una per ambiente. |
| [`keenauth_custom_domain`](/docs/terraform/custom-domain) | risorsa | Un dominio di accesso personalizzato. |
| [`keenauth_api_key`](/docs/terraform/api-key) | risorsa | Una chiave API di gestione: solo importazione; la distruzione la revoca. |
| `keenauth_organization` | risorsa | Un'organizzazione B2B: nome, slug, ID esterno, metadati, colore del brand e limite di membri. La distruzione la elimina immediatamente; le azioni di stato (disabilita, abilita, annulla eliminazione) restano nella CLI e nella dashboard. |
| `keenauth_organization_role` | risorsa | Un ruolo specifico dell'organizzazione e il suo insieme di autorizzazioni (piano Business). Importa con `<org_id>/<key>`. |
| [`keenauth_permission`](/docs/terraform/permission) | risorsa | Un'autorizzazione (scope OAuth) di un'API con i testi della sua schermata di consenso. Importa con `<api_id>/<value>`. |
| [`keenauth_role`](/docs/terraform/role) | risorsa | Un ruolo dell'ambiente e il suo insieme completo di autorizzazioni. Le assegnazioni a utenti e membership non sono risorse. |
| [`keenauth_organization_domain`](/docs/terraform/organization-domain) | risorsa | Un dominio di un'organizzazione per la cattura del dominio e l'instradamento SSO. La verifica resta un'azione. |
| [`keenauth_session_policy`](/docs/terraform/organization-policies) | risorsa | La durata delle sessioni di un'organizzazione; può essere solo più restrittiva dell'ambiente (piano Enterprise). |
| [`keenauth_mfa_policy`](/docs/terraform/organization-policies) | risorsa | Le regole MFA di un'organizzazione; può essere solo più restrittiva dell'ambiente. |
| [`keenauth_email_template`](/docs/terraform/email-template) | risorsa | Il contenuto pubblicato di un modello email (famiglia e lingua); piano Startup. Importa con `<family>/<locale>`. La distruzione lo rimuove solo dallo stato. |
| [`keenauth_management_client`](/docs/terraform/management-client) | risorsa | Le autorizzazioni dell'API di gestione e la allowlist IP di un'applicazione `management`. Importa con l'ID dell'applicazione. |
| [`keenauth_directory`](/docs/terraform/directory) | risorsa | Una directory SCIM di un'organizzazione e le sue impostazioni di provisioning; `name` e le impostazioni cambiano sul posto, mentre `organization_id`, `scim_host` e `type` la sostituiscono. Importa con l'ID della directory. |
| [`keenauth_directory_role_mapping`](/docs/terraform/directory-role-mapping) | risorsa | Associa un gruppo della directory SCIM a un ruolo; qualsiasi modifica la sostituisce. Importa con `<directory_id>/<mapping_id>`. |
| [`keenauth_directory_token`](/docs/terraform/directory-token) | risorsa | Un token SCIM di una directory, mantenuto nello stato solo cifrato con la tua chiave pubblica RSA; qualsiasi modifica crea un nuovo token, la distruzione lo revoca. Non importabile. |
| [`keenauth_webhook_endpoint`](/docs/terraform/webhook-endpoint) | risorsa | Un endpoint webhook; ogni argomento cambia sul posto. Il segreto di firma è mantenuto nello stato solo cifrato con la tua chiave pubblica RSA; cambiare la chiave o `rotation_trigger` lo ruota. Importa con l'ID o la chiave dell'endpoint. |
| `keenauth_application` | data source | Legge un'applicazione tramite `id` o `key`. |
| `keenauth_connection` | data source | Legge una connessione tramite `id` o `key`. |
| `keenauth_organization` | data source | Legge un'organizzazione tramite `id` o `slug`. |
| [`keenauth_role`](/docs/terraform/role) | data source | Legge un ruolo dell'ambiente tramite `id` o `key`. |
| `keenauth_environment` | data source | Legge l'ambiente della chiave API: ID, tipo, regione, cella, stato e piano. |

```terraform
resource "keenauth_connection" "google" {
  key      = "google"
  type     = "social"
  strategy = "google"
  name     = "google"
  status   = "active"
  settings = jsonencode({ scopes = ["openid", "email", "profile"] })
}

resource "keenauth_application" "storefront" {
  key            = "storefront"
  name           = "Storefront"
  app_type       = "web"
  party          = "first_party"
  redirect_uris  = ["https://shop.example.com/callback"]
  connection_ids = [keenauth_connection.google.id]
}
```

## Importazione

Le applicazioni e le connessioni possono essere importate tramite la loro `key` o il loro ID, un dominio personalizzato tramite il suo hostname o il suo ID, e una chiave API tramite il suo ID:

```shell
tofu import keenauth_application.storefront storefront
tofu import keenauth_connection.google conn_01j9zq3v8c5m2x7k4t6r1n0b3d
tofu import keenauth_custom_domain.login login.example.com
```

Le impostazioni dell'ambiente, la protezione dagli attacchi e la bozza di branding esistono una sola volta per ambiente; importali con gli ID fissi `environment-settings`, `attack-protection` e `branding`. La distruzione di uno di essi lo rimuove solo dallo stato.

## Modifiche sicure

- Una creazione invia un `Idempotency-Key`, quindi una creazione ripetuta non crea mai un secondo oggetto.
- Un aggiornamento o una eliminazione invia `If-Match` con l'ultimo ETag letto. Se qualcuno ha modificato l'oggetto dopo la creazione del piano, l'API risponde con `412` e nulla cambia. Esegui di nuovo `plan`.
- Una modifica fatta nella dashboard compare nel `plan` successivo come drift, e `apply` la riporta indietro. Un oggetto eliminato al di fuori del provider viene rimosso dallo stato e creato di nuovo.
- Un aggiornamento invia solo i campi modificati come JSON merge patch (RFC 7396).

## Segreti

Nessuna risorsa memorizza un segreto in chiaro nello stato. I segreti che fornisci a KeenAuth sono argomenti write-only (`*_wo`): il provider li invia ma non li scrive mai nei file di stato o di piano, e li reinvia solo quando cambia il loro `*_wo_version`. Richiedono OpenTofu o Terraform 1.11 o successivo. Attualmente si tratta del client secret di una connessione OIDC enterprise (`keenauth_connection_oidc_config`). I client secret delle applicazioni e le chiavi di firma non sono gestiti da questa versione del provider; creali e ruotali nella dashboard o con la CLI. I segreti generati da KeenAuth non possono essere write-only, perché un argomento write-only trasporta un valore solo dalla configurazione al provider. Il provider non crea mai chiavi API, perché la chiave grezza finirebbe nello stato: crea una chiave con la CLI, conservala nel tuo gestore di segreti e importala in `keenauth_api_key` tramite il suo ID. Il token SCIM di una directory viene mostrato una sola volta dall'API, quindi il provider revoca il token restituito dalla creazione di una directory e non lo conserva mai; `keenauth_directory_token` crea il token per il tuo provider di identità e lo mantiene nello stato solo cifrato con la tua chiave pubblica RSA. `keenauth_webhook_endpoint` mantiene il segreto di firma del webhook allo stesso modo, solo cifrato con il suo `public_key`, e lo scarta quando non viene fornita alcuna chiave. Le `settings` di una connessione non devono contenere segreti; l'API rifiuta le impostazioni che sembrano segreti.

## Limiti di questa versione

- Sono gestiti: applicazioni, connessioni e la relativa configurazione OIDC, impostazioni dell'ambiente, protezione dagli attacchi, il tema dell'ambiente della bozza di branding, domini personalizzati, chiavi API (solo importazione), organizzazioni, ruoli e autorizzazioni, domini delle organizzazioni, policy di sessione e MFA delle organizzazioni, modelli email, client di gestione, directory SCIM, le relative associazioni gruppo-ruolo, token SCIM (cifrati con la tua chiave pubblica) ed endpoint webhook. Hook, log stream e modelli SMS arriveranno nelle versioni successive.
- Il provider non pubblica il branding; pubblica la bozza nella dashboard o con `keenauth branding publish`.
- I campi opzionali con un valore predefinito lato server (ad esempio `grant_types`) mantengono l'ultimo valore quando li rimuovi dalla configurazione.
- Le descrizioni dello schema e i messaggi di errore sono in inglese.
