Git 에 두되 읽을 수 없게
한 줄 요약
SOPS 는 YAML·JSON 파일의 구조와 키 이름은 그대로 두고 값만 암호화합니다. 그래서 비밀값도 다른 설정처럼 Git 에서 리뷰하고 기록을 남길 수 있고, 읽을 수 있는 사람은 수신자 목록으로 정합니다.
왜 이게 필요했나
비밀값을 Git 밖(위키, 메신저, 누군가의 노트북)에 두면 배포 설정과 비밀값이 서로 다른 속도로 움직입니다. 석 달 전 버전으로 되돌려야 하는 날 "그때의 비밀번호" 를 아는 사람이 없고, 누가 언제 값을 바꿨는지도 남지 않습니다. 반대로 평문으로 Git 에 넣으면 앞 모듈에서 본 사고가 납니다.
파일 전체를 암호화해 넣는 방법도 있지만, 그러면 리뷰어는 무엇이 바뀌었는지 볼 수 없습니다. 바뀐 것이 비밀번호인지 네임스페이스인지 모르는 변경을 승인하게 되고, 머지 충돌이 나면 손으로 풀 수도 없습니다.
어떻게 동작하나
SOPS 는 두 겹의 키를 씁니다.
| 층 | 무엇 | 어디에 |
|---|---|---|
| 데이터 키 | 값을 실제로 암호화하는 대칭 키(AES-256-GCM) | 파일 안, 수신자마다 따로 봉해서 |
| 수신자 키 | 데이터 키를 봉하는 공개 키(age·PGP·클라우드 KMS) | 수신자 본인만 비밀 키를 가짐 |
수신자 중 한 사람의 비밀 키만 있으면 데이터 키를 꺼내고, 그 데이터 키로 모든 값을 풉니다. 어떤 파일을 누구에게 암호화할지는 저장소 맨 위의 .sops.yaml 에 적습니다. 경로 정규식(path_regex)으로 파일을 고르고, encrypted_regex 로 어느 키 아래의 값만 암호화할지 고르고, 수신자 공개 키를 나열합니다.
age 는 키 하나가 한 줄짜리 문자열이라 다루기 쉬운 현대식 암호화 도구입니다. 공개 키는 age1 로, 비밀 키는 AGE-SECRET-KEY-1 로 시작합니다. 서비스도 사람처럼 자기 키를 가질 수 있어서, 서비스가 배포될 때 자기 비밀 키로 파일을 직접 풀게 만들 수 있습니다.
사람이 떠날 때가 이 구조의 진짜 시험입니다. 수신자 목록에서 그 사람을 빼고 sops updatekeys 를 돌리면 새 파일에서는 그 사람 몫의 봉투가 사라집니다. 하지만 데이터 키는 그대로입니다. 그 사람이 예전에 꺼내 둔 데이터 키가 있다면 새 파일도 열립니다. 그래서 sops rotate 로 데이터 키를 새로 만들고, 그 사람이 평문을 봤다면 값 자체도 바꿉니다.
현장에서 만나는 모습
가장 흔한 실수는 순서입니다. 평문 Secret 을 먼저 커밋하고 다음 커밋에서 암호화하면, 기록에는 평문이 남습니다. 암호화한 뒤에 처음 커밋하는 습관과, 커밋 전에 git diff --cached 로 올라가는 내용을 보는 습관이 둘 다 필요합니다.
두 번째는 퇴사·계약 종료 체크리스트에 이 일이 없다는 것입니다. 계정과 노트북은 회수하는데 .sops.yaml 의 공개 키는 아무도 지우지 않습니다. 수신자 목록은 사실상 접근 권한 목록이므로, 권한 검토 주기에 함께 넣어야 합니다.
고친 뒤 무엇으로 확인하나
암호화 설정은 눈으로 읽어서는 맞는지 알 수 없습니다. 확인은 열쇠를 바꿔 끼우며 직접 열어 보는 방식으로 합니다.
- 남아야 할 사람(운영자, 서비스)의 키로 열리는가. 서비스는 실제로 다시 띄워 자기 키로 읽게 합니다.
- 떠난 사람의 키로는 열리지 않는가. 수신자 목록을 읽는 것보다 그 키로 복호화를 시도하는 편이 확실합니다.
- 데이터 키가 바뀌었는가. 수신자 갱신만 했는지 회전까지 했는지는 파일 겉모습으로 구별되지 않습니다. 회전 전후의 데이터 키를 비교하거나, 적어도 회전 명령을 실행했다는 기록을 남깁니다.
- Git 의 모든 객체에 평문이 없는가. 지금 파일만 보지 말고 기록 전체를 훑습니다.
이 네 가지를 매번 손으로 하기 어렵다면, CI 에서 평문 검사를 돌리고 퇴사 절차 문서에 키 회수 항목을 넣는 것부터 시작합니다.
English corner
- envelope encryption: 봉투 암호화. 데이터 키로 값을 암호화하고, 그 데이터 키를 다시 다른 키로 봉하는 구조입니다.
- recipient: 수신자. age 와 SOPS 문서에서 "이 파일을 열 수 있는 공개 키" 를 이렇게 부릅니다.
- rotate the data key: 데이터 키를 회전한다. 수신자 변경과 다른 일이라는 것을 문서가 따로 강조합니다.
- offboarding: 사람이 조직을 떠날 때의 회수 절차입니다.
다음 실습에서 할 것
배포 저장소의 평문 Secret 을 운영자·서비스·외주 개발자 세 사람에게 암호화해 커밋하고, 서비스가 자기 키로 읽게 합니다. 외주 계약이 끝나는 날을 가정해 수신자를 빼고 데이터 키와 비밀번호를 함께 회전합니다.
한 걸음 더 — 키 보관과 복구
age 비밀 키 자체를 어디에 두는가가 다음 질문입니다. 운영자 키를 노트북에만 두면 그 노트북을 잃을 때 모든 암호문을 열 수 없게 됩니다. 그래서 수신자에 복구용 키(오프라인에 안전하게 보관한 키)를 하나 더 넣어 두는 조직이 많습니다. 서비스 키는 배포 플랫폼이 관리하고, 사람 키는 정기적으로 회전하며, 복구 키는 거의 쓰지 않되 분실에 대비해 남깁니다. 세 종류의 키가 수명과 보관 위치가 다르다는 것을 처음부터 설계에 넣어야, 사람이 떠나거나 노트북을 잃는 흔한 사건에 흔들리지 않습니다.