장애 자동 대응의 안전장치 (Guarded Alert Remediation)

"경보를 받아 컨테이너 재시작 같은 조치를 자동으로 실행하면, 잘못된 명령이나 위조된 요청, 연쇄 실행은 무엇으로 막는가?" 이 페이지는 그 질문에 답한다. Guarded alert remediation은 Alertmanager의 webhook receiver 뒤에서 조치를 실행하는 시스템이 요청 인증, 반복 방지, 허용 목록, 시험 실행, 사람 승인, 도구 권한 분리 같은 장치를 여러 겹으로 두는 패턴이다. Source는 규칙 기반 webhook 앱과 AI 장애 관제 Agent 두 가지이며, 두 구현은 판단 주체가 다르지만 "실행 전에 무엇을 통과해야 하는가"라는 같은 문제를 다룬다. 이 패턴은 Agent Safety Boundary의 Authorization 경계에 해당하는 운영 사례로 볼 수 있다.

두 가지 구현 형태

구분 규칙 기반 webhook 앱 AI 장애 관제 Agent
판단 주체 코드가 alertname과 severity를 매칭한다[1] Agent가 metric·로그·과거 사례를 조회해 분석하고 조치를 제안한다[2]
실행 시점 조건이 맞으면 바로 실행한다. dryRun이 켜져 있으면 로그만 남긴다[1:1] 승인 기반 조치는 Discord 확인 뒤에 실행하고, playbook의 AUTO 조치는 코드가 즉시 실행한다[3]
실행 예시 docker:restart leafy_api[1:2] docker restart <container-name>[4]

흐름

규칙 기반 webhook 앱은 경보 하나가 다음 순서로 검사를 통과해야 실행된다.[1:3]

flowchart TB
    A[Alertmanager] -->|POST /alert| T{토큰 검증}
    T -->|불일치| X1[401 invalid token]
    T -->|일치| C{쿨다운 확인}
    C -->|쿨다운 중| X2[cooldown 응답, 실행 안 함]
    C -->|통과| M{경보 매칭과 허용 목록}
    M -->|불일치| X3[ok 응답, 실행 안 함]
    M -->|일치| D{dryRun}
    D -->|true| L[audit 로그만 기록]
    D -->|false| R[docker / ssh / script 실행]

AI 장애 관제 시스템의 로컬 코드에는 분석 뒤 playbook 조치와 대화 중 모델 제안을 처리하는 세 경로가 있다.[3:2]

flowchart TB
    A[Alertmanager webhook] --> PB[알람 검증과 playbook 조회]
    PB --> RA[ReAct 또는 Orchestrator 분석: 조회 도구]
    RA --> C{playbook category}
    C -->|AUTO| F[고정 playbook 명령]
    C -->|NEEDS_APPROVAL| T[playbook 템플릿과 알람 label]
    C -->|READ_ONLY 또는 NONE| D[분석 결과만 알림]
    T --> P[PendingApprovalStore: 명령과 채널, TTL]
    U[Discord 사용자 대화] --> CA[ConversationAgent: 로그 조회와 실행 제안]
    CA --> V{isAllowed: 형식 검사}
    V -->|통과| P
    V -->|거부| X[거부]
    P --> Y{listener 조건 통과와 yes 또는 approve}
    Y -->|확인| E{실행 서비스의 공통 형식 검사}
    Y -->|취소 또는 만료| N[실행 안 함]
    F --> E
    E -->|통과| R[docker restart 실행과 결과 전송]
    E -->|거부| X

안전장치별로 막는 위험

안전장치 막는 위험 규칙 기반 webhook 앱 AI 장애 관제 Agent
요청 인증 위조된 경보 요청 X-Alert-Token 공유 비밀, 불일치 시 401[1:4] source에 언급 없음
반복 방지 같은 조치의 연쇄 실행 cooldownSeconds: 120[1:5] source에 언급 없음
허용 목록 예상하지 못한 명령, prompt injection으로 생성된 명령 allowedActions 화이트리스트[1:6] isAllowed()가 docker restart <container-name> 형식만 통과시킨다[4:1]
경보별 허가 조치 경보와 무관한 조치 코드에서 ApiDown·critical일 때만 재시작[1:7] 알람 경로는 AlertPlaybook으로 조치를 정하지만, 대화의 execute_command는 playbook을 검사하지 않는다[3:3]
시험 실행 정책 검증 전의 실제 변경 dryRun: true가 기본이며 실행 대신 로그만 남긴다[1:8] source에 언급 없음
사람 승인 분석 오판에 따른 실행 없음 NEEDS_APPROVAL과 대화 제안은 대기시킨 뒤 확인받고, AUTO는 승인 없이 실행한다[3:4]
도구 권한 분리 분석 단계의 과잉 판단에 따른 실행 해당 없음 ReActAgent는 조회 도구만 갖고, 실행 제안 도구는 ConversationAgent 전용이다[4:2]
승인 경로 분리 대화 Agent 출력이 스스로 승인됨 해당 없음 listener가 대화와 yes/no·approve를 분리한다. 채널·role 검사는 설정값이 있을 때 적용한다[3:5]
실행 환경 제한 docker.sock을 통한 컨테이너 탈출 Docker socket proxy 같은 제한 래퍼를 권장한다[1:9] source에 언급 없음

