구성 변경 계획
POST /v1/config-plans · 권한 config:read와 문서에 있는 각 종류의 읽기 권한
구성 문서를 환경의 현재 구성과 비교하고 결과를 계획으로 저장합니다. 아무것도 변경되지 않습니다. 계획은 문서를 적용하면 무엇이 바뀌는지만 보여 줍니다. development에서 staging 또는 production으로 승격하기 전에 검토할 때 사용하세요.
요청
| 필드 | 설명 |
|---|---|
document |
필수. GET /v1/config-export 형식의 구성 문서입니다. JSON Schema https://docs.keenauth.com/config/schema/v1.json과 일치해야 합니다. |
prune |
선택, 기본값 false. true이면 문서에 없는 문서 종류의 리소스 삭제가 계획됩니다. |
- 문서의 종류는
kinds가 있으면 그것이고(이때 모든 리소스는 나열된 종류여야 함), 없으면 리소스의 종류입니다. 이 종류만 비교하며 다른 종류는 그대로 둡니다. - 문서에 없는 리소스는
prune이true가 아니면 삭제되지 않습니다. 단일 종류(environment_settings,identity_settings,branding)는 절대 삭제되지 않습니다. - 단일 종류에서 문서에 없는 필드는 변경되지 않으며 대상의 현재 값이 유지됩니다. 따라서 필드가 추가되기 전에 내보낸 문서는 그 필드를 초기화하지 않습니다.
null을 포함해 명시적으로 지정한 값은 그대로 기록됩니다. 다른 종류에서는 없는 필드가 기본값을 받습니다. - 문서에는 비밀 값이 있으면 안 됩니다. 비밀 필드에는
secret_ref자리 표시자나null만 넣을 수 있으며, 값은 거부되고 응답에 다시 표시되지 않습니다. - 문서의
warnings는 무시됩니다. 최대 15,000개까지 허용됩니다(내보내기에는 그보다 많이 포함되지 않습니다). - 권한은 같은 종류를 내보낼 때와 같습니다.
prune을 사용하면 삭제되는 리소스를 참조할 수 있는 종류도 읽으므로 그 권한도 필요합니다.
응답
201 Created, Location: /v1/config-plans/{plan_id}와 Cache-Control: no-store 포함.
| 필드 | 설명 |
|---|---|
id |
계획 ID, cfgp_…. |
status |
planned, expires_at 이후에는 expired. |
expires_at |
계획은 1시간 동안 유효하며 만료 7일 후 삭제됩니다. |
summary |
create, update, delete, no_op 작업 수. |
changes |
리소스마다 하나의 항목, 종류 순서 다음 key 순서. |
warnings |
secret_required: 대상에 아직 없는 클라이언트 시크릿이 연결에 필요합니다. |
각 변경에는 kind, key, action(create, update, delete 또는 no_op), object_version(계획 시점 대상 리소스의 버전, create에서는 null), requires_secret, fields, 그리고 create와 update에서는 원하는 spec이 있습니다. fields의 각 항목은 필드 차이입니다. pointer(RFC 6901, 예: /spec/name), op(RFC 6902와 같은 add, remove 또는 replace), before, after. 목록은 전체 값으로 비교합니다.
내보낸 문서를 변경하지 않고 보내면 리소스와 집합형 목록의 순서와 관계없이 모든 리소스가 no_op으로 계획됩니다.
{
"id": "cfgp_01m4qpqtywfs7930tb6kqn5rc5",
"status": "planned",
"prune": false,
"kinds": ["connection"],
"expires_at": "2026-10-12T11:00:00Z",
"summary": {"create": 1, "update": 1, "delete": 0, "no_op": 1},
"changes": [
{"kind": "connection", "key": "db", "action": "no_op", "object_version": 5, "requires_secret": false, "fields": []},
{"kind": "connection", "key": "github", "action": "create", "object_version": null, "requires_secret": true, "fields": [], "spec": {"type": "social", "strategy": "github", "name": "GitHub", "display_name": null, "status": "active", "settings": {}, "client_secret": {"secret_ref": {"source": "env", "name": "KEENAUTH_CONNECTION_GITHUB_CLIENT_SECRET"}}}},
{"kind": "connection", "key": "google", "action": "update", "object_version": 4, "requires_secret": false, "fields": [{"pointer": "/spec/name", "op": "replace", "before": "Google", "after": "Google Workspace"}], "spec": {"type": "social", "strategy": "google", "name": "Google Workspace", "display_name": null, "status": "active", "settings": {}, "client_secret": {"secret_ref": {"source": "env", "name": "KEENAUTH_CONNECTION_GOOGLE_CLIENT_SECRET"}}}}
],
"warnings": [{"code": "secret_required", "kind": "connection", "key": "github", "pointer": "/spec/client_secret"}]
}
모든 계획은 환경의 관리 로그에 config_plan.created 항목을 기록합니다.
제한
- 속도: 플랜에는 환경별 분당 자체 한도가 있습니다.
production에서 Free 20, Startup과 Business 60, Enterprise 120이며development와staging에서는 그 10분의 1(최소 2)입니다. - 환경별 할당량: 적용되지도 만료되지도 않은 플랜은 최대 100개, 삭제될 때까지(만료 7일 후) 저장되는 플랜은 최대 2,000개 및 1 GiB입니다. 다른 환경의 플랜은 계산되지 않습니다.
- 용량: 서버는 큰 플랜을 동시에 제한된 수만 계산하며, 한 환경은 그 용량의 최대 4분의 1만 사용할 수 있습니다.
- 필드 제한은 구성 서비스가 쓰기 시 적용하는 제한입니다. 스키마가 목록과 텍스트를 제한하고(예:
redirect_uris50,allowed_web_origins20,permissions1,000), 연결의settings는 최대 32 KiB, 깊이 8단계, 애플리케이션의jwks와 각 권한의consent_text_i18n은 최대 16 KiB입니다.
오류
| HTTP | code | 발생 조건 |
|---|---|---|
| 400 | malformed_request, unknown_field |
본문이 JSON이 아니거나 document, prune 이외의 필드가 있습니다. |
| 401 | unauthenticated |
자격 증명이 없거나 유효하지 않거나 취소되었습니다. |
| 403 | insufficient_permissions |
필요한 권한이 없습니다. required_permissions에 모두 나열됩니다. |
| 413 | config_document_too_large, payload_too_large |
문서가 리소스 5,000개 또는 10 MiB를 넘습니다. 더 적은 종류를 계획하세요. |
| 422 | validation_failed |
아래를 참조하세요. errors[].pointer는 요청 안(/document/...)을 가리킵니다. |
| 429 | rate_limited |
플랜 속도 제한 또는 환경의 플랜 할당량에 도달했거나 환경이 너무 많은 플랜을 계산하고 있습니다. Retry-After 시간 후 다시 시도하세요(할당량의 경우 가장 오래된 플랜이 만료되거나 삭제될 때). |
| 503 | service_unavailable |
플랜 계산 용량이 가득 찼거나 종속 서비스를 일시적으로 사용할 수 없습니다. Retry-After 시간 후 다시 시도하세요. |
errors[].code |
의미 |
|---|---|
required |
document가 없습니다. |
invalid |
이 포인터에서 문서가 스키마와 일치하지 않습니다. |
duplicate |
두 리소스의 kind와 key가 같습니다. |
kind_not_listed |
리소스의 종류가 kinds에 없습니다. |
secret_value |
비밀 값이 발견되었습니다. secret_ref 자리 표시자를 사용하세요. |
unresolved_reference |
참조하는 key가 변경 후에는 존재하지 않습니다. |
key_in_use |
key가 구성으로 관리되지 않는 애플리케이션(조직 소유 또는 자체 등록) 또는 시스템 API에 속합니다. |
still_referenced |
/prune: 남는 리소스가 계획이 삭제할 리소스를 참조합니다. |
too_large |
리소스, 경고 또는 최상위 필드에 JSON 값이 200,000개를 초과합니다. |
too_long |
연결의 settings가 32 KiB를 초과하거나, 애플리케이션의 jwks 또는 권한의 consent_text_i18n이 16 KiB를 초과합니다. |
too_deep |
연결의 settings가 8단계보다 깊게 중첩되어 있습니다. |
reserved |
API identifier가 플랫폼의 urn:idp: 네임스페이스에 있습니다. |
예제
curl -X POST "https://api.eu.keenauth.com/v1/config-plans" \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d "{\"document\": $(cat keenauth.json), \"prune\": false}"
keenauth config plan -f keenauth.yaml