
예전에, 친구가 운영하던 1인 앱 프로젝트의 업로드 키스토어(upload keystore) 가 노트북 SSD 사망과 함께 통째로 날아간 적이 있어요. 그때 제가 옆에서 같이 복구 절차를 밟았는데, 새벽에 깃허브 단톡방에 "키 날아갔다 어떡하지" 메시지가 올라왔던 게 아직도 생생하네요.
다행히 플레이 앱 사이닝(Play App Signing) 에 가입돼 있었고, 업로드 키 재설정 신청을 넣어 2~3 영업일 만에 다시 배포 라인을 살릴 수 있었습니다. 그 한 주 동안 굴려본 절차와, 같은 사고를 안 겪게 보관 체계를 다시 짠 기록을 남겨둡니다.
재설정이 가능해진 건 분명 다행이지만, 그걸 평소 운영의 기본값으로 잡으면 안 된다는 쪽으로 정리됐어요. 보관을 단단히 해두는 게 여전히 출발점이라고 봅니다.
업로드 키와 앱 서명 키, 구조부터 한 번 정리
플레이 앱 사이닝이 들어오면서 키가 두 갈래로 나뉘었습니다. 개발자 손에 남는 업로드 키(upload key) 와, 구글이 금고에 보관하는 앱 서명 키(app signing key) 두 종류예요.
업로드 키는 개발자가 .aab 파일에 서명할 때 쓰는 키입니다. 구글 콘솔에 올라온 빌드의 업로드 키 서명을 검증한 다음, 구글이 들고 있는 앱 서명 키로 다시 서명해 사용자에게 배포하는 흐름이지요.
옛날 방식은 앱 서명 키가 곧 업로드 키였습니다. 그래서 키스토어(keystore) 를 잃어버리면 같은 패키지명으로는 영영 업데이트를 못 올리는 사고가 났었어요. 지금은 업로드 키가 날아가도 구글에 재설정 요청을 넣을 수 있다는 점이 가장 큰 변화로 알려져 있습니다.
다만 2021년 8월 이후 신규 앱은 플레이 앱 사이닝이 의무이고, 그 이전에 옛 방식으로 올라간 앱은 여전히 한 벌짜리 키 구조라 분실 시 복구 경로가 닫혀 있는 경우가 많아요. 본인 앱이 어느 쪽인지부터 콘솔에서 확인해 두시는 게 좋겠습니다.

앱 서명 키 재설정 신청, 실제 절차와 영업일
업로드 키 재설정은 콘솔 → 테스트 및 출시 > 앱 무결성 > 앱 서명 메뉴에서 신청합니다. 새로 만든 키스토어의 PEM 파일 업로드 양식이 따로 있어요.
신청 후에는 보통 2~ 3 영업일이 걸리는 것으로 알려져 있습니다. 2~3 영업일이 어느 정도냐면, 월요일 오전에 넣었을 때 빨라야 수요일 오후, 늦으면 그 다음 주 월요일에야 새 업로드 키로 빌드를 올릴 수 있다는 얘기입니다. 그동안은 기존 사용자 대상 업데이트가 통째로 막혀요.
승인 후에는 새 업로드 키로 서명한 첫 .aab 부터 통과되고, 기존 업로드 키 서명은 거절됩니다. 깃허브 액션(GitHub Actions) 워크플로우의 시크릿도 같이 갈아끼워야 자동 배포가 안 멈춥니다.
복구 자체는 다행히 매끄러웠는데, 사람이 깨어있어야 하는 시간 2~3일 분이 통째로 묶인다는 게 진짜 비용이더라고요. 이 사이에 핫픽스가 필요한 크래시가 터지면 손쓸 방법이 거의 없는 상황이 됩니다.
키스토어 보관, 1Password 와 깃허브 액션 Secrets 운영
같은 사고를 안 겪게 그날 이후로 보관 체계를 세 갈래로 재정비했습니다.
1. 비밀번호 관리자에 파일과 비밀번호를 분리 보관
키스토어 파일과 비밀번호를 한 줄에 같이 적어두면 사고가 났을 때 한 번에 털리는 구조거든요. 1패스워드(1Password) 나 비트워든(Bitwarden) 같은 도구에서 파일 첨부 필드와 비밀번호 필드를 따로 둬야 합니다. 한쪽이 새도 다른 쪽이 살아남는 구조가 출발점이에요.
2. 1인 개발자라면 최소 3중 백업
비밀번호 관리자 본채 + 클라우드 백업 + 외장 SSD 한 벌이 기본선입니다. 팀 단위라면 책임자 2인 이상이 같이 접근할 수 있는 공유 저장소에 둬야 퇴사·휴직 같은 인적 사고에 안 흔들립니다. 한 사람 손에만 키가 있는 구조는 그 사람이 자리를 비우는 순간 그대로 사고로 이어질 수 있어요.
3. CI/CD 는 base64 인코딩 후 시크릿 저장
키스토어를 base64 로 인코딩해 깃허브 액션 Secrets 같은 보안 저장소에 등록하고, 워크플로우 안에서 임시 파일로만 풀어 쓰는 식입니다. 평문 키스토어를 레포에 올리는 일은 절대 없어야 합니다.
base64 인코딩을 쉽게 설명하자면, 바이너리 파일을 텍스트로 길게 풀어쓴 형태라고 보시면 됩니다. 깃허브 시크릿 같은 텍스트 기반 저장소에 그대로 붙여넣을 수 있게 변환하는 작업이에요.
인코딩 자체는 한 줄로 끝납니다.
base64 -w 0 upload-keystore.jks > upload-keystore.jks.b64
이 결과물을 UPLOAD_KEYSTORE_BASE64 같은 시크릿으로 등록하고, 워크플로우에서 디코딩한 다음 서명 시점에만 임시 파일로 풀어 쓰면 됩니다. 비밀번호는 UPLOAD_KEYSTORE_PASSWORD 같은 별도 시크릿으로 분리해야 한 군데가 새도 둘이 같이 안 새는 구조예요.
참고로 저는 1패스워드의 문서 첨부 항목에 키스토어 원본을, 별도 항목에 비밀번호를 보관하고 있어요. 같은 키스토어의 base64 사본은 깃허브 시크릿으로도 등록해 두구요. 원본 한 벌이 사라져도 시크릿에서 복구할 수 있게 이중 안전망을 만들어두는 쪽으로 잡았습니다.

