
# keenauth_webhook_endpoint

El recurso `keenauth_webhook_endpoint` gestiona un endpoint de webhook: una dirección HTTPS que recibe los eventos del entorno, firmados con Standard Webhooks. El proveedor mantiene el secreto de firma en el estado solo cifrado con una clave pública RSA que usted le proporciona.

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

## Argumentos

- `url` es obligatorio: solo `https`, sin puerto o con el puerto 443, sin información de usuario, sin fragmento, y con un nombre de host en lugar de una dirección IP (como máximo 2048 caracteres).
- `key` es único en el entorno (`^[a-z0-9][a-z0-9_-]{0,63}$`). Si lo omite, la API genera `endpoint-<últimos 8 caracteres del ID>`.
- `event_types` enumera los tipos de evento del catálogo (como máximo 100). Un conjunto vacío, que es el predeterminado, significa todos los tipos excepto los tipos `authentication.*` de alto volumen, que debe nombrar explícitamente.
- `event_schema_versions` asigna a un tipo de evento una versión del esquema de la carga útil. Cada tipo debe ser uno que el endpoint reciba.
- `payload_mode` es `thin` (el predeterminado: IDs, nombres de campos modificados y campos de estado, sin datos personales) o `full`.
- `rate_limit_per_second` va de 1 a 1000; el predeterminado es 50.
- `status` es `enabled` (el predeterminado) o `disabled_by_user`.

Cada argumento se cambia en su lugar. Las actualizaciones envían solo los campos modificados como JSON Merge Patch, con el ETag de la última lectura como `If-Match`. Si el endpoint se modificó en otro lugar después de la última lectura, el apply falla con `412` y no se cambia nada; ejecute plan de nuevo para revisar la desviación.

## El secreto de firma nunca se almacena en texto plano

La API devuelve el secreto de firma (`idp_whsec_…`) solo cuando se crea el endpoint y cuando se rota el secreto. Con `public_key`, el proveedor cifra el secreto con RSA-OAEP (SHA-256, MGF1 SHA-256, etiqueta vacía) y escribe solo el texto cifrado en base64 en `encrypted_signing_secret`. Sin `public_key`, el secreto se descarta; rótelo más adelante con `keenauth webhook-endpoints rotate-secret` o establezca `public_key`. El secreto en texto plano nunca llega al estado, a un archivo de plan, a una salida ni a un registro.

Cree el par de claves una sola vez, fuera de OpenTofu, y mantenga la clave privada fuera de su configuración:

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

Después de `tofu apply`, descifre el secreto y entréguelo al receptor:

```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` debe ser una clave pública RSA codificada en PEM (`PUBLIC KEY` o `RSA PUBLIC KEY`) de al menos 2048 bits. Una clave privada o una clave más pequeña se rechaza en el momento del plan.

## Rotación

El secreto se rota cuando establece o cambia `public_key`, y cuando `rotation_trigger` cambia a un valor nuevo, por ejemplo el ID de un recurso `time_rotating`. Después de una rotación, el secreto anterior sigue firmando junto al nuevo durante `previous_secret_ttl_hours` (de 0 a 168; el predeterminado de la API es 24; 0 lo elimina de inmediato), para que el receptor pueda cambiar sin perder eventos. `previous_secret_expires_at` muestra cuándo deja de funcionar el secreto anterior. Eliminar `public_key` solo elimina `encrypted_signing_secret`; no rota el secreto.

## Límites y estado

Un endpoint habilitado cuenta para el límite del plan por entorno: Free 3, Startup 20, Business 20, Enterprise 50. Crear o habilitar uno más falla con `403 quota_exceeded`; deshabilite o elimine otro endpoint, o actualice el plan.

KeenAuth deshabilita un endpoint que sigue fallando (`disabled_by_failure`) o cuyo receptor responde `410 Gone` (`disabled_by_receiver`). El siguiente plan muestra el cambio de vuelta al `status` configurado, y al aplicarlo el endpoint vuelve a habilitarse.

## Importación

Importe con el ID del endpoint o con su clave:

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

El secreto de firma no se puede leer de nuevo, así que `encrypted_signing_secret` queda vacío después de la importación. Si su configuración establece `public_key`, el siguiente apply rota el secreto y entrega el nuevo cifrado.

Los envíos de prueba, las repeticiones y los reintentos de entrega son acciones puntuales, no configuración. Para ellos use `keenauth webhook-endpoints test`, `replay` y `deliveries`.
