
# keenauth_webhook_endpoint

`keenauth_webhook_endpoint` 리소스는 웹훅 엔드포인트를 관리합니다. 웹훅 엔드포인트는 환경의 이벤트를 수신하는 HTTPS 주소이며, 이벤트는 Standard Webhooks 방식으로 서명됩니다. 프로바이더는 서명 시크릿을 지정하신 RSA 공개 키로 암호화한 상태로만 state에 보관합니다.

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

## 인수

- `url`은 필수입니다. `https`만 사용할 수 있고, 포트는 생략하거나 443만 지정할 수 있으며, 사용자 정보와 프래그먼트를 포함할 수 없습니다. IP 주소가 아닌 호스트 이름이어야 하며 최대 2048자입니다.
- `key`는 환경 내에서 고유해야 합니다(`^[a-z0-9][a-z0-9_-]{0,63}$`). 생략하면 API가 `endpoint-<ID의 마지막 8자>` 형식으로 값을 생성합니다.
- `event_types`는 카탈로그의 이벤트 타입 목록입니다(최대 100개). 기본값인 빈 집합은 대량으로 발생하는 `authentication.*` 타입을 제외한 모든 타입을 의미하며, 이 타입은 명시적으로 지정해야 합니다.
- `event_schema_versions`는 이벤트 타입을 페이로드 스키마 버전에 매핑합니다. 각 타입은 해당 엔드포인트가 수신하는 타입이어야 합니다.
- `payload_mode`는 `thin`(기본값: ID, 변경된 필드 이름, 상태 필드만 포함하며 개인 데이터는 제외) 또는 `full`입니다.
- `rate_limit_per_second`는 1에서 1000 사이이며, 기본값은 50입니다.
- `status`는 `enabled`(기본값) 또는 `disabled_by_user`입니다.

모든 인수는 제자리에서(in place) 변경됩니다. 업데이트 시에는 변경된 필드만 JSON Merge Patch로 전송되며, 마지막으로 읽은 ETag를 `If-Match`로 함께 보냅니다. 마지막 읽기 이후 엔드포인트가 다른 곳에서 변경되었다면 적용이 `412` 오류로 실패하고 아무것도 변경되지 않습니다. 이 경우 plan을 다시 실행하여 드리프트를 검토하십시오.

## 서명 시크릿은 평문으로 저장되지 않습니다

API는 엔드포인트를 생성할 때와 시크릿을 교체할 때에만 서명 시크릿(`idp_whsec_…`)을 반환합니다. `public_key`를 지정하면 프로바이더는 RSA-OAEP(SHA-256, MGF1 SHA-256, 빈 label)로 시크릿을 암호화하고, base64 암호문만 `encrypted_signing_secret`에 기록합니다. `public_key`를 지정하지 않으면 시크릿은 폐기되며, 나중에 `keenauth webhook-endpoints rotate-secret` 명령으로 교체하거나 `public_key`를 설정하십시오. 평문 시크릿은 state, plan 파일, 출력 값, 로그 어디에도 기록되지 않습니다.

키 쌍은 OpenTofu 외부에서 한 번만 생성하고, 개인 키는 구성 파일에 포함하지 마십시오.

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

`tofu apply` 실행 후 시크릿을 복호화하여 수신 측에 전달하십시오.

```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`는 PEM 형식의 RSA 공개 키(`PUBLIC KEY` 또는 `RSA PUBLIC KEY`)여야 하며, 최소 2048비트 이상이어야 합니다. 개인 키이거나 더 작은 키이면 plan 단계에서 거부됩니다.

## 교체(Rotation)

`public_key`를 설정하거나 변경하면 시크릿이 교체됩니다. `rotation_trigger`가 새 값으로 바뀌는 경우(예: `time_rotating` 리소스의 ID)에도 교체됩니다. 교체 후에도 이전 시크릿은 `previous_secret_ttl_hours`(0~168, API 기본값은 24, 0이면 즉시 폐기) 동안 새 시크릿과 함께 서명에 사용되므로, 수신 측은 이벤트를 놓치지 않고 전환할 수 있습니다. `previous_secret_expires_at`에서 이전 시크릿이 만료되는 시점을 확인할 수 있습니다. `public_key`를 제거하면 `encrypted_signing_secret`만 제거되며, 시크릿은 교체되지 않습니다.

## 한도와 상태

활성화된 엔드포인트는 환경별로 요금제 한도에 포함됩니다. 한도는 Free 3개, Startup 20개, Business 20개, Enterprise 50개입니다. 한도를 초과하여 엔드포인트를 생성하거나 활성화하면 `403 quota_exceeded` 오류가 발생합니다. 이 경우 다른 엔드포인트를 비활성화하거나 삭제하거나, 요금제를 업그레이드하십시오.

KeenAuth는 계속 실패하는 엔드포인트(`disabled_by_failure`)나 수신 측이 `410 Gone`으로 응답하는 엔드포인트(`disabled_by_receiver`)를 비활성화합니다. 다음 plan에서는 구성된 `status`로 되돌리는 변경이 표시되며, 이를 적용하면 엔드포인트가 다시 활성화됩니다.

## 가져오기(Import)

엔드포인트 ID 또는 key로 가져올 수 있습니다.

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

서명 시크릿은 다시 읽을 수 없으므로, 가져오기 후 `encrypted_signing_secret`은 비어 있습니다. 구성에 `public_key`가 설정되어 있다면 다음 apply에서 시크릿이 교체되고, 새 시크릿이 암호화된 상태로 전달됩니다.

테스트 전송, 재전송, 전달 재시도는 일회성 작업이며 구성에 포함되지 않습니다. 이러한 작업에는 `keenauth webhook-endpoints test`, `replay`, `deliveries` 명령을 사용하십시오.
