Poooling Forest
빌딩 정문 손잡이가 거대한 금속 열쇠 모양으로 바뀐 시네마틱 이미지, 키 하나가 회사의 정문이 되는 장면
Security

Private Repo에 올린 키 하나가 회사의 정문이 됩니다

private repo는 금고가 아니라 권한 있는 사람만 보는 저장소입니다. 티빙·GitHub·Nx 사고와 GitGuardian 통계로 보면, 보안의 정답은 키를 잘 숨기는 것이 아니라 오래 살아 있는 키를 애초에 만들지 않는 구조였습니다.

송찬영

CTO

몇 년 전, 저는 보안을 '얼마나 잘 숨겼느냐'의 문제로만 봤습니다. 키를 환경변수로 빼고, 설정 파일을 gitignore에 넣고, 저장소를 private으로 돌려놓으면 일이 끝났다고 생각했습니다. 그렇게 한 다음에는 마음이 꽤 놓였습니다.

그러다 새벽에 한 줄의 알림을 받은 적이 있습니다. 오래전 누군가가 테스트하다 잠깐 커밋했던 키가, 이미 지운 줄 알았던 키가, 과거 커밋 어딘가에 그대로 살아 있다는 내용이었습니다. 저장소는 분명 private이었습니다. 그런데도 그 키는 멀쩡히 작동하고 있었습니다. 그날 저는 한 가지를 깨달았습니다. private repo는 제가 생각한 금고가 아니었습니다.

요즘 정보 유출 사고가 부쩍 잦습니다. 그런데 해커가 늘 복잡한 기술로 데이터베이스를 뚫는 건 아닙니다. 더 조용하고 빠른 길이 따로 있습니다. 오늘은 그 길에 대해, 그리고 그 길을 아예 없애는 방법에 대해 이야기해 보려고 합니다.

private repo는 금고가 아닙니다

살짝 열린 금고 문 안이 평범한 코드 저장소 화면인 모습, 옆 복도에 키와 토큰이 흩어진 장면

많은 팀이 private repo에 올린 코드는 안전하다고 믿습니다. 저도 그랬습니다. 하지만 private repo는 금고가 아니라, 권한이 있는 사람만 들여다볼 수 있는 저장소일 뿐입니다. 문이 자물쇠가 아니라 명단으로 잠겨 있는 셈입니다.

그래서 명단 안의 누군가가 흔들리면 문은 그냥 열립니다. 계정 하나가 탈취되거나, 개발자 PC의 세션이 노출되거나, CI/CD 토큰 하나가 새기만 해도 그렇습니다. 그 순간 저장소 안에 잠들어 있던 키들, GitHub에 남은 키, 개발자 PC의 토큰, CI/CD의 배포 권한, 클라우드 접근 권한이 한꺼번에 회사의 출입증으로 바뀝니다.

해커가 굳이 어려운 DB 취약점을 파고들 이유가 없습니다. 정문 열쇠가 코드 안에 그냥 놓여 있기 때문입니다. 공격자는 늘 가장 쉬운 출입구를 먼저 찾습니다.

유출 증가, 대부분 키에서 시작됩니다

급상승하는 막대 그래프 위로 키 아이콘이 흩날리는 데이터 시각화

이것이 제 경험에서 끝나는 이야기였으면 좋겠지만, 숫자가 그렇지 않다고 말합니다. GitGuardian의 연례 시크릿 유출 리포트에 따르면, 2025년 한 해 public GitHub 커밋에서만 2,864만 개가 넘는 신규 하드코딩 시크릿이 탐지됐습니다. 전년 대비 34% 늘어난 수치입니다.

저는 이 숫자를 보면서 AI 생각을 했습니다. 코드 생산 속도가 빨라지는 만큼, 그 코드에 섞여 들어가는 키와 토큰도 같은 속도로 늘어나고 있다는 뜻이기 때문입니다. 빠르게 만들수록 빠르게 새는 것입니다. public 저장소가 이 정도라면, '우리는 private이라 괜찮다'는 안심이 얼마나 얇은 것인지 짐작이 갑니다.

