JStory Box
별의 제국
001 / 130LONG-FORM EDITION

ORIGINAL FICTION

제53화 — 섞이면 안 되는 것

14,610일 · 53 / 287약 8분0자
지난 화 끝부분 다시 보기

계산서비스가 열두 고객을 넘겼을 때 첫 보안사고가 날 뻔했다.

‘날 뻔했다’는 표현이 중요했다.

실제 데이터 유출은 없었다.

하지만 충분히 가까웠다.

고객 A의 작업결과가 임시 저장폴더에 남아 있었다.

고객 B 작업을 준비하던 직원이 잘못된 경로를 열었다.

파일명만 보였다.

내용을 열기 전에 멈췄다.

즉시 보고.

운영팀은 해당 영역을 잠갔다.

대니얼에게 Level 3 경보가 왔다.

그는 20분 만에 사무실에 도착했다.

“누가 봤습니까?”

“직원 한 명.”

“고객 데이터 열었습니까?”

“아뇨. 파일명만.”

“외부 노출?”

“확인상 없습니다.”

대니얼은 숨을 내쉬었다.

“원인.”

운영책임자가 말했다.

“임시 스테이징 영역이 고객별로 완전히 분리되지 않았습니다.”

“왜?”

“초기엔 고객 몇 곳이라 작업자가 직접 폴더 나눴습니다.”

대니얼의 얼굴이 굳었다.

수동.

작은 규모에서는 돌아갔다.

규모가 커지자 위험이 됐다.

“서비스 중단.”

이선이 고개를 들었다.

“전부?”

“확인 끝날 때까지.”

운영담당이 말했다.

“현재 작업 열아홉 건 있습니다.”

“멈춥니다.”

“고객 SLA—”

“데이터 섞이는 것보다 낫습니다.”

이번에는 아무도 반대하지 않았다.

서비스 전체가 정지됐다.

고객에게 공지.

‘보안 격리 점검을 위해 일시 중단.’

구체적 사건도 숨기지 않았다.

아직 유출은 확인되지 않았다고 명시.

첫 전화는 바로 왔다.

“우리 데이터 문제 있습니까?”

“현재 노출 확인 없습니다.”

“그럼 왜 멈춰요?”

“노출 가능성이 있는 구조를 발견했기 때문입니다.”

고객 쪽은 잠깐 조용했다.

“언제 재개합니까?”

“확인 후 알려드리겠습니다.”

대니얼은 이번에는 시간을 섣불리 약속하지 않았다.

팀은 밤새 구조를 뜯었다.

고객별 디렉터리.

권한.

작업계정.

임시파일.

로그.

결과물.

A1과 범용 노드 사이 데이터 이동.

생각보다 많은 곳에서 ‘편의상’ 공유가 있었다.

초기 서비스는 사람이 기억하고 구분했다.

이제 안 된다.

대니얼이 말했다.

“고객별 완전격리.”

운영책임자가 고개를 끄덕였다.

“논리적으로뿐 아니라 계정과 저장영역까지.”

“작업자도 필요한 고객만.”

“네.”

“테스트 데이터도 섞지 말고.”

“네.”

이선이 말했다.

“비용 올라가.”

대니얼은 바로 답했다.

“올라가도 합니다.”

이번에는 망설임이 없었다.

서비스는 이틀 반 멈췄다.

매출손실.

긴급작업 일부 환불.

한 고객은 불만이 컸다.

다른 고객은 오히려 말했다.

“문제 생기기 전에 멈춘 건 잘한 것 같습니다.”

대니얼은 두 반응 다 받아들였다.

재개 전 외부 보안자문도 받았다.

자문가는 냉정했다.

“이건 규모가 작을 때 흔히 생기는 구조입니다.”

대니얼이 물었다.

“흔하면 괜찮습니까?”

“아뇨.”

상대가 웃었다.

“흔하다고 안전한 건 아니죠.”

자문가는 더 불편한 질문을 던졌다.

누가 관리자 권한을 갖는가.

퇴사자가 생기면?

로그는 누가 지울 수 있는가.

백업도 분리됐는가.

장애복구 시 고객 데이터가 어디로 가는가.

대니얼은 대부분 답했다.

일부는 답하지 못했다.

“보안도 시스템이네요.”

대니얼이 말했다.

자문가가 웃었다.

보안점검 이틀째, 한 직원이 대니얼에게 찾아왔다.

그날 잘못된 폴더를 연 사람이었다.

표정이 굳어 있었다.

“제가 실수했습니다.”

대니얼은 바로 대답하지 않았다.

“어떤 실수요?”

“경로 확인을 안 하고 열었습니다.”

“왜?”

“익숙해서요.”

직원은 처벌을 예상하는 얼굴이었다.

대니얼은 사건기록을 다시 봤다.

경로 구조.

권한.

폴더 이름.

사람이 실수할 가능성을 전제로 하지 않은 시스템.

“같은 상황 다시 주면 또 실수할 수 있습니까?”

직원이 당황했다.

“안 합니다.”

“그게 아니라.”

대니얼이 말했다.

“누구든 할 수 있냐고요.”

직원은 잠깐 생각했다.

“네.”

“그럼 사람만의 문제는 아닙니다.”

대니얼은 사고보고서의 원인 항목을 고쳤다.

기존 초안.

Operator error

새 문장.

Inadequate isolation allowed operator error to create exposure risk.

직원이 그걸 보고 놀랐다.

“제 책임이 없는 건 아닙니다.”

“있습니다.”

대니얼이 말했다.

“하지만 당신 해고하면 폴더 구조가 안전해집니까?”

“아뇨.”

“그럼 그건 해결이 아닙니다.”

이선이 나중에 보고서를 읽고 말했다.

