cron 이 새벽 세 시에 curl 을 했다 · 잡은 다음에 무엇을 먼저 하는가 · 이론
잡은 다음에 무엇을 먼저 하는가
한 줄 요약
대응은 순서 싸움이다. 격리는 증거를 지우고, 증거 수집은 피해를 키운다. 그래서 무엇을 지금 하고 무엇을 나중에 할지를 미리 정해 두고 사건 때는 그 표를 따른다.
왜 이게 필요했나
알림이 울린 뒤 30분 동안 일어나는 일은 대개 이렇다. 누군가 파드를 지운다. 누군가 노드를 재부팅한다. 누군가 cron 파일을 지운다. 한 시간 뒤 "어떻게 들어왔는지" 를 물으면 아무도 모른다. 침입 경로를 담고 있던 것을 전부 지워 버렸기 때문이다.
반대 방향도 실패다. 증거를 완벽하게 모으겠다고 손을 대지 않는 사이에 그 자격증명으로 다른 네임스페이스가 털린다.
그래서 대응 절차는 "무엇이 옳은가" 가 아니라 "무엇을 먼저 하는가" 의 문제다. [NIST SP 800-61](https://csrc.nist.gov/pubs/sp/800/61/r2/final) 이 오래 인용되는 이유도 이것이다 — 탐지·분석 다음에 격리·근절·복구가 오고, 그 사이의 판단 기준을 사건 전에 정해 두라고 한다.
어떻게 동작하나
실무에서 쓰는 순서는 네 단계로 줄일 수 있다.
1. 범위 정하기 무엇이 있는지 세고, 각 자료가 언제부터 언제까지인지 적는다2. 증거 보존 원본은 건드리지 않고 사본 + 해시. 휘발성이 큰 것부터3. 타임라인 출처가 다른 기록을 하나의 시간축(UTC)에 올린다4. 격리·근절 표에 따라 조치. 각 조치에 근거 한 줄휘발성 순서가 핵심이다. 메모리는 프로세스를 죽이는 순간 사라지고, 프로세스 목록과 열린 소켓은 재부팅하면 사라지고, 디스크의 파일은 대체로 남는다. 그래서 "프로세스를 지금 죽일까" 라는 질문의 답은 거의 언제나 "메모리를 뜬 다음에" 다.
반대로 자격증명 폐기는 미룰 수 없다. 노드 하나를 꺼도 그 노드에서 새어 나간 인증서는 클러스터 어디서든 계속 쓰인다. 쿠버네티스에서 노드의 신원은 system:node:<이름> 이고 [Node 인가 모드](https://kubernetes.io/docs/reference/access-authn-authz/node/)가 그 신원이 무엇을 읽을 수 있는지를 정한다. 그 노드에 스케줄된 파드가 쓰는 시크릿이 거기 포함되므로, 노드 하나의 자격증명이 곧 그 노드 위 워크로드의 비밀 전부다.
타임라인을 만들 때는 형식을 미리 못 박는 편이 낫다. 시각은 UTC ISO 8601 로, 출처 이름은 정해진 낱말로, 행위자와 무슨 일을 각각 한 칸에. 그렇게 해 두면 여러 사람이 나눠 적어도 합칠 수 있고, 정렬만으로 이야기가 보인다.
조치 표는 사건마다 새로 쓰는 것이 아니라 미리 만들어 두고 그날의 값만 채운다. 예를 들면 이런 모양이다.
조치 시점 근거메모리 수집 지금 프로세스를 건드리면 사라진다. 되돌릴 수 없다네트워크 차단 지금 외부로 나가는 것만 끊는다. 프로세스는 살려 둔다프로세스 종료 나중 메모리를 뜬 뒤. 지금 죽이면 그 증거가 함께 죽는다예약 작업 제거 나중 지속화 수단은 원본을 보존한 뒤에 치운다자격증명 폐기 지금 노드를 꺼도 유출된 인증서는 클러스터에서 계속 쓰인다노드 재설치 나중 디스크 이미지를 뜬 뒤. 마지막 단계다표가 있으면 새벽 세 시에 판단할 것이 줄어든다. 판단할 것이 줄어들면 실수도 줄어든다.
그리고 조사에서 실제로 일이 진행되는 방식은 축(pivot) 이다. 하나의 값 — PID, 파일 경로, 목적지 주소, 신원 — 을 잡고 다른 자료에서 같은 값을 찾는다. 호스트 로그의 PID 하나가 커널 감사 기록으로 이어지고, 거기서 읽힌 인증서 경로가 나오고, 그 인증서의 신원이 API 서버 감사 로그의 user.username 과 맞아떨어진다. 그 연결이 "노드가 뚫렸다" 를 "결제 네임스페이스의 시크릿이 읽혔다" 로 바꾼다.
현장에서 만나는 모습
사후 분석 보고서에서 가장 자주 빠지는 절이 탐지 공백이다. 무슨 일이 있었고 어떻게 고쳤는지는 다들 쓰는데, "왜 세 시간 동안 아무도 몰랐는가" 는 안 쓴다. 그런데 다음 사건을 줄이는 것은 그 절이다. 규칙이 없었는지, 규칙은 있었는데 알림이 아무도 안 보는 채널로 갔는지, 로그 자체가 없었는지는 전혀 다른 처방으로 이어진다.
두 번째로 자주 무너지는 것이 증거의 무결성이다. 원본 파일을 열어서 편집기로 보다가 저장 버튼을 누르면 그 순간 그 파일은 증거가 아니다. 사본을 뜨고 해시를 남기는 30초가 그것을 막는다.
세 번째는 보고서가 사람 이름으로 끝나는 것이다. "담당자가 실수했다" 로 끝나는 보고서는 다음 주에 같은 사고를 부른다. 고쳐야 할 것은 대개 "왜 그 실수가 가능했는가" 쪽에 있다 — 그 예약 작업 디렉터리에 아무나 쓸 수 있었던 것, 노드 인증서가 워크로드와 같은 파일시스템에 있었던 것, 알림 채널에 아무도 없었던 것.
네 번째는 타임라인의 시간대가 섞이는 것이다. Falco 알림은 UTC 로 남고, 저널은 화면에 보여 줄 때 호스트의 지역 시간을 쓰고, 감사 로그 원본은 에폭 초다. 이 셋을 그대로 붙이면 세 시간짜리 사건이 여섯 시간으로 보이거나 순서가 뒤집힌다. 그래서 타임라인의 첫 칸은 언제나 UTC 로 통일하고, 원본 형식은 필요하면 마지막 칸에 덧붙인다.
다음 실습에서 할 것
실습에서는 실제 사건 하나의 자료 네 종류 — Falco 알림, 커널 감사 원본, cron 의 저널, 쿠버네티스 감사 로그 — 를 받아 조사를 한 바퀴 돈다. 자료를 세고, 최초 알림을 집고, 사본과 해시로 증거를 보존하고, 네 출처를 하나의 시간축에 올리고, 축을 잡아 호스트에서 클러스터로 건너뛰고, 조치 여섯 가지의 순서를 근거와 함께 정하고, 마지막에 사후 분석 보고서를 쓴다. 파일만 다루므로 실습 파드에서 돈다.