
# OpenTofu 및 Terraform 프로바이더

`keenauth/keenauth` 프로바이더는 KeenAuth 환경 하나의 설정을 코드로 관리합니다. 관리 API를 호출하며 플러그인 프로토콜 6을 사용하고 OpenTofu 및 Terraform과 함께 동작합니다. 아직 프로바이더 레지스트리에 게시되지 않았습니다.

## 인증 및 대상

프로바이더는 자신의 자격 증명이 속한 환경을 관리합니다. 여러 환경을 관리하려면 환경마다 프로바이더 별칭(alias)을 하나씩 설정하십시오. 인증 방식은 두 가지 중 하나만 사용할 수 있습니다. 관리 API 키를 사용하거나, `private_key_jwt`를 사용하는 `management` 애플리케이션으로 키 없이 인증하는 방식입니다. 두 가지를 모두 설정하면 오류가 발생합니다.

| 설정 | 환경 변수 | 설명 |
|---|---|---|
| `api_key` | `KEENAUTH_API_KEY` | 관리 API 키입니다. 환경 변수 사용을 권장합니다. 키는 상태 파일이나 계획 파일에 기록되지 않습니다. |
| `client_id` | `KEENAUTH_CLIENT_ID` | `api_key` 대신 사용하는 `management` 애플리케이션의 ID(`app_…`)입니다. `private_key`와 `issuer`가 필요합니다. |
| `private_key` | `KEENAUTH_PRIVATE_KEY` | 애플리케이션에 공개 키가 등록된 PEM PKCS#8 개인 키입니다. EC P-256, EC P-384, Ed25519 또는 2048비트 이상의 RSA를 사용할 수 있습니다. 환경 변수 사용을 권장합니다. 상태 파일에는 기록되지 않습니다. |
| `private_key_algorithm` | | `PS256`(기본값) 또는 `RS256`이며, RSA 키에만 해당합니다. |
| `issuer` | `KEENAUTH_ISSUER` | 환경의 기본 호스트 `https://<environment>.<region>.keenauth.app`입니다. 프로바이더는 `<issuer>/oauth2/token`에서 토큰을 발급받습니다. |
| `scopes` | | `client_id`로 요청할 권한입니다. 생략하면 부여의 기본 스코프가 적용됩니다. |
| `region` | `KEENAUTH_REGION` | `eu`(기본값) 또는 `us`입니다. API 주소는 `https://api.eu.keenauth.com/v1` / `https://api.us.keenauth.com/v1`입니다. |
| `base_url` | `KEENAUTH_BASE_URL` | API 주소를 직접 지정합니다. `https://<host>.keenauth.com/v1` 형식만 허용되며, 로컬 테스트용 루프백 주소도 허용됩니다. |

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

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

### `private_key_jwt`를 사용한 키 없는 인증

