로그는 있었다.
Activity Log도 있고, Query Audit도 있고, Workflow도 있고, Export도 있었다. 하나씩 보면 다 맞는 기능이다. 그런데 고객 감사 대응을 시작하는 순간 질문이 바뀐다.
“그래서 이 변경이 안전하게 통제됐다는 걸 어떻게 증명하나요?”
안녕. 오늘 이야기는 로그 기능 자체보다, 로그들이 서로 손을 잡지 못할 때 생기는 문제에 가깝다. 제품 안에 증거 조각은 충분히 있는데, 사람이 그 조각을 엑셀과 기억력과 약간의 기도로 이어 붙여야 하는 상황 말이야.
감사는 로그 목록을 보러 오지 않는다
엔지니어는 흔히 이렇게 생각한다.
“로그 남겼으니까 됐지.”
틀린 말은 아니다. 하지만 감사 대응에서는 반만 맞다. 감사에서 필요한 건 로그의 존재가 아니라 이야기의 재구성이다.
예를 들어 어떤 원장 테이블 정책이 바뀌었다고 해보자. 감사관이나 고객 담당자가 궁금한 건 보통 이런 순서다.
누가 바꿨나?
언제 바꿨나?
무엇을 바꿨나?
어떤 승인 절차를 거쳤나?
그 뒤 실제로 어떤 Query가 실행됐나?
변경 전후 값은 무엇이었나?
이 질문에 답하려면 Activity Log 하나만으로는 부족하다. Workflow도 봐야 하고, Query Audit도 봐야 하고, 경우에 따라 DML Snapshot이나 정책 설정 화면도 봐야 한다.
여기서 재밌는 역설이 나온다. 기능은 많아질수록 답이 쉬워질 것 같은데, 서로 연결되지 않으면 오히려 탐정 일이 늘어난다.
“클릭하면 보인다”는 “바로 증명된다”가 아니다
Activity Log 화면에서 항목을 누르면 상세가 나온다. 그 자체는 괜찮다. 그런데 감사 대응에서는 “상세를 열면 언젠가 볼 수 있음”과 “한눈에 증거로 제출할 수 있음” 사이에 큰 강이 있다.
Connection과 Database는 보이는데 Schema와 Table은 상세를 눌러야 보인다고 해보자. 평소 운영 화면에서는 큰 문제가 아닐 수 있다. 하지만 원장 테이블 관련 변경만 빠르게 모아 봐야 하는 상황에서는 이야기가 달라진다.
한 건이면 클릭하면 된다.
열 건이면 Export한다.
백 건이면 엑셀이 열린다.
그리고 어느 순간 제품 화면은 뒤로 물러나고, 사람이 만든 임시 리포트가 실제 업무 도구가 된다. 이건 UX 문제가 아니라 운영 비용 문제다. 더 정확히는 제품이 해야 할 증적 연결을 사람이 대신하고 있는 상태다.
Workflow와 Query Audit은 서로 인사해야 한다
Workflow는 절차를 말한다. 누가 요청했고, 누가 승인했고, 어떤 상태로 끝났는지 보여준다.
Query Audit은 실행을 말한다. 누가 어떤 Query를 언제 실행했고, 결과가 어땠는지 보여준다.
둘 다 중요하다. 그런데 감사 질문은 보통 둘 중 하나만 묻지 않는다.
“승인된 요청이 실제로 어떻게 실행됐나요?”
이 질문이 나오는 순간 Workflow와 Query Audit은 서로 인사해야 한다. Workflow 화면에서 관련 Query Audit으로 바로 가고, Query Audit에서도 관련 Workflow와 승인 단계를 되짚을 수 있어야 한다.
이 연결이 없으면 사람은 시간대를 좁히고, 사용자 이름을 맞추고, SQL 내용을 비교하고, Export 파일을 열어본다. 탐정물로 쓰면 재밌지만, 제품 운영으로는 피곤하다.
원장 통제는 현재 상태와 과거 사건을 섞으면 안 된다
Ledger 같은 원장 통제 영역에서는 더 조심해야 한다.
현재 어떤 테이블이 Ledger 정책 대상이라고 해서, 과거 어떤 Query가 실행될 당시에도 그랬다고 단정하면 안 된다. 현재 설정은 현재 설정이고, 변경 이력은 변경 이력이고, 실제 실행 증적은 또 다른 데이터다.
쉽게 말하면 이런 식이다.
현재 설정: 지금 이 테이블은 Ledger 대상인가?
변경 이력: 언제 Ledger 대상으로 등록됐나?
실행 증적: 특정 Query가 실행될 당시 정책이 적용됐나?
승인 증적: 그 실행은 어떤 승인 절차를 거쳤나?
이 네 가지를 한 덩어리로 뭉치면 설명은 빨라 보이지만 위험해진다. 실행 시각보다 Ledger 설정 시각이 늦다면, 지금은 Ledger 대상이어도 당시에는 아닐 수 있다.
그런 경우 제품은 “문제 있음”이라고 바로 단정하기보다 configuredAfterExecution 같은 상태로 보여주는 편이 낫다. 결론을 대신 내리는 게 아니라, 사람이 확인해야 할 후보를 정확히 좁혀주는 것이다.
좋은 리포트는 SQL 모음이 아니다
고객 지원을 하다 보면 쿼리가 쌓인다.
처음에는 임시 SQL 하나다. 다음에는 가이드가 붙는다. 그다음에는 컬럼 설명이 붙고, 실행 순서가 붙고, 한계 문구가 붙는다. 어느 순간 이것은 “쿼리”가 아니라 “감사 대응 패키지”가 된다.
그래서 Report 프로젝트를 만든다면, 단순히 SQL을 모아두는 것으로는 부족하다. 각 리포트는 최소한 이런 정보를 가져야 한다.
무슨 질문에 답하는가?
어떤 입력 조건이 필요한가?
어떤 화면/로그/API를 근거로 삼는가?
어떤 경우에는 단정하면 안 되는가?
고객에게는 어떤 문장으로 설명할 수 있는가?
특히 폐쇄망 고객이나 금융권 고객에서는 “나중에 누군가 다시 실행할 수 있는가”가 중요하다. 한 명의 엔지니어가 멋지게 해결한 사건은 고맙지만, 다음 감사 때도 그 사람이 깨어 있어야 한다면 시스템이라고 부르기 어렵다.
제품이 대신 해줘야 할 일
이 문제를 크게 만들지 않으려면, 제품은 로그를 더 많이 남기는 것만으로는 부족하다.
로그 사이의 길을 만들어야 한다.
- Activity Log 목록에서 Schema, Table, Policy Type, 변경 전후 요약을 바로 볼 수 있게 하기
- Workflow에서 실제 Query Audit으로 이동할 수 있게 하기
- Query Audit에서 관련 Workflow 승인 절차로 되돌아갈 수 있게 하기
- 원장 관련 변경과 실행을 정기 점검 리포트로 좁혀주기
- 단정할 수 없는 항목은
manualReviewRequired처럼 솔직하게 표시하기
이런 기능은 화려하지 않다. 데모 영상에서 박수받기 어려울 수도 있다. 하지만 고객 감사 대응 순간에는 이런 기능이 제품의 신뢰도를 만든다.
진짜 감사 대응 제품은 “로그가 있습니다”에서 끝나지 않는다.
“이 사건을 이렇게 따라가면 증명할 수 있습니다”까지 데려다준다.
그리고 아마 이게 운영형 제품의 묘미다. 멋진 기능은 사용자를 놀라게 하지만, 좋은 증적 동선은 사용자를 안심시킨다. 둘 중 오래 기억되는 건 대개 후자다.