플레이 앱 사이닝의 한계, 멀티 마켓과 긴급 대응
마지막으로 짚어둘 한계가 두 가지 있어요.
하나는 멀티 마켓. 플레이 앱 사이닝의 앱 서명 키는 구글이 들고 있기 때문에, 원스토어나 갤럭시 스토어 같은 다른 마켓에 동일 서명으로 올리는 건 불가능합니다. 멀티 마켓 배포를 하려면 처음부터 마켓별 별도 키스토어와 별도 배포 라인을 잡아야 한다는 얘기지요.
다른 하나는 긴급 대응. 키가 유출됐다고 판단해 재설정을 걸어도 2~3 영업일 동안은 손이 묶입니다. 그 시간 안에 사고 범위가 커질 수 있다는 점은 분명한 약점이네요.
그래서 두 갈래로 운영을 갈라뒀습니다. 평소엔 보관을 단단히 해서 재설정 신청 자체를 0회로 가져가는 게 본선이고, 재설정은 "최악의 사고가 났을 때 그래도 살아남는다"는 보험으로만 둡니다. 둘 다 챙기되 무게는 전자에 싣는 거예요.
두 갈래 중에 저는 분명히 전자 쪽에 손을 듭니다. "업로드 키 = 끝장"이라는 옛 공포는 신규 앱에선 옛말이 된 게 맞지만, 재설정 카드는 2~3 영업일짜리 배포 정지와 멀티 마켓 제약이 따라붙는 비싼 카드라, 가능하면 끝까지 안 꺼내는 쪽이 1인 개발자에겐 훨씬 남는 장사라고 봅니다.

'Android 개발 > 트러블슈팅' 카테고리의 다른 글
| Room 느린 쿼리, Database Inspector로 풀스캔 잡은 기록 (1) | 2026.07.23 |
|---|---|
| Hilt vs Koin 마이그레이션, 6년차가 둘 다 깔아본 뒤 안 갈아탄 이유 (0) | 2026.07.08 |
| 로컬 초록불, CI 빨간불 — Flaky 테스트 격리로 5주 만에 18.3%→2.1% 잡은 기록 (0) | 2026.07.03 |
| 안드로이드 ANR 해결, Play Console '메인 5초' 리포트만 보고 범인 찾은 자리 (0) | 2026.07.02 |
| Play가 16KB 페이지 크기를 요구합니다 — 네이티브 라이브러리 안 깨지게 맞춘 자리 (0) | 2026.07.01 |