1. `app_type = "management"`로 애플리케이션을 생성하고, 설정에 필요한 권한을 담은 `keenauth_management_client` 레코드를 만드십시오.
2. 키 쌍의 공개 키를 애플리케이션에 등록하십시오(`POST /v1/applications/{application_id}/credentials`에 `type: public_key`를 보내거나, CLI 또는 대시보드를 사용합니다).
3. 프로바이더에 애플리케이션 ID, 개인 키, 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
```

관리 토큰이 필요할 때마다 프로바이더는 60초 동안 유효한 클라이언트 어설션(RFC 7523)에 서명합니다. `iss`와 `sub`은 클라이언트 ID이고, `aud`는 issuer이며, `jti`는 무작위 값이고, `kid`는 키의 RFC 7638 썸프린트입니다. 이 어설션을 `client_credentials` 부여로 교환해 10분짜리 토큰을 받으며, 이전 토큰이 만료되기 1분 전에 새 토큰을 받습니다. 토큰의 권한이 애플리케이션의 `keenauth_management_client` 레코드를 넘는 일은 없습니다. 관리 클라이언트처럼 API 키로만 접근할 수 있는 엔드포인트에는 `api_key`로 설정한 프로바이더 별칭이 필요합니다.

## 리소스

| 이름 | 종류 | 관리 대상 |
|---|---|---|
| `keenauth_application` | resource | 애플리케이션(OAuth 2.0 / OpenID Connect 클라이언트)입니다. |
| `keenauth_connection` | resource | 로그인 연결입니다. 데이터베이스, 비밀번호 없는 방식, 패스키, 소셜, 엔터프라이즈 중 하나입니다. |
| [`keenauth_connection_oidc_config`](/docs/terraform/connection-oidc-config) | resource | 엔터프라이즈 OIDC 연결의 relying party 설정이며, 쓰기 전용 클라이언트 시크릿을 포함합니다(OpenTofu 또는 Terraform 1.11 이상). 연결 ID로 가져올 수 있습니다. 삭제하면 상태에서만 제거됩니다. |
| [`keenauth_environment_settings`](/docs/terraform/environment-settings) | resource | 환경 설정입니다. 언어, 세션, 가입, 알림, 복구, MFA, 기본 인증 요소를 포함합니다. 환경당 하나만 있습니다. |
| [`keenauth_attack_protection`](/docs/terraform/attack-protection) | resource | 공격 방어 설정입니다. 무차별 대입, IP 제한, 자격 증명 스터핑, 봇, 유출된 비밀번호, 가입, SMS 사기, 위험 정책을 포함합니다. 환경당 하나만 있습니다. |
| [`keenauth_branding`](/docs/terraform/branding) | resource | 브랜딩 초안의 환경 테마입니다. 환경당 하나만 있습니다. |
| [`keenauth_custom_domain`](/docs/terraform/custom-domain) | resource | 사용자 지정 로그인 도메인입니다. |
| [`keenauth_api_key`](/docs/terraform/api-key) | resource | 관리 API 키입니다. 가져오기만 가능하며, 삭제하면 키가 폐기됩니다. |
| `keenauth_organization` | resource | B2B 조직입니다. 이름, slug, 외부 ID, 메타데이터, 브랜드 색상, 멤버 수 제한을 포함합니다. 삭제하면 즉시 제거됩니다. 상태 작업(비활성화, 활성화, 삭제 취소)은 CLI와 대시보드에서 수행합니다. |
| `keenauth_organization_role` | resource | 조직 전용 역할과 그 권한 집합입니다(Business 요금제). `<org_id>/<key>`로 가져올 수 있습니다. |
| [`keenauth_permission`](/docs/terraform/permission) | resource | API의 권한(OAuth 스코프)과 동의 화면 문구입니다. `<api_id>/<value>`로 가져올 수 있습니다. |
| [`keenauth_role`](/docs/terraform/role) | resource | 환경 역할과 그 전체 권한 집합입니다. 사용자 및 멤버십 할당은 리소스가 아닙니다. |
| [`keenauth_organization_domain`](/docs/terraform/organization-domain) | resource | 도메인 캡처와 SSO 라우팅을 위한 조직 도메인입니다. 인증(검증)은 작업으로 유지됩니다. |
| [`keenauth_session_policy`](/docs/terraform/organization-policies) | resource | 조직의 세션 유효 기간입니다. 환경 설정보다 엄격하게만 설정할 수 있습니다(Enterprise 요금제). |
| [`keenauth_mfa_policy`](/docs/terraform/organization-policies) | resource | 조직의 다중 인증 규칙입니다. 환경 설정보다 엄격하게만 설정할 수 있습니다. |
| [`keenauth_email_template`](/docs/terraform/email-template) | resource | 이메일 템플릿 하나(계열 및 로케일)의 게시된 내용입니다(Startup 요금제). `<family>/<locale>`로 가져올 수 있습니다. 삭제하면 상태에서만 제거됩니다. |
| [`keenauth_management_client`](/docs/terraform/management-client) | resource | `management` 애플리케이션의 관리 API 권한과 IP 허용 목록입니다. 애플리케이션 ID로 가져올 수 있습니다. |
| [`keenauth_directory`](/docs/terraform/directory) | resource | 조직의 SCIM 디렉터리와 그 프로비저닝 설정입니다. `name`과 설정은 제자리에서 변경되고, `organization_id`, `scim_host`, `type`이 변경되면 리소스가 교체됩니다. 디렉터리 ID로 가져올 수 있습니다. |
| [`keenauth_directory_role_mapping`](/docs/terraform/directory-role-mapping) | resource | SCIM 디렉터리 그룹을 역할에 매핑합니다. 어떤 변경이든 리소스가 교체됩니다. `<directory_id>/<mapping_id>`로 가져올 수 있습니다. |
| [`keenauth_directory_token`](/docs/terraform/directory-token) | resource | 디렉터리의 SCIM 토큰입니다. 상태에는 RSA 공개 키로 암호화된 형태로만 보관됩니다. 어떤 변경이든 새 토큰을 생성하며, 삭제하면 토큰이 폐기됩니다. 가져올 수 없습니다. |
| [`keenauth_webhook_endpoint`](/docs/terraform/webhook-endpoint) | resource | 웹훅 엔드포인트입니다. 모든 인수가 제자리에서 변경됩니다. 서명 비밀은 RSA 공개 키로 암호화된 형태로만 상태에 보관됩니다. 키 또는 `rotation_trigger`를 변경하면 비밀이 교체됩니다. 엔드포인트 ID 또는 키로 가져올 수 있습니다. |
| `keenauth_application` | data source | `id` 또는 `key`로 애플리케이션 하나를 읽습니다. |
| `keenauth_connection` | data source | `id` 또는 `key`로 연결 하나를 읽습니다. |
| `keenauth_organization` | data source | `id` 또는 `slug`로 조직 하나를 읽습니다. |
| [`keenauth_role`](/docs/terraform/role) | data source | `id` 또는 `key`로 환경 역할 하나를 읽습니다. |
| `keenauth_environment` | data source | API 키가 속한 환경을 읽습니다. ID, 종류, 리전, 셀, 상태, 요금제를 포함합니다. |

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

## 가져오기

애플리케이션과 연결은 `key` 또는 ID로, 사용자 지정 도메인은 호스트 이름 또는 ID로, API 키는 ID로 가져올 수 있습니다.

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

환경 설정, 공격 방어 설정, 브랜딩 초안은 환경마다 하나씩만 존재합니다. 이들은 고정 ID `environment-settings`, `attack-protection`, `branding`으로 가져오십시오. 이들 중 하나를 삭제하면 상태에서만 제거됩니다.

## 안전한 변경

- 생성 요청에는 `Idempotency-Key`가 포함되므로, 재시도된 생성 요청이 객체를 두 번 만들지 않습니다.
- 업데이트나 삭제 요청에는 마지막으로 읽은 ETag를 담은 `If-Match`가 포함됩니다. 계획을 세운 후 누군가 객체를 변경했다면 API가 `412`로 응답하며 아무것도 변경되지 않습니다. `plan`을 다시 실행하십시오.
- 대시보드에서 한 변경은 다음 `plan`에서 드리프트로 표시되며, `apply`를 실행하면 되돌아갑니다. 프로바이더 외부에서 삭제된 객체는 상태에서 제거된 후 다시 생성됩니다.
- 업데이트는 변경된 필드만 JSON 병합 패치(RFC 7396)로 전송합니다.

## 시크릿

어떤 리소스도 시크릿을 평문으로 상태에 저장하지 않습니다. KeenAuth에 전달하는 시크릿은 쓰기 전용 인수(`*_wo`)입니다. 프로바이더는 이를 전송하지만 상태 파일이나 계획 파일에는 절대 기록하지 않으며, `*_wo_version`이 변경될 때만 다시 전송합니다. 이 기능에는 OpenTofu 또는 Terraform 1.11 이상이 필요합니다. 현재는 엔터프라이즈 OIDC 연결의 클라이언트 시크릿(`keenauth_connection_oidc_config`)이 이에 해당합니다. 애플리케이션 클라이언트 시크릿과 서명 키는 이 버전의 프로바이더가 관리하지 않으므로, 대시보드나 CLI에서 생성하고 교체하십시오. KeenAuth가 생성하는 시크릿은 쓰기 전용이 될 수 없습니다. 쓰기 전용 인수는 설정에서 프로바이더로 값을 전달할 뿐이기 때문입니다. 프로바이더는 API 키를 생성하지 않습니다. 원본 키가 상태에 남게 되기 때문입니다. CLI로 키를 생성하고, 시크릿 관리자에 저장한 뒤, ID로 `keenauth_api_key`에 가져오십시오. 디렉터리의 SCIM 토큰은 API가 한 번만 보여 주므로, 프로바이더는 디렉터리 생성 시 반환되는 토큰을 폐기하고 보관하지 않습니다. `keenauth_directory_token`은 아이덴티티 공급자용 토큰을 생성하고, 이를 RSA 공개 키로 암호화된 형태로만 상태에 보관합니다. `keenauth_webhook_endpoint`도 웹훅 서명 비밀을 같은 방식으로 보관합니다. 즉 `public_key`로만 암호화하며, 키가 주어지지 않으면 비밀을 버립니다. 연결 `settings`에는 시크릿을 넣으면 안 됩니다. API는 시크릿처럼 보이는 설정을 거부합니다.

## 이 버전의 제한 사항

- 애플리케이션, 연결 및 그 OIDC 설정, 환경 설정, 공격 방어 설정, 브랜딩 초안의 환경 테마, 사용자 지정 도메인, API 키(가져오기만 가능), 조직, 역할과 권한, 조직 도메인, 조직 세션 및 다중 인증 정책, 이메일 템플릿, 관리 클라이언트, SCIM 디렉터리, 그룹-역할 매핑, SCIM 토큰(공개 키로 암호화), 웹훅 엔드포인트를 관리합니다. 훅, 로그 스트림, SMS 템플릿은 이후 버전에서 지원합니다.
- 프로바이더는 브랜딩을 게시하지 않습니다. 대시보드에서 또는 `keenauth branding publish`로 초안을 게시하십시오.
- 서버 기본값이 있는 선택 필드(예: `grant_types`)는 설정에서 제거해도 마지막 값을 유지합니다.
- 스키마 설명과 오류 메시지는 영어로 제공됩니다.