“좋네.”

“뭐가요?”

“예전 같으면 누가 실수했는지 먼저 찾았을 것 같은데.”

대니얼은 부정하지 못했다.

2046년 막판에는 사람이 실수하면 화부터 났다.

시간이 없었으니까.

하지만 압박이 클수록 사람이 실수하지 않는 시스템이 더 필요했다.

직원은 징계 대신 재교육을 받았다.

그리고 새 격리구조 검증팀에 들어갔다.

자기가 실수했던 경로를 가장 잘 알았기 때문이다.

몇 주 뒤 그 직원이 새 문제 하나를 발견했다.

백업복구 테스트 중 권한이 예상보다 넓어지는 순간.

실제 고객 데이터로 가기 전에 차단.

대니얼이 말했다.

“이번엔 당신이 막았네요.”

직원이 조금 웃었다.

“지난번 덕분입니다.”

그 문장이 대니얼에게 오래 남았다.

실패한 사람을 제거하는 것보다 실패를 이해한 사람을 시스템 개선에 쓰는 편이 강할 수 있다.

물론 악의나 반복적 무시는 다른 문제다.

하지만 정직한 실수와 시스템 결함을 구분해야 한다.

A1에서 배운 실패문화가 이제 보안사고에도 적용되고 있었다.

서비스 재개 후 첫 한 달.

보안사고 0.

접근차단 이벤트는 여러 건.

대부분 정상적인 오입력.

시스템이 막았다.

대니얼은 그 숫자가 좋았다.

사람이 완벽해진 게 아니다.

사람이 틀려도 고객 데이터가 섞이지 않게 됐다.

좋은 시스템은 사람을 믿지 않는 시스템이 아니라, 사람이 인간일 수 있게 만드는 시스템일지도 몰랐다.

“원래 그렇습니다.”

“저희는 제품기능처럼 봤던 것 같습니다.”

“보안은 기능이라기보다 제약에 가깝습니다.”

“제약?”

“무엇을 하면 안 되는지 정하는 것.”

대니얼은 그 말을 좋아했다.

기술은 가능성을 늘린다.

보안은 허용되는 가능성을 줄인다.

둘 다 시스템을 만든다.

서비스 재개.

이번에는 고객마다 명확히 분리된 환경.

작업 하나가 다른 고객 영역에 접근하려 하면 자동차단.

대니얼은 일부러 공격 테스트를 시켰다.

접근 실패.

로그 발생.

경보.

좋았다.

그런데 성능은 조금 나빠졌다.

격리 비용.

중복 저장.

환경복제.

대니얼이 말했다.

“최적화할 수 있습니까?”

운영책임자가 웃었다.

“대표님.”

“네.”

“보안 없애면 제일 빨라집니다.”

사람들이 웃었다.

대니얼도 웃었다.

“그건 안 됩니다.”

“그러니까 성능 일부는 보안값입니다.”

그 문장이 마음에 들었다.

성능의 반대편에 ‘낭비’만 있는 게 아니다.

안전.

복구.

보안.

여유.

미래의 Daniel은 이 요소들을 훨씬 큰 시스템에 넣어야 한다.

그날 사고기록 제목은 이렇게 남았다.

Cross-Tenant Exposure Near Miss

실제 유출 0.

피해 0.

그럼에도 회사 전체가 멈췄다.

한 직원이 물었다.

“너무 과한 대응 아니었습니까?”

대니얼은 고개를 저었다.

“아무 일도 안 났을 때 고치는 게 제일 싸니까요.”

공장 사고근접 보고에서 배운 문장.

이제 서버에 적용됐다.

사고가 나기 전에 보이는 흔적을 잡는다.

대니얼은 서비스가 커질수록 A1보다 훨씬 많은 걸 배우고 있다는 생각을 했다.

서비스 재개 뒤 고객 설명회도 열었다.

큰 회의가 아니라 온라인 통화였다.

대니얼은 직접 참석했다.

첫 질문은 날카로웠다.

“실제 유출이 없다는 걸 어떻게 증명합니까?”

보안책임자가 로그와 권한기록을 설명했다.

대니얼은 기술적 세부보다 무엇을 확인했고 무엇은 아직 확인 중인지 구분해 말했다.

두 번째 질문.

“왜 이런 구조가 처음부터 없었습니까?”

대니얼은 잠깐 망설였다.

핑계는 많았다.

고객이 적었다.

초기 서비스였다.

빠르게 만들었다.

그는 짧게 답했다.

“저희 판단이 부족했습니다.”

침묵.

“그래서 구조를 바꿨습니다.”

고객 한 명이 말했다.

“그 답이 제일 낫네요.”

대니얼은 조금 놀랐다.

완벽한 척하는 것보다 잘못을 인정하고 수정한 구조를 보여주는 편이 신뢰를 만들었다.

물론 모든 고객이 안심한 것은 아니었다.

한 곳은 계약을 줄였다.

또 한 곳은 보안검토를 추가했다.

Helioxen은 그 비용을 받아들였다.

신뢰는 한 번의 설명으로 복구되는 게 아니다.

몇 달 동안 사고 없이 운영해야 했다.

대니얼은 그 긴 시간이 필요하다는 사실을 받아들였다.

미래를 아는 자신에게 가장 힘든 건 언제나 ‘시간이 걸린다’는 답이었다.

그래도 어떤 시간은 돈으로 못 줄인다.

신뢰.

숙련.

관계.

검증.

그런 것들은 반복해서 쌓아야 했다.

END OF CHAPTER

읽은 화로 기록했습니다. 다음 화는 바로 이어집니다.

다음 화

읽는 흐름을 끊지 않고 바로 다음 화로 이어집니다.

읽던 위치를 저장했습니다.