TT Lab
블로그 시작하기
배우기 러닝패스 코스

지운 토큰이 기록에서 문을 연다

외주 개발자가 떠나는 날의 SOPS

TT Lab 에서 이어서 보기

이 실습은 VM 에서 돕니다

우분투 24.04 VM 한 대입니다. root 이고 systemd 와 커널 기능이 그대로 있습니다. 실습 파드에는 capability 가 없어 이 실습이 다루는 설정을 바꿀 수 없기 때문에 VM 으로 돕니다. 처음 뜨는 데 몇 분이 걸립니다. 세션이 끝나면 VM 은 통째로 사라지므로 남기고 싶은 것은 화면에서 복사해 두세요.

목표

SOPS 와 age 로 쿠버네티스 Secret 매니페스트의 값만 암호화해 Git 에 두고, 서비스가 자기 키로 그것을 읽게 합니다. 함께 일하던 외주 개발자가 떠날 때 열쇠를 거두는 절차를 끝까지 해 봅니다.

왜 중요한가

비밀값을 Git 밖에 두면 배포 설정과 비밀값이 서로 다른 속도로 바뀌고, 결국 "이 버전에 맞는 비밀번호가 무엇이었나" 를 아무도 모르게 됩니다. SOPS 는 파일 구조와 키 이름은 그대로 두고 값만 암호화해서, 비밀값도 리뷰와 기록을 받게 합니다.

대신 새 질문이 생깁니다. 누가 읽을 수 있는가, 그리고 그 사람이 떠나면 무엇을 바꿔야 하는가. 수신자 목록에서 이름을 지우는 것만으로는 부족합니다. 떠난 사람은 옛 파일과 그 안의 데이터 키, 그리고 평문을 이미 봤을 수 있습니다.

단계

  1. 운영자 age 키 쌍을 /root/keys/ops.agekey·/root/keys/ops.pub 로 만듭니다.
  2. /root/deploy/.sops.yaml 에 경로·암호화 범위·수신자 셋을 적습니다.
  3. secrets/payapi.yaml 을 제자리에서 암호화합니다.
  4. 커밋하고, 평문이 기록 어디에도 없게 합니다.
  5. cfgapp 을 다시 띄워 서비스 키로 읽게 합니다.
  6. contractor 를 빼고 수신자를 갱신하고 데이터 키를 회전합니다.
  7. DB 비밀번호 자체를 바꾸고, 파일과 서비스에 반영해 커밋합니다.

참고

운영자 키를 만든다

age 키 쌍을 만들어 비밀 키를 /root/keys/ops.agekey(권한 600)에, 공개 키를 /root/keys/ops.pub 에 저장하세요. 서비스와 외주 개발자의 공개 키는 같은 디렉터리에 이미 있습니다.

age 의 키 생성 도구는 비밀 키 파일을 쓰면서 공개 키를 화면에 알려 줍니다. 비밀 키 파일에서 공개 키를 다시 뽑는 옵션도 있습니다.

무엇을 누구에게 암호화할지 적는다

/root/deploy/.sops.yaml 에 규칙 하나를 두세요. secrets/ 아래의 .yaml 파일에 적용되고(path_regex), data 와 stringData 아래의 값만 암호화하며(encrypted_regex), 수신자는 ops·cfgapp·contractor 세 공개 키입니다.

규칙은 creation_rules 목록의 한 항목입니다. 여러 age 공개 키는 쉼표로 이어 한 문자열로 적습니다. 값만 암호화하면 리뷰어가 무엇이 바뀌었는지 키 이름으로 볼 수 있습니다.

값만 암호화한다

/root/deploy/secrets/payapi.yaml 를 제자리에서 암호화하세요. stringData 의 값은 ENC[ 로 시작해야 하고, metadata.name 같은 다른 필드는 그대로 읽혀야 합니다.

규칙 파일은 sops 가 파일 경로를 보고 스스로 찾습니다. 제자리 암호화 옵션을 쓰면 평문 파일이 따로 남지 않습니다.

커밋하고 기록을 확인한다

규칙 파일과 암호화된 Secret 을 커밋하세요. 저장소의 어느 객체에도 평문 값이 없어야 합니다.

커밋하기 전에 git diff --cached 로 무엇이 올라가는지 보세요. 평문을 한 번이라도 커밋했다면 앞 실습에서 본 것처럼 기록에 남습니다.

서비스가 자기 키로 읽는다

cfgapp 서비스를 다시 띄워 암호화된 파일을 자기 키(/etc/cfgapp/age.key)로 읽게 하세요. http://127.0.0.1:8090/ 이 200 과 "ok": true 를 돌려줘야 합니다.

이 서비스는 기동할 때 한 번 복호화합니다. 수신자 목록에 서비스의 공개 키가 없으면 여기서 실패합니다.

떠난 사람의 열쇠를 거둔다

외주 계약이 끝났습니다. 먼저 contractor 키(/var/lib/labhub-isec/contractor.agekey)로 지금 파일이 열리는 것을 확인한 뒤, .sops.yaml 에서 contractor 를 빼고 파일의 수신자를 갱신하고 데이터 키까지 회전하세요. contractor 키로는 열리지 않고 ops·cfgapp 키로는 열려야 합니다.

수신자 갱신(updatekeys)은 데이터 키를 새 수신자에게 다시 봉할 뿐이라, 떠난 사람이 이미 꺼내 둔 데이터 키는 여전히 맞습니다. 값의 암호문을 새 데이터 키로 바꾸는 명령이 따로 있습니다.

값 자체를 바꾸고 다시 띄운다

떠난 사람은 평문을 이미 봤습니다. 새 DB 비밀번호를 만들어 cfgdb-passwd <새 값> 으로 DB 에 적용하고, 암호화된 파일의 stringData.db_password 를 같은 값으로 바꿔 커밋한 뒤 cfgapp 이 새 값으로 도는지 확인하세요.

암호화된 파일은 sops <파일> 로 편집기에서 열거나, 값 하나를 바꾸는 하위 명령(set)으로 고칩니다. 서비스는 기동할 때만 읽습니다. 커밋까지 해야 다음 배포가 같은 값을 씁니다.