
# keenauth_webhook_endpoint

La risorsa `keenauth_webhook_endpoint` gestisce un endpoint webhook: un indirizzo HTTPS che riceve gli eventi dell'ambiente, firmati con Standard Webhooks. Il provider conserva il segreto di firma nello stato solo cifrato con una chiave pubblica RSA che gli fornisci.

```terraform
resource "keenauth_webhook_endpoint" "orders" {
  key         = "orders"
  url         = "https://hooks.example.com/keenauth"
  description = "Order service"
  event_types = ["user.created", "user.updated", "organization.created"]
  event_schema_versions = {
    "user.created" = 1
  }
  public_key = file("${path.module}/webhook-secret-key.pub.pem")

  rotation_trigger          = time_rotating.webhook_secret.id
  previous_secret_ttl_hours = 48
}

resource "time_rotating" "webhook_secret" {
  rotation_days = 90
}

output "orders_webhook_secret_encrypted" {
  value = keenauth_webhook_endpoint.orders.encrypted_signing_secret
}
```

## Argomenti

- `url` è obbligatorio: solo `https`, nessuna porta o porta 443, nessuna informazione utente, nessun frammento, e un nome host invece di un indirizzo IP (al massimo 2048 caratteri).
- `key` è univoca nell'ambiente (`^[a-z0-9][a-z0-9_-]{0,63}$`). Se la ometti, l'API la ricava come `endpoint-<ultimi 8 caratteri dell'ID>`.
- `event_types` elenca i tipi di evento del catalogo (al massimo 100). Un insieme vuoto, il default, significa tutti i tipi tranne i tipi `authentication.*`, ad alto volume, che devi indicare esplicitamente.
- `event_schema_versions` associa un tipo di evento a una versione dello schema del payload. Ogni tipo deve essere uno di quelli che l'endpoint riceve.
- `payload_mode` è `thin` (il default: ID, nomi dei campi modificati e campi di stato, senza dati personali) oppure `full`.
- `rate_limit_per_second` va da 1 a 1000; il default è 50.
- `status` è `enabled` (il default) oppure `disabled_by_user`.

Ogni argomento cambia sul posto. Gli aggiornamenti inviano solo i campi modificati come JSON Merge Patch, con l'ETag dell'ultima lettura come `If-Match`. Se l'endpoint è stato modificato altrove dopo l'ultima lettura, l'apply fallisce con `412` e non cambia nulla; esegui di nuovo plan per rivedere la divergenza.

## Il segreto di firma non viene mai memorizzato in chiaro

L'API restituisce il segreto di firma (`idp_whsec_…`) solo quando l'endpoint viene creato e quando il segreto viene ruotato. Con `public_key`, il provider cifra il segreto con RSA-OAEP (SHA-256, MGF1 SHA-256, etichetta vuota) e scrive in `encrypted_signing_secret` solo il testo cifrato in base64. Senza `public_key` il segreto viene scartato; ruotalo in seguito con `keenauth webhook-endpoints rotate-secret` oppure imposta `public_key`. Il segreto in chiaro non arriva mai allo stato, a un file di piano, a un output o a un log.

Crea la coppia di chiavi una sola volta, fuori da OpenTofu, e tieni la chiave privata fuori dalla configurazione:

```shell
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out webhook-secret-key.pem
openssl pkey -in webhook-secret-key.pem -pubout -out webhook-secret-key.pub.pem
```

Dopo `tofu apply`, decifra il segreto e consegnalo al ricevitore:

```shell
tofu output -raw orders_webhook_secret_encrypted | base64 -d | \
  openssl pkeyutl -decrypt -inkey webhook-secret-key.pem \
    -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256
```

`public_key` deve essere una chiave pubblica RSA codificata in PEM (`PUBLIC KEY` o `RSA PUBLIC KEY`) di almeno 2048 bit. Una chiave privata o una chiave più piccola viene rifiutata al momento del plan.

## Rotazione

Il segreto viene ruotato quando imposti o modifichi `public_key`, e quando `rotation_trigger` cambia in un nuovo valore, per esempio l'ID di una risorsa `time_rotating`. Dopo una rotazione il vecchio segreto continua a firmare accanto al nuovo per `previous_secret_ttl_hours` (da 0 a 168; il default dell'API è 24; 0 lo elimina subito), così il ricevitore può passare al nuovo senza perdere eventi. `previous_secret_expires_at` mostra quando il vecchio segreto smette di valere. Rimuovere `public_key` elimina solo `encrypted_signing_secret`; non ruota il segreto.

## Limiti e stato

Un endpoint abilitato conta nel limite del piano per ambiente: Free 3, Startup 20, Business 20, Enterprise 50. Creare o abilitare un endpoint in più fallisce con `403 quota_exceeded`; disabilita o elimina un altro endpoint, oppure passa a un piano superiore.

KeenAuth disabilita un endpoint che continua a fallire (`disabled_by_failure`) oppure il cui ricevitore risponde `410 Gone` (`disabled_by_receiver`). Il plan successivo mostra la modifica tornando allo `status` configurato, e applicandola l'endpoint viene di nuovo abilitato.

## Import

Importa con l'ID dell'endpoint o con la sua key:

```shell
tofu import keenauth_webhook_endpoint.orders orders
```

Il segreto di firma non può essere riletto, quindi `encrypted_signing_secret` è vuoto dopo l'import. Se la tua configurazione imposta `public_key`, il prossimo apply ruota il segreto e consegna quello nuovo cifrato.

I test di invio, i replay e i nuovi tentativi di consegna sono azioni una tantum, non configurazione. Per questi usa `keenauth webhook-endpoints test`, `replay` e `deliveries`.