티빙 사고가 던진 질문

데이터센터 복도 바닥에 클라우드 액세스 키 카드가 떨어진 장면, 옐로우 경고 톤

최근 사례 하나를 짚어보겠습니다. 개인정보위 발표에 따르면, 티빙은 2026년 6월 3일 개인정보 유출 신고를 했고, 하루 전인 6월 2일에 데이터베이스 비인가 접근과 개인정보 유출 정황을 인지했다고 합니다.

제가 주목한 건 사고 대응 과정이었습니다. 보도 기준으로 그 과정에 AWS 액세스 키 폐기와 GitHub 자격증명 교체 조치가 포함됐다고 합니다. 정확한 침입 경로는 조사 결과를 더 지켜봐야 하니 단정할 일은 아닙니다. 다만 대응 조치에 '키 폐기'와 '자격증명 교체'가 들어갔다는 사실만으로도, 클라우드 출입증의 위치가 사고의 한가운데에 있다는 점은 분명해집니다.

우리 회사의 클라우드 출입증은 지금 어디에 있습니까.

저는 이 질문을 받고 나서야 우리 시스템을 처음부터 다시 훑어봤습니다. 누가, 어떤 키로, 어디까지 들어갈 수 있는지를 처음부터 확인했습니다.

GitHub도, 개발 도구도 예외가 아닙니다

감염된 코드 에디터에서 토큰들이 빠져나가고, 확장 아이콘이 촉수처럼 키와 .env 파일을 끌어가는 구도

'그래도 우리는 GitHub 같은 큰 곳을 쓰니까'라는 마음도 위험합니다. GitHub은 2026년 5월, 직원 장비가 악성 코드가 심긴(poisoned) VS Code 확장에 감염되면서 내부 저장소가 유출됐다고 밝혔습니다. 저장소를 가장 잘 다루는 회사조차 예외가 아니었습니다.

Nx Console 사고도 비슷한 결이었습니다. 악성 VS Code 확장이 배포됐고, 영향받은 사용자들에게 자격증명 회전을 안내했습니다. 평소에 무심코 깔던 확장 프로그램 하나가 GitHub 토큰, AWS 정보, SSH 키, 그리고 .env 파일까지 노릴 수 있다는 이야기입니다.

여기서 핵심은 명확합니다. 개발자 PC가 한 번 뚫리면, private repo도 더 이상 안전하지 않습니다. 명단 안의 사람이 쓰는 도구가 곧 문이기 때문입니다.

키를 지웠는데 왜 위험합니까

휴지통에 버린 키가 여러 갈래 커밋 히스토리와 브랜치에 그대로 복제되어 남아 있는 그래프

여기서 제가 새벽에 겪은 그 장면으로 돌아가게 됩니다. 분명히 지웠는데 키가 살아 있었던 이유. 답은 단순합니다. Git은 기록을 남기기 때문입니다.

최신 코드에서 한 줄을 지운다고 그 키가 사라지는 게 아닙니다. 과거 커밋, 다른 브랜치, 누군가의 clone, 로그, 빌드 artifact 어딘가에 그대로 남아 있을 수 있습니다. 화면에서만 보이지 않을 뿐, 실제로는 여러 갈래로 복제되어 살아 있는 것입니다.

GitHub도 같은 이야기를 합니다. 유출된 secret은 즉시 침해된 것으로 보고, 단순 삭제가 아니라 revoke나 rotation이 필요하다고 안내합니다. 정리하면 이렇습니다. 키는 삭제가 아니라 폐기와 재발급이 원칙입니다. 지우는 것과 무효화하는 것은 전혀 다른 일입니다.

가장 위험한 착각, 그리고 정석 구조

여기까지 오면 '그럼 키를 더 잘 숨기자'는 결론에 닿기 쉽습니다. 그런데 이것이 제가 오래 빠져 있던 착각이었습니다. 숨긴 키는 결국 커밋 히스토리에, 백업에, 누군가의 노트북에 남습니다. 숨기는 한 어딘가에는 존재하고, 존재하는 한 언젠가 샙니다.

