사람의 승인
쓰기 래퍼로 등록한 도구는 계획(Plan)이 성공하고 사람이 승인해야 실행(Apply) 단계로 넘어갑니다. Kubernetes 쓰기와 노트 쓰기가 이 절차를 따릅니다.
실행 흐름
호출
-> 원본 인자 크기 검사와 인자 해시 계산
-> 호출자 인증 -> 사용자 도구 정책 -> 필수 스코프
-> 잘못된 인자 거부
-> Plan: 대상/정책 검증과 변경 계산
-> 너무 크거나 마스킹된 미리보기 거부
-> 승인: 활성 시간 창 / 클라이언트 입력 / 웹 링크
-> 현재 승인된 Plan으로 Apply
-> 결과 마스킹 및 크기 제한 -> JSONL 감사 이벤트
원본 인자의 크기 검사와 파싱은 인가 전에 처리하지만, 이 과정에서 발생한 오류는 호출자, 사용자 도구 정책, 스코프 검사를 마친 뒤 반환합니다. 일반적으로 필요한 스코프는 ops:write입니다. HTTP에서는 /mcp에 접근할 때 ops:read도 필요합니다.
계획(Plan)은 실제 상태를 바꾸지 않으며, 요약에는 대상과 변경 결과가 명확히 드러나야 합니다. 마스킹으로 요약이 바뀌면 사람이 변경 내용을 정확히 확인할 수 없으므로 쓰기를 거부합니다. 웹 승인 시 실행 전에 계획을 다시 계산하며, 저장된 결과 조회는 계획이나 실행을 반복하지 않습니다. 계획(Plan)과 실행(Apply)에는 server.tool_timeout 제한 시간을 각각 따로 적용하며, 기본값은 각각 30초입니다.
승인 경로
opsgate는 먼저 요청과 require_web 제한을 검증한 뒤 전달받은 approval_id가 있으면 저장된 결과를 조회합니다. 그 외에는 유효한 승인 시간 창과 클라이언트 입력을 확인합니다. 새 HTTP 요청은 approval.web이 켜져 있으면 기본적으로 웹 승인을 사용합니다. approval.require_web: false를 명시하면 지원하는 클라이언트에서 클라이언트 내 확인(elicitation)을 허용하고, 지원하지 않으면 웹 승인을 사용합니다. 사용할 수 있는 승인 경로가 없으면 요청을 거부합니다.
미리보기가 잘린 계획은 마스킹된 전체 인자를 보여 주는 웹 승인이 필요하며, 브라우저 승인 경로가 없으면 변경을 더 작은 쓰기로 나누어야 합니다. 이 전체 검토 요구 여부는 서명된 클라이언트 상태와 웹 승인 기록에 바인딩되며, 기존의 유효한 승인 시간 창은 계속 적용됩니다.
전체 검토가 필요한 경우 인자(approval_id 제외)가 마스킹으로 바뀌면 승인이나 승인 시간 창 재사용 전에 쓰기를 거부하므로, 변경을 나누거나 마스킹된 값을 제거하세요.
서버 하나에서 여러 Kubernetes 클러스터처럼 여러 시스템에 접근하는 경우, 승인 화면은 요약 위에 대상 시스템을 표시합니다. 보호 대상으로 지정된 시스템은 도구에 승인 시간 창을 허용했더라도 호출할 때마다 사람이 승인해야 합니다.
승인 시간 창
승인 시간 창은 사용자, 정확한 도구 이름, 대상 시스템을 기준으로 일정 시간 동안 승인을 유지하는 선택 기능입니다. 해당 대상에서 그 도구의 유효한 모든 인자에 적용되며, 사용자 ID가 같으면 전송 방식이 달라도 사용할 수 있습니다. 한 대상에 대한 승인은 다른 대상이나 대상 이름이 없는 요청에는 적용되지 않습니다. 일반 인가 검사는 그대로 거쳐야 하고, 내용을 확인할 수 있는 요약과 유효한 계획(Plan)도 필요합니다.
approval.window의 기본값은 0이며, 이때는 승인 시간 창을 사용할 수 없습니다. 활성화하려면 값을 1m부터 12h 사이로 설정해야 하고, 도구 이름이 approval.window_tools의 path.Match 글로브 패턴과 일치해야 합니다. 목록이 비어 있으면 어떤 도구에도 승인 시간 창을 허용하지 않습니다. 설정을 켜더라도 사람이 승인 시간 창 옵션을 직접 선택해야 승인이 유지됩니다.
유효한 승인 시간 창은 사용자/도구/대상 조합을 기준으로 총 100개까지 유지하며, 새 승인을 추가하려고 기존의 유효한 승인을 삭제하지는 않습니다. 사용자, 도구, 대상이 모두 같으면 승인을 갱신할 수는 있습니다.
아래 내용을 기존 설정에 추가하세요.
approval:
ttl: 10m
window: 15m
window_tools: [k8s_rollout_restart]
클라이언트 내 확인
웹 승인을 켠 HTTP 서버에서 클라이언트 내 확인을 허용하려면 approval.require_web: false를 명시하세요. 웹 채널이 없는 external/static 인증과 stdio에서는 클라이언트 내 확인이 계속 기본값입니다.
require_web이 false이고 클라이언트가 elicitation을 지원한다고 알리면, opsgate는 여러 차례 입력을 주고받는 MCP InputRequests에 opsgate_approval 폼을 담아 반환합니다. 폼에는 요약, 요청자, 전송 방식을 보여 주고 대상 시스템이 있으면 함께 표시합니다. 사람이 approve: true로 승인해야 합니다. 승인 시간 창을 허용하는 도구에는 allow_window 옵션도 표시합니다.
서버는 사용자, 전송 방식, 도구, 대상 시스템, 호출마다 승인이 필요한지 여부, 인자 해시, 요약 해시, 만료 시각, nonce, 제시한 승인 시간 창의 길이를 요청 상태에 담고 HMAC-SHA256으로 서명해 클라이언트에 전달합니다. 서명 키는 프로세스가 시작할 때마다 무작위로 생성합니다.
후속 호출에서 서버는 서명과 만료 여부를 검사하고 이미 사용한 nonce를 거부합니다. 그런 다음 요청 정보의 일치 여부와 응답을 검사하기 전에 인증된 nonce를 사용한 것으로 처리합니다. 따라서 요청 정보가 일치하지 않거나 응답이 잘못되어도 그 상태를 다시 쓸 수 없습니다. 응답 내용의 키는 approve와 allow_window만 허용합니다. allow_window는 boolean이어야 하며, 서버가 제시했고 여전히 허용되는 승인 시간 창에만 사용할 수 있습니다.
이 opt-in을 사용하면 침해된 클라이언트가 자기 쓰기를 스스로 승인할 수 있습니다. 서버는 사람과 클라이언트 소프트웨어 중 누가 답했는지 구별할 수 없습니다. HTTP 시작 시 클라이언트 내 확인을 허용하면 경고를 남깁니다. 인증된 브라우저에서 결정해야 한다면 웹 전용 승인을 유지하세요.
웹 승인
웹 승인을 사용하려면 HTTP에서 auth.mode: builtin이 필요합니다. 이때 approval.web의 기본값은 true입니다. 내장 로그인 세션을 사용하므로 external/static 모드와 stdio에서는 사용할 수 없습니다.
최초 호출 -> 승인 생성 후 approval.wait 동안 대기
-> 아직 대기 중이면 /approve/<id> 링크 반환
-> 사람이 링크를 열고 요청한 사용자로 로그인
-> Reject / Approve / Approve + 설정된 시간 동안 허용
-> 승인 시 Plan 재계산 -> 요약/대상 검사 -> Apply -> 감사 로그
-> 대기 중인 호출에 결과 반환, 또는 approval_status로 조회
승인하면 원래 호출을 정확히 한 번 실행하며, Approve + allow for 시간 창을 선택해도 해당 호출을 실행합니다. 원래 호출자의 ID, 스코프, 도구 목록, 인자를 사용합니다. MCP 요청이나 브라우저 연결이 끊겨도 실행은 계속되며, 재계획과 실행에 각각 server.tool_timeout을 적용합니다. 요약, 대상, 검토 요구가 바뀌면 아무것도 적용하지 않고 페이지와 저장된 결과에 이유를 표시합니다. 실행 실패는 Not applied: ... 오류로 반환하며, 다시 쓰기를 시도하려면 새 승인이 필요합니다.
approval.wait는 웹 승인을 직접 또는 모드로 켜면 기본 25s, 그 외에는 0s입니다. 허용 범위는 0s–55s이며, 0이면 즉시 대기 링크를 반환합니다. 대기 중인 호출은 실행 성공 시 결과, 실패 시 오류, 거부 시 거부 결과를 받습니다. 요청 취소는 대기만 끝내며 승인을 취소하지 않습니다. 생성 시 pending 이벤트를 기록하고, 실행은 approval: web인 적용 이벤트를 정확히 하나 기록합니다. 대기 호출이나 결과 재조회는 적용 이벤트를 중복 기록하지 않습니다.
대기 시간이 먼저 끝나면 일반 텍스트 도구 결과에 링크를 사용자에게 보여 달라는 안내, 만료 시각, approval_id를 담습니다. 승인 후 실행을 위해 다시 호출할 필요는 없습니다. 결과는 읽기 전용 approval_status에 {"approval_id":"<id>"}를 전달해 조회합니다(ops:read 필요). 요청자만 조회할 수 있고 다른 사용자는 없는 ID와 같은 알 수 없음/만료 응답을 받습니다. tool, target, status(pending, running, applied, not_applied, rejected)와 결과가 있으면 result를 반환합니다.
AI가 승인이 아직 결정 전이거나 실행 중일 때 같은 호출(같은 요청자, 인자, 실행 계획)을 다시 보내면, 새 승인을 만들지 않고 기존 승인에 합류해 결과를 기다립니다. 승인한 뒤 페이지에는 결과와 함께 적용됨 또는 적용 안 됨이 표시됩니다.
호환성을 위해 원래 도구에 같은 인자와 approval_id를 추가해 재호출해도 저장된 결과만 반환하고 다시 실행하지 않습니다.
{"kind":"deployment","namespace":"default","name":"web","approval_id":"<id from the pending result>"}
페이지에는 계획을 한 줄씩 표시하고 연속된 --- 및 +++ 헤더(흐리게 표시) 뒤의 diff 줄만 강조하며, 마스킹된 인자도 함께 보여 줍니다. 요청한 사용자 본인만 페이지를 열고 승인 여부를 결정할 수 있습니다. 승인·거부 요청에는 CSRF 검사와 교차 출처 보호를 적용하고, 결정은 한 번만 받습니다. 페이지에는 스크립트를 허용하지 않는 엄격한 Content Security Policy를 적용합니다.
결과 재조회는 요청자, 전송 방식, 도구, 정규화한 마스킹 전 인자 해시(approval_id 제외)가 일치해야 합니다. 저장된 실행 함수는 승인한 요약, 대상, 검토 요구에 연결되며 적용 전에 다시 검사합니다. 완료된 결과 조회는 새 계획과 비교하지 않습니다. 승인한 변경 자체가 현재 계획을 바꿀 수 있기 때문입니다. approval_id가 있는 재호출은 승인 시간 창으로 새 실행을 허용하지 않으며, ID 없는 새 호출은 유효한 시간 창을 계속 사용할 수 있습니다.
builtin 인증을 쓰면 approval.web: false를 명시하지 않는 한 웹 승인이 켜지고, 기본적으로 브라우저에서만 승인합니다. 내장 인증을 사용하는 기존 HTTP 설정에 이 선택을 명시하려면 아래 내용을 추가하세요.
approval:
ttl: 10m
web: true
require_web: true
require_web: true는 클라이언트 내 확인을 끕니다. 명시적 true는 stdio의 승인 래퍼를 사용하는 쓰기도 거부합니다. 파일에서 require_web을 생략하면 모드 파일이라도 -transport stdio에서는 클라이언트 내 확인을 허용합니다. 사용자가 로컬에서 시작한 프로세스이고 웹 채널이 없기 때문입니다. config show는 HTTP 기본값을 명시적 true로 출력하므로, 그 출력을 stdio로 실행하면 키를 지우거나 false로 바꾸기 전까지 쓰기를 거부합니다. HTTP에서는 기존의 유효한 승인 시간 창을 계속 사용할 수 있습니다. HTTP 서버를 시작할 때 require_web: true인데 web: true가 아니면 설정을 거부하며, 내장 인증을 사용하지 않는 경우에도 웹 승인을 허용하지 않습니다.
재사용 방지, 제한, 상태
| 제어 | 동작 |
|---|---|
| 인자 일치 검사 | approval_id를 제외하고 정규화한 마스킹 전 JSON 인자의 SHA-256을 비교합니다. 마스킹된 인자는 표시와 감사 로그에만 사용합니다. |
| 계획(Plan) 일치 검사 | 다시 계산한 요약, 대상 시스템, 호출마다 승인이 필요한지 여부가 일치해야 합니다. 노트 쓰기는 실행(Apply) 중 계획 단계의 파일 스냅샷도 검사합니다. |
| 일회성 사용 | 웹 결정은 저장된 실행 함수를 한 번 시작하며 결과 조회는 실행하지 않습니다. 클라이언트 내 확인에는 사용한 nonce를 기록합니다. |
| 대기/입력 유효 기간 | approval.ttl이며 기본값은 10m입니다. TTL이 0 이하이면 승인 요청을 거부합니다. |
| 웹 기록 용량 | 실행 중이거나 보관 중인 결과를 포함해 유효한 기록은 최대 100개이며, 유효한 기록을 밀어내지 않습니다. |
| 결과 보관 | 최소 원래 만료 시각까지, 실행 결과는 완료 후 최소 10분까지 조회할 수 있습니다. 거부 기록은 원래 만료 시각까지 유지합니다. |
| nonce 용량 | 사용한 nonce 중 아직 만료되지 않은 항목은 최대 1,000개입니다. 새 후속 호출을 받기 위해 유효한 기존 항목을 삭제하지 않습니다. |
| 시간 창 용량 | 유효한 사용자/도구/대상 조합은 최대 100개입니다. |
| 상태 저장 | 대기 기록, 승인 시간 창, 사용한 nonce, 클라이언트 내 확인 서명 키는 메모리에만 저장하며, 재시작하면 모두 사라집니다. |
원본 쓰기 인자의 기본 크기 제한은 16 KiB이며, 내용을 전달하는 일부 도구는 이보다 큰 인자를 허용합니다. 요약의 크기 제한도 도구별 인자 제한에 따라 커집니다. 각 제한은 도구를 참고하세요.
감사 및 운영 경계
도구 이벤트는 pending, denied, ok, error로 기록합니다. 브라우저에서 승인하거나 거부하면 approved 또는 rejected 이벤트를, 복구 확인이 끝나면 recovered, not_recovered, unverified 이벤트를 추가하고, 승인 시간 창을 허용하면 window_granted를 추가합니다. 승인 경로가 있으면 approval 필드에 elicitation, web, window를 표시합니다. 계획과 표시용 인자는 마스킹하며, 성공한 호출의 전체 결과는 감사 텍스트로 저장하지 않습니다.
승인은 요청한 작업에만 유효하며, 같은 클라이언트가 이후에 요청하는 임의의 작업까지 허용하지는 않습니다. 승인 시간 창은 유효 기간 동안 승인한 대상에서 그 도구의 모든 작업으로 승인 범위를 넓히도록 설계했습니다. OS 권한, Kubernetes RBAC, provider 허용 목록, 스코프, 도구 제한은 여전히 필요합니다.
내장 로그인 설정은 인증을, 신뢰 경계는 보안 정책을 참고하세요.
카탈로그 조치 링크
새 링크는 GET /approve/action/{tool}?<인자>&source=rule|ai 형식입니다. 서버
카탈로그에는 k8s_rollout_restart, k8s_restore_image, k8s_scale,
k8s_delete_pod만 있고 노트 도구는 없습니다. 활성 provider와 서버 도구 정책이
Direct로 등록한 조치만 사용할 수 있습니다. 카탈로그는 영문·한글 이름, 정확한
링크 인자 목록과 향후 되돌리기 정보를 정의합니다. 규모 조정과 이미지 복구는
되돌릴 수 있고, 재시작과 파드 삭제는 되돌릴 수 없습니다. 재시작은 데이터를
직접 바꾸지 않지만 승인은 필요합니다.
허용 인자는 cluster, namespace, name입니다. 재시작·규모 조정에는 kind,
규모 조정에는 정수 replicas, 이미지 복구에는 container, expected_image,
image를 추가합니다. 클러스터가 하나면 cluster는 생략할 수 있습니다.
알 수 없거나 반복된 필드, approval_id, 잘못된 출처와 마스킹·비밀 값은 승인
생성 전에 거부합니다. source는 표시·감사 전용이며 도구 인자로 전달하지 않고
기본값은 rule입니다. 현재 영어 승인 화면에는 카탈로그 이름과
“Suggested by: rule” 또는 “Suggested by: AI — review carefully”를 표시합니다.
출처는 제안 표시이며 작성자를 인증한 증거가 아닙니다. 대기·결정·실행 감사
이벤트에 source를 기록합니다.
조회 전용 action_link는 기본 source=ai로 현재 대상을 Plan으로 검증한 뒤
URL, 이름, 계획 요약을 반환합니다. ops:read와 호출자의 도구 정책을 확인하지만
실행하거나 승인을 부여하지 않습니다. 링크를 열면 여전히 브라우저 로그인과
승인자 자신의 ops:write, 도구 정책, 대상 허용 목록을 확인합니다. 승인 시
계획을 다시 확인하고 한 번 실행하며 승인 시간 창은 제공하지 않습니다. 링크의
파드 삭제는 컨트롤러 소유 파드만 허용하며 실행 직전에도 소유자를 확인하고
리소스 버전 사전 조건을 적용합니다. MCP 요청은 컨트롤러가 없는 파드에 대한
기존 경고 동작을 유지합니다.
기존 /approve/restart/{cluster}/{kind}/{namespace}/{name}과
/approve/restore-image/{cluster}/{namespace}/{name}?container=…&expected_image=…&image=…
링크도 같은 카탈로그 검증을 거치는 별칭으로 계속 동작합니다.
승인함과 알림
휴대전화나 데스크톱의 일반 브라우저에서 /approvals를 열고 변경을 요청한 사용자로
로그인하세요. 승인함에는 자신에게 전달된 watch 알림(아래에서 설정한 경우)과 자신의
유효한 승인을 표시하며, 대기 요청 다음에 결정과 실행 결과를 보여 줍니다. 요청을 열어 계획을 검토하고 승인하면 기존과 같이 계획을 다시
검사하고 한 번 실행합니다. 알림 없이도 승인함을 사용할 수 있습니다. Telegram/Discord의
인앱 브라우저 대신 일반 브라우저를 사용하면 브라우저의 패스키로 로그인할 수 있습니다.
Web Push 알림 설정:
-
builtin 인증을 쓰는 HTTP 설정에서 push를 켜세요(
approval.web필요).approval: web: true push: enabled: true subject: mailto:owner@example.com state_file: /var/lib/opsgate/push.json language: kosubject에는 자신의 연락처mailto:또는https:URL을 넣으세요. 모드 파일의state_file기본값은/var/lib/opsgate/push.json이며, 그 외에는 필수입니다. OAuth 상태 파일과 다른 파일을 사용하세요. HTTPS 리버스 프록시에서 기존 인증·승인 경로와 함께/approvals및 하위 경로를 전달하세요. -
각 기기의 일반 브라우저에서
/approvals를 열고 로그인하세요. iPhone에서는 먼저 **홈 화면에 추가(Add to Home Screen)**를 선택하고 홈 화면의 opsgate를 여세요. 데스크톱 등 지원하는 브라우저에서도 승인함을 설치할 수 있습니다. -
Enable notifications on this device를 누르고 알림을 허용하세요. 계정에
ops:write가 필요합니다. 사용자마다 최대 10개의 기기를 보관하며, 추가하거나 갱신한 구독을 최신으로 옮기고 필요하면 가장 오래된 구독을 제거합니다. Disable notifications on this device로 해당 기기의 구독을 해제할 수 있습니다. 컴퓨터에서 보고 있다면 폰에서 열기가 승인함을 폰에서 여는 QR 코드를 보여 줍니다. 승인 페이지와 조치 선택 페이지에도 같은 QR이 있습니다. 테스트 알림 보내기는 계정의 모든 기기로 알림을 보내고, 승인함은 알림을 켠 기기 수를 보여 주며, 서버 로그에는 푸시 서비스가 받아들인 기기 수만 남습니다. iPhone과 iPad는 홈 화면에 추가한 앱에만 알림을 보내므로, Safari 탭에서 승인함을 열면 그렇게 안내합니다. 모든 opsgate 페이지가 설치 정보(manifest)를 연결하므로 승인 페이지나 로그인 페이지 등 어느 페이지에서 추가해도 같은 앱이 설치되고, 앱은 승인함을 엽니다.
새 MCP 웹 승인 요청은 요청자의 기기로 알림을 큐에 넣습니다. 링크로 만든 요청은 이미
사용자가 브라우저에 있으므로 알리지 않습니다. 알림을 누르면 /approvals/next를 열고,
로그인 후 가장 최근의 결정 전 승인, 승인함 알림, 끝난 복구 확인 중 하나로
바로 이동합니다. 기다리는 것이 없으면 승인함으로 갑니다. 알림 자체는 어떤 작업도 승인하지
않습니다.
알림 문구는 가장 최근 항목의 종류만 말합니다. 승인 요청이 있음, 알림에 대한 조치가 필요함,
조치 결과 복구됨, 아직 복구되지 않음, 복구 여부를 확인하지 못함 중 하나입니다(language: ko면
한국어). 서비스 워커는 푸시를 받으면 로그인된 GET /approvals/latest에서 이 종류를 읽습니다.
세션이 만료되는 등으로 읽지 못하면 “승인 요청이 있습니다”, 승인함 알림을 켰다면
“알림에 대한 조치가 필요합니다”를 표시합니다.
개인정보: push에는 승인 내용, ID, 대상, 결과가 없습니다. push 서비스는 VAPID
연락처와 전송 시점이 포함된 빈 요청만 받으며, 서비스 워커가 /approvals/latest를 읽어
기기에서 알림을 만듭니다. 이 응답은 항목의 종류만 담고 대상은 담지 않습니다. 알림이 잠금
화면에 보일 수 있기 때문입니다. 기기 구독 URL은 접근 권한을 가진 비밀 URL이므로 로그나 감사 기록에
남기지 않습니다. 구독과 서버가 생성한 VAPID 키 쌍은 0600 상태 파일에 원자적으로
저장합니다. 재시작해도 파일을 유지하세요. 삭제했다면 기기에서 구독을 해제한 뒤 알림을
다시 켜야 합니다. 승인 기록은 계속 메모리에만 있습니다.
전달은 최선을 다해 시도합니다. 워커 하나가 최대 100개 요청의 큐를 처리하며, 짧은 시간 제한을 사용하고 재시도하지 않습니다. 큐가 가득 차면 알림을 버리고 일반 경고를 기록합니다. 오프라인 기기는 승인 만료 전에 알림을 받을 수 있습니다. 404/410 응답은 해당 구독을 제거합니다. 현재 상태는 승인함에서 확인하세요. MCP 대기 메시지는 알림 전달에 성공했다고 단정하지 않습니다.
엔드포인트는 포트 443의 HTTPS, 최대 1 KiB여야 하며 approval.push.allowed_hosts에
맞아야 합니다. 기본값은 fcm.googleapis.com, updates.push.services.mozilla.com,
web.push.apple.com, *.notify.windows.com이며 와일드카드는 하위 도메인에만 맞습니다.
DNS 조회 뒤 연결할 주소를 검사하여 사설·루프백 등 공개되지 않은 주소를 거부하고,
리다이렉트와 환경 변수 프록시는 사용하지 않습니다. 신뢰할 수 있는 브라우저 push
서비스에 대해서만 허용 목록을 변경하세요. 저장된 엔드포인트가 설정 정책에서 벗어나면
시작에 실패하므로 허용 목록을 줄이기 전에 해당 구독을 해제하세요. 상태가 잘못되거나
읽을 수 없는 경우에도 서명 키를 조용히 교체하지 않고 시작에 실패합니다.
복구 확인
"적용됨"은 Kubernetes API가 변경을 받아들였다는 뜻일 뿐, 서비스가 다시 동작한다는
뜻은 아닙니다. 웹에서 승인한 k8s_rollout_restart, k8s_restore_image, k8s_scale,
k8s_delete_pod(컨트롤러가 소유한 파드)가 실행되면, opsgate가 워크로드를 지켜보고 복구
여부를 알려 줍니다.
| 결과 | 의미 |
|---|---|
| 복구됨 | 롤아웃이 끝나고 모든 복제본을 사용할 수 있는 상태를 10초 간격으로 두 번 연속 확인했습니다. 파드를 삭제한 경우에는 먼저 이전 파드가 사라져야 합니다. |
| 아직 복구되지 않음 | Deployment가 진행 기한(progress deadline)을 넘겼거나, 3분이 지나도 사용할 수 있는 상태가 되지 않았습니다. 상세 내용에 개수와 첫 번째 컨테이너 사유(예: CrashLoopBackOff)를 표시합니다. |
| 적용됨, 복구 여부 모름 | 확인하는 동안 워크로드를 읽지 못했습니다. |
판정 조건은 kubectl rollout status가 기다리는 조건과 같습니다. 컨트롤러가 변경을
반영했고, 모든 복제본이 새 버전이며, 이전 복제본이 남아 있지 않고, 새 복제본을 모두
사용할 수 있어야 합니다. 준비 상태(readiness)가 애플리케이션 정상 동작을 보장하지는
않습니다. readiness probe가 실패하면 확인도 실패합니다.
확인하는 동안 승인 페이지는 "적용됨, 복구 확인 중"을 표시하고 스스로 새로 고칩니다.
확인이 끝나면 결과가 승인 페이지, 승인함, approval_status(recovery,
recovery_detail)에 나타나고, 감사 로그에 recovered, not_recovered, unverified
이벤트가 남습니다. 푸시를 켰다면 결과를 알리는 알림도 갑니다. 알림은 잠금 화면에 보일 수
있으므로 결과만 말하고 워크로드 이름은 넣지 않습니다. 알림을 누르면 승인 페이지가
열립니다. 클라이언트 안에서 승인했거나 승인 시간 창으로 실행된 쓰기는 확인하지 않으며,
서버를 다시 시작하면 진행 중이던 확인은 사라집니다.
되돌리기
되돌릴 수 있는 조치는 실행 계획에 되돌리는 방법도 함께 기록합니다. 실행되면 결과에
되돌리기 링크가 붙습니다. 승인 페이지와 승인함에서는 버튼으로, MCP 도구 결과와
approval_status에서는 undo_url로 보입니다. 실행 감사 이벤트에는 "undo": true가
기록됩니다.
| 조치 | 되돌리기 |
|---|---|
k8s_scale |
실행 계획에서 확인한 이전 파드 수로 되돌립니다. 현재 값과 같은 값으로 조정하면 되돌리기가 없습니다. |
k8s_restore_image |
revert: true로 복원 전 이미지로 되돌립니다. |
| 재시작, 파드 삭제 | 없습니다. |
되돌리기 링크도 일반 카탈로그 링크입니다. 비밀 값이 없고, 열면 현재 상태로 새 실행
계획을 보여 주며, 로그인한 사람이 승인하기 전에는 아무것도 바뀌지 않습니다. 그사이
누군가 워크로드를 바꿨다면 실행 계획에 드러납니다. 승인 페이지는 이 서버의 출처에 있는
카탈로그 링크만 버튼으로 보여 줍니다. 되돌리기 링크는 웹 승인이 있어야 만들어지며, 없으면
결과에 undo_url이 없습니다.
revert: true를 주면 k8s_restore_image는 image로 같은 Deployment가 소유하고 삭제
중이 아닌 ReplicaSet의 파드 템플릿에서 같은 컨테이너가 쓴 이미지만 받습니다. 복원 전
이미지는 보통 실패하던 이미지이므로, 일반 복원과 달리 그 이미지를 실행 중인 준비된 파드를
요구하지 않습니다. 실행 계획에도 "This image is NOT verified healthy"라고 표시합니다.
expected_image는 여전히 현재 이미지와 같아야 하고, 매번 사람이 승인하며, 승인 시간 창은
적용되지 않습니다. revert를 다시 되돌리는 것은 일반 복원이므로 준비된 원본이 다시 필요합니다.
action_link는 revert를 거부하므로 analyzer는 확인되지 않은 이미지를 제안할 수 없고,
revert 링크는 복원의 되돌리기에서만 나옵니다.
장애별 현재 선택지
GET /approve/options/{cluster}/{namespace}/{pod}는 로그인이 필요하며 그 사용자의
현재 상태로 k8s_remediation_options를 평가합니다. 카탈로그 버튼, 고정 영어·한국어
이유, rule 출처를 표시합니다. ops:read, ops:write,
k8s_remediation_options와 선택한 조치의 도구 권한, provider 허용 목록이 필요합니다.
꺼졌거나 허용되지 않은 조치는 조용히 제외합니다. 페이지는 조회 전용이고 대기 승인을
만들지 않으며 다른 승인 페이지와 같은 no-store·보안·교차 출처 보호를 적용합니다.
버튼은 기존 /approve/action/...의 계획 → CSRF로 보호된 사람 승인 → 재계획 확인 →
적용 → 감사를 따릅니다. 선택은 승인이 아니며 승인 창을 부여하지 않습니다.
| 현재 상태 | 순서대로 제공하는 조치 |
|---|---|
ImagePullBackOff, ErrImagePull, InvalidImageName |
소유 Deployment의 검증된 이미지 복구 후보 |
Deployment의 현재 파드가 CrashLoopBackOff 또는 3회 이상 재시작했고 현재 ReplicaSet보다 오래된 정상 후보가 있음 |
이미지 복구 우선, 그다음 워크로드 재시작 |
Deployment ProgressDeadlineExceeded 또는 새 파드는 준비되지 않았고 이전 ReplicaSet에 검증된 준비 파드가 있음 |
이미지 복구 |
Deployment·StatefulSet·DaemonSet에서 3회 이상 재시작하고 restartAdvice에 적합함 |
워크로드 재시작. Job, 설정·이미지 오류, Unknown·Completed 종료 제외 |
OOMKilled와 3회 이상 재시작 |
시간을 벌 뿐이며 메모리 제한을 확인하라는 이유와 함께 워크로드 재시작 |
컨트롤러 소유 파드가 5분 넘게 종료 중이거나 Unknown이거나 NotReady 노드에 있음 |
UID·resource-version 확인 후 해당 파드 삭제. 강제 삭제하지 않음 |
| 적합한 조치 없음 | 빈 조치 목록과 기존 고정 조회 힌트 |
이미지 복구는 준비되어 실행 중인 컨테이너·이미지 식별 검증과 namespace당 ReplicaSet·파드 각 500개 제한을 유지합니다. 이미지 최대 5개와 재시작·삭제를 제공합니다. 준비 상태는 애플리케이션 정상 동작의 증거일 뿐 보장이 아니며 이미지 복구로 설정을 되돌리지는 않습니다. 재시작은 누락된 설정·잘못된 이미지·메모리 제한을 고치지 않습니다.
선택 ?workload=deployment/name(statefulset/name, daemonset/name도 지원)은
사라진 파드의 이동용 힌트일 뿐입니다. 페이지에 파드가 사라졌음을 명시하고 현재
워크로드와 UID로 검증한 소유 파드, Deployment 정체 조건을 평가합니다. 사라진
파드의 실패 상태를 재사용하거나 그 파드 삭제를 제안하지 않습니다. 힌트는 소유권
증명이 아닙니다. 다른 허용 워크로드로 고쳐도 그 대상의 현재 상태·권한을 독립적으로
확인합니다. 파드도 사용할 힌트도 없으면 조치를 표시하지 않습니다. 알 수 없거나
중복된 쿼리 필드, 지원하지 않는 종류는 거부합니다. 클러스터 메시지가 규칙 이유나
실행 링크가 되지 않습니다.
서명된 watch 알림
HTTP 서버에 approval.inbox_notify.secret_file과 subjects를, 별도 watch 프로세스에
watch.inbox를 설정하세요. 양쪽 설정 예시를
참고하세요. 기본은 모두 꺼져 있습니다. subject는 설정된 builtin 사용자 1–100명이어야
하고 중복은 허용하지 않으며 웹 승인이 필요합니다. 기기 알림 구독에는 여전히
ops:write가 필요하고, 현재 선택지는 로그인한 사용자의 스코프·도구 정책·대상 허용 목록을
별도로 확인합니다.
POST /approvals/notify에는 브라우저 세션이 필요하지 않습니다. 원문 본문의 유효한
HMAC-SHA256을 상수 시간 비교로 검증합니다. 본문은 64 KiB와 업로드 5초, 항목은 1–50개로 제한하며,
식별자 길이·경고 수준·타임스탬프를 검증합니다. 알 수 없는 필드, 잘못된 대상, 뒤에 붙은
JSON은 거부합니다. sent_at은 5분 미만으로 오래되어야 하고 미래는 1분까지 허용합니다.
재전송 검사용 digest는 서명된 유효 기간이 끝날 때까지 최대 1,000개 보관합니다.
hex 대소문자로 재전송 검사를 우회할 수 없습니다. 잘못된 요청도 포함해 전체 분당
60회로 제한하고 응답에는 입력을 반영하지 않습니다. 두 프로세스의 시계를 맞추고
전용 무작위 키를 쓰세요.
수락된 알림은 /approvals 맨 위 Alerts waiting for a decision에 설정된
사용자에게만 보입니다. 사용자마다 마지막 수신 후 1시간 동안 최대 50개를 유지하며,
가득 차면 가장 오래된 항목을 지웁니다. 같은 클러스터/네임스페이스/파드/이유의 반복은
기존 항목을 갱신해 맨 위로 옮깁니다. Dismiss는 동일 origin과 CSRF 검사를 거친
POST로 해당 사용자의 항목만 지웁니다. 수신·해제로 승인하거나 실행하는 일은 없습니다.
선택지 링크는 식별자와 선택적인 워크로드 이동 힌트로 서버에서 만들며, 소유 관계는
현재 상태에서 확인합니다.
Web Push가 켜져 있으면 첫 알림에서 사용자별 내용 없는 푸시를 큐에 넣고 1분 동안
뒤따르는 알림을 묶습니다. 그동안에도 수락한 모든 알림을 승인함에 기록하며, 나중에
추가 푸시를 보내지는 않습니다. 기존 푸시 큐와 기기 전송 제한을 따르는 최선형 전송입니다.
가장 최근 항목이 경고라면 알림은 An alert needs a decision(en) 또는
알림에 대한 조치가 필요합니다(ko)를 표시하고, 누르면 /approvals/next를 엽니다.
알림·재전송 방지·푸시 묶음 상태는 메모리에만 있어 재시작하면 사라집니다. watch 재시도는 제한되어 알림을 놓칠 수 있습니다. 이 메모리 승인함은 HTTP 서버 복제본 하나로 운영하세요. 서명은 공유 키를 안다는 뜻이며 실제 장애의 증거는 아닙니다. 조치는 항상 기존 계획 → 사람 승인 → 재계획 검사 → 실행 → 감사 기록을 거칩니다.