iOS 프로젝트/개인 앱 - 일공이

git reset으로 APIKey 유출 되돌리기 - GitGuardian has detected the following Google API Key

Dev.Andy 2023. 11. 12. 17:14

머리말

급하게 날라온 Git 관련 이메일

Google API Key를 업로드

Git에서 feature 브랜치로 기능 구현을 마치고 GitHub로 git push를 진행한 직후 아래와 같은 이메일이 발송되었다.

GitGuardian has detected the following Google API Key 이메일 이미지
Google API Key가 유출되었다고 받은 이메일

😱😱😱

여태 잘 주의하다가 새롭게 기능을 추가하면서 API Key가 유출되는(!) 문제가 발생했다. 구글에서 제공한 Info.plist에 API Key가 있는 줄은... 꿈에도 몰랐다

순간 식은 땀이 흐르면서 막막함이 들었지만 원인을 분석해서 차례차례 해결해나갔다 🔥

GitHub Repository의 Private 전환 & 문제의 git log 찾기

1) GitHub repository를 "Private"으로 전환하기

일단 해당 Repository가 Public으로 공개된 상태라면 곧바로 비공개 상태로 변경해야 한다.

1-1) (Repository Page) > Settings > General

곧바로 Repository 페이지로 들어가 Settings를 클릭 후  스크롤 다운 ⬇

1-2) Danger Zone > Change repository visibility

맨아래로 스크롤 하면 Danger Zone에 Change visibility를 눌러 Private으로 전환한다

2) git log로 문제의 커밋 확인하기

2-1) git log 명령어에 3가지 옵션을 붙여 다른 branch와 확인하기

git log --oneline --graph --all

위와 같은 명령어를 입력하면 아래와 같이 결과가 나올 것이다. 문제의 commit이 어디부터 시작인지 분석해보자.

  • git log 옵션의 의미
    • oneline 긴 로그 설명을 한 줄만 보여주도록 함
    • graph 그래프 형식으로 보여준다
    • all 모든 브랜치를 다 보여주기
* bbbbbbb (HEAD -> feature/push-notification, origin/feature/push-notification) feat: Firebase Messaging을 이용한 알림 기능 구현 
및 테스트  성공
* aaaaaaa chore: Firebase SDK 설치
* 0729903 feat: Apple Push Notification 기능 구현
* 25c4159 docs: 앱 관련 파일 위치 이동 및 빌드 설정
* 6034082 (tag: 1.1.1, origin/main, origin/develop, origin/HEAD, main, develop) Merge branch 'release-1.1.1'

필자 같은 경우는 "aaaaaaa"의 commit부터 잘못 되었다.

 

문제의 git log를 다루는 3가지 방법

(2023-11-17 업데이트)

개요

이제 문제의 git log를 다뤄야 하는데, 방법은 크게 3가지 방법이 있고, 각각의 단점이 있다.

  1. git revert
  2. git rebase -i & edit
  3. git reset
명령어 정의 및 특징 단점
`git revert` - 과거의 커밋을 현재로 끌어올리는 "재설정"
- 팀플에 적합 (과거의 커밋 히스토리가 그대로 남는다)
- revert를 한 히스토리가 남는다.
- 병합(merge)이기 때문에 돌아가려는 과거와 현재의 충돌(conflict)을 일일이 손봐야 한다.
`git rebase -i` & edit
(interactive rebase)
- 현재 브랜치에 있는 커밋을 가공하여 커밋의 "복제본"으로 대체
- squash, reword, edit 등이 있는데 이중에 특정 커밋의 파일 상태를 변경하는 edit을 이용하면 그 커밋의 파일 상태를 변경할 수 있다
- 팀플에 부적합 (커밋의 해시번호 변경)
- 복제본이기에 메시지가 동일하더라도, 커밋의 해시 번호(hash number)가 뒤바뀐다
`git reset` - 실제 과거의 커밋으로 되돌아가기(HEAD의 이동)
- 팀플에 부적합 (아예 새로운 커밋 생성)
- 새로운 커밋으로 기존을 덮어쓰는 것이기에 새로운 커밋이 생성
- 너무 멀리 떨어진 커밋을 수정하기에 부적합 (과거의 시점부터 새로운 커밋을 새로 만들어야 한다)

3) git reset으로 과거의 commit으로 되돌아가기

- 프로젝트 자체가 혼자였지만, 아니라 하더라도 main 브랜치가 아닌 혼자 진행하는 feature 브랜치이기에 마음 편히 git reset을 진행할 수 있었다.

