인수인계 자료를 정리하다가 Android 릴리스 서명키의 소재를 확인해야 했다. 서명키를 분실하면 스토어 앱 업데이트가 영구히 불가능해지므로 인계 목록에서 우선순위가 높은 항목이다. CI를 보니 몇 달째 서명 빌드가 정상적으로 돌고 있었다.
Table of contents
Open Table of contents
사본과 원본의 구분
CI 설정을 열어 보니 조직 시크릿에 인코딩된 사본이 들어 있고 빌드할 때 디코드해서 서명하고 지우는 구조였다.
- run: echo "$RELEASE_KEYSTORE" | base64 -d > release.keystore
- run: jarsigner -keystore release.keystore -storepass "$STOREPASS" ...
- run: rm -f release.keystore
그런데 이 시크릿은 값을 넣을 수는 있고 되읽을 수는 없다. CI 안에서 환경변수로 주입될 뿐 콘솔에서도 API로도 조회가 안 된다. 빌드는 되고 인계는 안 되는 상태이며 동작한다는 것과 보유한다는 것이 여기서 갈린다.
있을 법한 곳의 전수 확인
원본 파일이 어디 있는지 찾았다. 첫 가설은 빌드 서버였는데 흔한 경로를 보고 없어서 루트부터 통째로 훑었다. 확장자와 프로젝트 이름과 소스 디렉터리를 전부 조건에 넣었는데 0건이었다.
여기서 이유가 드러났다. 그 서버에는 Android 저장소 자체가 받아져 있지 않았다. 받아져 있는 것은 백엔드 저장소 여섯 개뿐이었으므로 애초에 있을 수 없는 곳을 뒤진 것이다.
로컬 클론을 미커밋 파일까지 봤고 시크릿 매니저 항목 13개를 전부 확인했지만 없었다. 후보를 하나씩 지우고 남은 것이 조직 시크릿의 읽을 수 없는 사본과 담당자 개인 로컬의 원본 둘이었다.
탐색 종료의 판단
이 지점에서 판단이 갈린다. 백업 서버와 옛 이메일 첨부와 다른 사람 장비까지 더 뒤질 수도 있었다. 그러지 않고 탐색 종료를 선언하고 인계 항목으로 올렸다.
[인계 필수] Android 릴리스 서명키
- 원본 keystore 파일 / keypass / storepass / alias
- 조직 인프라 어디에도 원본이 없음. 시크릿에는 되읽기 불가한 사본만 존재
- 확인 완료: 빌드 서버 전체 스캔 0건 / 로컬 클론 0건 / 시크릿 매니저 13항목 0건
없는 것을 계속 찾는 것도 회피의 한 형태다. 어디에 없는지를 실측으로 확정하는 것이 그 시점의 결과물이고 그다음은 사람에게 받는 것이다.
write-only 자산의 목록
이 건을 계기로 같은 성질의 것들을 훑었다. 넣을 수는 있고 읽을 수는 없는 자산들이다. CI 시크릿 대부분이 그렇고 클라우드 액세스 키의 비밀 부분은 발급할 때 한 번만 보이며 일부 콘솔의 클라이언트 시크릿은 재조회가 안 되고 서명키와 인증서의 비밀키도 마찬가지다.
공통점은 지금 잘 돌아간다는 사실이 우리가 갖고 있다는 것을 보증하지 않는다는 점이다. 돌아가는 이유는 과거 어느 시점에 누가 넣었기 때문이고 그 사람과 그 원본이 지금도 접근 가능한지는 별개 사실이다.
재생성 가능성으로 하는 점검
이런 항목은 동작 확인이 아니라 재생성 가능성으로 점검하기로 했다. 지금 이 값을 처음부터 다시 만들어 낼 수 있는지 묻고 못 만들면 원본 소재를 확정한다. 원본이 조직이 관리하는 곳에 있는지 보고 개인 장비에 있으면 인계 항목으로 올린다.
마지막으로 분실하면 무슨 일이 나는지를 본다. 이것이 우선순위를 정한다. API 키는 재발급하면 되지만 앱 서명키는 안 된다.
정리
- CI가 서명 빌드를 성공시킨다고 조직이 원본 키를 가진 것이 아니다
- 되읽을 수 없는 시크릿은 빌드에 쓰이고 인계에는 못 쓴다
- 원본 소재는 추론이 아니라 실측으로 확정한다
- 뒤지기 전에 그 저장소가 그 서버에 있기는 한지부터 본다
- 후보를 다 지웠으면 탐색 종료를 선언하고 인계 항목으로 넘긴다
- 없는 것을 계속 찾는 것도 회피의 한 형태다
- 자산 점검은 동작 확인이 아니라 재생성 가능성으로 한다
- 분실 시 영구 불가한 것과 재발급 가능한 것을 구분해 우선순위를 정한다