설계 포인트

한계와 주의

관련

테스트 질문

출처


  1. 자동 대응 시스템.md — "Alertmanager가 보낸 경보를 수신하여 화이트리스트/쿨다운 정책으로 Docker 재시작 등의 자동 대응 액션을 실행하는 Spring Boot 앱.", 구성 흐름 "토큰 검증 → 쿨다운 확인 → 화이트리스트 매칭 → docker / ssh / script 실행 (dryRun 모드 시 로그만)", token: "SHARED_SECRET" # 단순 토큰 검증, dryRun: true # true 시 실행 안 하고 로그만, cooldownSeconds: 120 # 같은 액션 반복 방지, allowedActions 화이트리스트, Controller 코드의 ResponseEntity.status(401).body("invalid token"), "cooldown" 응답, "ApiDown"·"critical" 매칭, "docker:restart leafy_api", private final AtomicLong lastActionTs, "Docker 소켓 직접 마운트 (/var/run/docker.sock) → 컨테이너 탈출 위험", "프록시/제한 래퍼(Docker socket proxy) 사용 권장" ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. 01-프로젝트-개요.md — "Alertmanager 웹훅을 수신해 AI가 자율적으로 분석하고 Discord를 통해 결과와 조치를 제안하는 에이전트", "Alertmanager에서 웹훅이 오면 에이전트가 자동으로 Prometheus 메트릭, Loki 로그, 과거 유사 사례(RAG)를 조회하고 근본 원인 및 조치를 분석한다.", "AlertPlaybook (알람별 허가된 조치 목록 조회)", "에이전트가 docker restart <container> 실행이 필요하다고 판단하면 직접 실행하지 않고 Discord로 확인 요청을 보낸다. 운영자가 yes를 입력해야 실행된다. 허가된 명령 패턴(docker restart <name>)만 실행 가능하다." ↩︎ ↩︎

  3. monitoring-agent-authorization-code-2026-10-09-a1ca1b7.md — local clean commit a1ca1b7의 발췌. AlertAnalysisChain.java L66–99·L116–133, AlertPlaybook.java L16–25·L88–89는 playbook과 AUTO 직접 실행, DiscordNotificationService.java L73–92는 NEEDS_APPROVAL의 대기 저장, ConversationAgent.java L59–80과 AgentTools.java L112–150은 대화 Agent의 조회 도구 등록과 Loki 조회 대상 검사, ConversationTools.java L14–50은 형식 검사 뒤 대기 저장, CommandExecutorService.java L22–32·L53–88은 공통 형식 검사와 실행, DiscordBotListener.java L49–90·L92–126 및 PendingApprovalStore.java L14–58은 조건부 role·채널 필터와 명령·채널별 승인이다. 실제 배포·설정값은 확인하지 않았다. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  4. 03-도구를-두-종류로-나눈-이유.md — "AgentTools는 읽기 전용으로 유지했다.", "ConversationTools는 ConversationAgent 전용으로 만들고, execute_command 하나만 넣었다.", "중요한 건 execute_command가 실제로 명령을 실행하지 않는다는 점이다. 실행이 아니라 "제안"이다.", "docker restart <container-name> 형식만 허용한다. 에이전트가 프롬프트 인젝션을 당하거나 예상치 못한 명령을 생성하더라도 이 검증을 통과하지 못하면 거부된다.", "PendingApprovalStore에 30분 TTL로 저장되고, Discord에서 "yes"가 들어와야 실행된다.", "같은 채널에서 "yes"를 입력한 사람만 해당 채널의 대기 명령을 실행할 수 있다.", ""yes/no" 처리 경로와 대화 처리 경로가 분리되어 있다.", "에이전트의 출력이 스스로 실행을 트리거하는 건 불가능하다.", "ConversationTools가 생성되는 시점에 컨텍스트(어느 채널, 어떤 알림)가 이미 고정된다.", "명령이 늘수록 isAllowed() 로직이 복잡해지고 검증 실수 가능성도 높아진다." ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  5. 03-에이전트-파이프라인.md — "AlertPlaybook — 알람명으로 허가된 조치 조회", DiscordNotificationService 분기 "[NEEDS_APPROVAL] → 분석 결과 + 명령 실행 승인 요청", "[AUTO] → 명령 자동 실행 후 결과 전송", "[READ_ONLY/NONE] → 분석 결과만 전송" ↩︎