그래서 기준을 바꿔야 합니다. 정답은 키를 잘 숨기는 것이 아니라, 애초에 오래 살아 있는 키를 만들지 않는 것입니다. 훔쳐 갈 키 자체가 없으면, 명단이 흔들려도 가져갈 게 없기 때문입니다. 풀링포레스트가 자격증명을 다루는 운영 원칙도 정확히 이 한 문장에서 출발합니다.

구체적으로는 이렇게 설계합니다. 사람의 접근은 장기 액세스 키를 발급하지 않고 AWS IAM Identity Center의 SSO 로그인으로 처리해, 만료되는 임시 자격증명만 쓰게 합니다. 서버는 자기 권한을 코드에 박힌 키가 아니라 IAM Role로 받습니다. 권한은 계정, 환경, 서비스별로 Role을 잘게 나누고, production Role은 branch와 environment, 승인 조건으로 접근을 제한해 최소 권한을 지킵니다.

애플리케이션이 쓰는 비밀값, 그러니까 DB 비밀번호, 외부 API 키, OAuth, SMTP, PG사 키, private key 같은 것들은 코드나 GitHub Secret에 두지 않고 Secrets Manager에서 런타임에 조회합니다. 운영 서버 접속도 SSH 키를 사람끼리 돌려쓰는 대신 SSM Session Manager로 전환합니다. 이렇게 하면 로컬에도, 원격 저장소에도 '오래 사는 키'가 남지 않는 구조가 됩니다.

오늘 바로 점검할 7가지

거창한 보안 프로젝트를 시작하기 전에, 오늘 당장 스스로에게 던질 수 있는 질문들이 있습니다. 저도 우리 시스템을 다시 훑을 때 이 순서로 점검했습니다.

  1. AWS access key가 GitHub에 들어간 적이 있는가.
  2. GitHub Actions에 장기 AWS key가 들어가 있는가.
  3. 개발자는 AWS Identity Center로 접근하는가.
  4. 서버는 IAM Role로 권한을 받는가.
  5. DB와 외부 API 키는 Secrets Manager에 있는가.
  6. Secret scanning과 push protection이 켜져 있는가.
  7. 유출된 키를 삭제만 하고 폐기는 안 한 적이 있는가.

일곱 질문 중 하나라도 '글쎄'라는 답이 나온다면, 거기가 지금 우리 회사의 정문일 가능성이 높습니다.

좋은 보안은 속도를 늦추지 않습니다

풀링포레스트에서 업무시스템과 ERP, AI 도구를 만들면서 제가 점점 또렷해진 생각이 있습니다. 좋은 보안은 개발 속도를 늦추는 장치가 아니라, 누군가 실수해도 회사 전체가 열리지는 않도록 받쳐 주는 구조라는 점입니다. 사람은 실수합니다. 키는 새기 마련입니다. 그걸 전제로 시스템을 짜는 게 진짜 안전한 설계입니다.

private repo에 키를 두지 않는 것, 오래 살아 있는 키를 만들지 않는 것, 그리고 권한을 작업하는 그 순간에만 잠깐 열어 주는 것. 이 세 가지가 시작점입니다. 어렵게 들리지만 결국은 '훔쳐 갈 게 없는 상태'를 만드는 일이라, 한 번 자리 잡으면 오히려 마음이 가벼워집니다.

여러분의 회사는 어떻습니까. 지금 클라우드 출입증이 어디에 있는지, 그 키가 얼마나 오래 살아 있는지 한번 떠올려 보시면 좋겠습니다. 그 질문 하나가 새벽의 알림을 막아 줄지도 모릅니다.

지금 읽으신 내용, 귀사에 적용해보고 싶으신가요?

상황과 목표를 알려주시면 가능한 옵션과 현실적인 도입 경로를 제안해드립니다.

보안클라우드 보안시크릿 관리OIDCDevSecOps