📌 주의사항
- 문제가 발생한 커밋이 다른 사람과 같이 진행하는 branch라면, git revert나 interactive rebase 등으로 커밋을 변경할 경우 커밋의 해시 번호가 바뀌기 때문에 팀원의 양해를 구하고 진행해야 할 것이다. (*)
- 또한 필자는 문제의 커밋을 발견한 지점이 HEAD와 멀지 않았기에 git reset을 사용했다.

3-1) git reset에 soft 옵션으로 staged 상태는 남기기

# 방법 1. 커밋의 해시 넘버로 돌아가기
git reset --soft <commit hash number>

# 방법 2. 현재 HEAD를 기준으로 인덱스 번호로 돌아가기
# - 가장 최근 커밋은 HEAD^
# - HEAD~ 이후에 붙는 숫자 n은 HEAD로부터 n만큼 떨어져 있다.
git reset --soft HEAD~2

# 방법 3. HEAD 대신 @ 이용하기
git reset --soft @~2

(2023-11-13 월 업데이트)

그냥 git reset를 하게 되면 기본값인 `--mixed`가 적용되어 staged 상태가 저장되지 않은 채 해당 커밋으로 되돌아간다 일일이 git add 하는 게 귀찮다. 따라서 `--soft`로 일단 staged 상태를 유지해서 필요한 부분만 적용하는 게 좋다.

git reset --soft 0729903

`aaaaaaa`가 발생했으니 그 직전 커밋인 `0729903`으로 되돌아간다.

4)  문제의 파일을 unstaged로 변경 및 gitignore에 파일 추가

4-1) `git reset HEAD <file>`로 해당 문제의 파일 unstaged 하기

`--soft` 옵션으로 커밋의 staged 기록이 남아 있으니 문제의 파일을 unstaged로 바꾼다.

git reset HEAD (프로젝트)/.../GoogleService-Info.plist

4-2) 커밋에 부적절한 파일 unstaged (선택)

만약 되돌아간 커밋에서 추가로 커밋할 내용이 원래의 커밋 내용과 벗어난 파일이 있을 수 있다.

필자의 경우에는 단순히 Firebase와 관련된 패키지 설치가 주된 내용이었기에, 그 외에 상관없는 파일은 모두 unstaged 했다.

그냥 문제의 파일만 반영하고 싶다면 이 단계를 생략해도 된다.

# 예시
git reset HEAD (프로젝트)/.../AppDelegate.swift

4-3) `.gitignore` 파일에 staged 하지 말아야 할 파일을 추가

이제 수정해야하는 부분을 수정한다. 필자 같은 경우에는 `.gitignore`가 문제이니 이를 반영한다.

# .gitignore
# 아래 내용 추가
GoogleService-Info.plist

4-4) 수정한 `.gitignore` 파일 staged

이제 `.gitignore`에 반영해서 업데이트 한다.

5) 해당 파일 수정 및 차례차례 commit 하기

📌 "4-3"의 경우를 거쳤을 경우에만 해당

git commit -m "커밋 내용"

4-3 단계를 거쳤다면 이제 다시 문제의 커밋 이후에, 작성한 커밋이 또 있다면 계속해서 커밋을 진행한다. staged/unstaged은 본인의 판단하에 진행하면 된다.

6) 해당 브랜치를 강제 푸쉬하기

git push origin +(브랜치 이름)

이미 GitHub에는 문제의 커밋이 반영되어 있기에 해당 브랜치의 내용을 강제로 덮어씌어야 한다.

아래 같이 크게 3가지 방법이 있는데, 편한 걸 이용하면 된다. (필자는 주로 +를 자주 쓴다)

# 방법 1
git push origin +feature/push-notification

# 방법 2
git push -f origin feature/push-notification

# 방법 3
git push --force origin feature/push-notification

꼬리말

완성 결과

다행히 git을 제외한 새로운 커밋으로 만들었고 이를 강제로 덮어 씌웠다 :)

* dc65056 (HEAD -> feature/push-notification, origin/feature/push-notification) feat: Firebase Messaging을 이용한 알림 기능 구현 
및 테스트  성공
* 0366771 chore: Firebase SDK 설치
* 0729903 feat: Apple Push Notification 기능 구현
* 25c4159 docs: 앱 관련 파일 위치 이동 및 빌드 설정
* 6034082 (tag: 1.1.1, origin/main, origin/develop, origin/HEAD, main, develop) Merge branch 'release-1.1.1'

해당 GitHub Pull Requests

아래에도 잘 반영이 되어 이제 APIKey가 보이지 않는다

사이트

Push Notifications (서버 알림) 기능 구현 #61