Skip to main content

Removing sensitive data from a repository(리포지토리에서 중요한 데이터 제거)

민감한 데이터를 Git 리포지토리에 커밋한 경우 기록에서 해당 데이터를 제거할 수 있습니다.

리포지토리에서 중요한 데이터 제거 정보

git filter-repo 같은 도구 또는 BFG 리포지토리 클리너를 사용하여 리포지토리의 기록을 변경할 때는, 특히 열린 끌어오기 요청 및 중요한 데이터와 관련된 의미를 이해하는 것이 중요합니다.

git filter-repo 도구와 BFG Repo-Cleaner는 리포지토리의 기록을 다시 씁니다. 이로 인해 사용자가 변경하는 기존 커밋과 거기에 종속된 커밋의 SHA가 변경됩니다. 변경된 커밋 SHA는 리포지토리에서 열려 있는 끌어오기 요청에 영향을 줄 수 있습니다. 리포지토리에서 파일을 제거하기 전에 모든 열려 있는 끌어오기 요청을 병합하거나 닫는 것이 좋습니다.

git rm을 사용하면 마지막 커밋에서 파일을 제거할 수 있습니다. 최신 커밋으로 추가된 파일을 제거하는 방법에 대한 자세한 내용은 "GitHub의 대용량 파일 정보" 항목을 참조하세요.

중요한 데이터 노출 정보

이 문서에서는 GitHub Enterprise Server 인스턴스의 리포지토리에 있는 분기 또는 태그에서 중요한 데이터에 연결할 수 없도록 커밋하는 방법에 대해 설명합니다. 그러나 이러한 커밋은 다른 곳에서도 계속 액세스할 수 있습니다.

  • 리포지토리의 모든 클론 또는 포크에서
  • GitHub Enterprise Server의 캐시된 뷰에서 SHA-1 해시를 통해 직접
  • 이를 참조하는 끌어오기 요청을 통해

다른 사용자의 클론 또는 리포지토리 포크에서 중요한 데이터를 제거할 수는 없지만 사이트 관리자에게 문의.에 문의하여 GitHub Enterprise Server에 대한 끌어오기 요청에서 캐시된 뷰 및 중요한 데이터에 대한 참조를 제거할 수 있습니다.

GitHub Enterprise Server에 커밋을 푸시했으면 중요한 커밋 데이터의 손상을 고려해야 합니다. 암호를 커밋한 경우 암호를 변경해야 합니다. 키를 커밋한 경우 새 키를 생성하세요.

중요한 데이터를 도입한 커밋이 모든 포크에 있는 경우 계속 액세스할 수 있습니다. 포크 소유자와 조정하여 중요한 데이터를 제거하거나 포크를 완전히 삭제하도록 요청해야 합니다.

리포지토리의 기록을 다시 작성하기로 결정할 때 이러한 제한 사항을 고려하세요.

리포지토리의 기록에서 파일 제거

git filter-repo 도구 또는 BFG Repo-Cleaner 오픈 소스 도구를 사용하여 리포지토리의 기록에서 파일을 제거할 수 있습니다.

Note

중요한 데이터가 이진 파일로 식별된 파일에 있는 경우, 데이터를 제거하거나 바꾸기 위해 그 파일을 수정할 수 없으므로, 기록에서 파일을 제거해야 합니다.

BFG 사용

BFG Repo-Cleaner는 오픈 소스 커뮤니티에서 빌드하고 유지 관리하는 도구입니다. 원치 않는 데이터를 더 빠르고 간단하게 제거하기 위해 git filter-repo에 대한 대안을 제공합니다.

예를 들어, 중요한 데이터를 포함하는 파일을 제거하고 최근 커밋을 그대로 두려면 다음을 실행합니다.

bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

리포지토리의 기록에서 passwords.txt에 나열된 모든 텍스트를 바꾸려면 다음을 실행합니다.

bfg --replace-text passwords.txt

중요한 데이터가 제거된 후에는 변경 내용을 GitHub Enterprise Server로 강제 푸시해야 합니다. 강제 푸시하면 리포지토리 기록이 다시 작성되어 커밋 기록에서 중요한 데이터가 제거됩니다. 강제 푸시하는 경우 다른 사용자가 작업을 기반으로 한 커밋을 덮어쓸 수 있습니다.

git push --force

자세한 사용법과 다운로드 지침은 BFG Repo-Cleaner 설명서를 참조하세요.

git filter-repo 사용

Warning

변경 내용을 스태시한 후에 git filter-repo를 실행할 경우 다른 스태시 명령을 사용하여 변경 내용을 가져올 수 없습니다. git filter-repo를 실행하기 전에, 적용한 모든 변경 내용을 스태시 해제하는 것이 좋습니다. 스태시한 마지막 변경 내용 세트를 스태시 해제하려면 git stash show -p | git apply -R을 실행합니다. 자세한 내용은 Git 도구 - 스태시 및 정리를 참조하세요.

git filter-repo가 작동하는 방식을 설명하기 위해, 리포지토리 기록에서 중요한 데이터를 포함하는 파일을 제거한 다음 실수로 다시 커밋되지 않도록 .gitignore에 추가하는 방법을 보여 드리겠습니다.

  1. git filter-repo 도구의 최신 릴리스를 설치합니다. git-filter-repo는 수동으로 설치하거나 패키지 관리자를 사용하여 설치할 수도 있습니다. 예를 들어, HomeBrew를 사용하여 도구를 설치하려면 brew install 명령을 사용하세요.

    brew install git-filter-repo
    

    자세한 내용은 newren/git-filter-repo 리포지토리의 INSTALL.md를 참조하세요.

  2. 기록에 중요한 데이터가 포함된 리포지토리의 로컬 복사본이 아직 없다면 로컬 컴퓨터에 리포지토리를 복제합니다.

    $ git clone https://HOSTNAME/YOUR-USERNAME/YOUR-REPOSITORY
    > Initialized empty Git repository in /Users/YOUR-FILE-PATH/YOUR-REPOSITORY/.git/
    > remote: Counting objects: 1301, done.
    > remote: Compressing objects: 100% (769/769), done.
    > remote: Total 1301 (delta 724), reused 910 (delta 522)
    > Receiving objects: 100% (1301/1301), 164.39 KiB, done.
    > Resolving deltas: 100% (724/724), done.
    
  3. 리포지토리의 작업 디렉터리로 이동합니다.

    cd YOUR-REPOSITORY
    
  4. 아래의 명령에서 PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA(파일 이름이 아닌) 제거할 파일의 경로로 바꾸어서 실행합니다. 이 인수를 사용하면 다음과 같은 작업이 수행됩니다.

    • Git이 모든 분기와 태그의 전체 기록을 강제로 처리합니다(체크아웃하지 않음).

    • 지정된 파일과 그 결과로 생성된 빈 커밋을 제거합니다.

    • .git/config 파일에 저장된 일부 구성(예: 원격 URL)을 제거합니다. 이 파일은 나중에 복원할 수 있도록 미리 백업해두는 것이 좋습니다.

    • 기존 태그 덮어쓰기

        $ git filter-repo --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA
        Parsed 197 commits
        New history written in 0.11 seconds; now repacking/cleaning...
        Repacking your repo and cleaning out old unneeded objects
        Enumerating objects: 210, done.
        Counting objects: 100% (210/210), done.
        Delta compression using up to 12 threads
        Compressing objects: 100% (127/127), done.
        Writing objects: 100% (210/210), done.
        Building bitmaps: 100% (48/48), done.
        Total 210 (delta 98), reused 144 (delta 75), pack-reused 0
        Completely finished after 0.64 seconds.
      

      Important

      중요한 데이터를 포함하는 파일이 이동되었거나 이름이 바뀌어서 다른 경로에 있다면 변경된 경로에 대해서도 이 명령을 실행해야 합니다.

  5. 중요한 데이터를 포함하는 파일을 실수로 다시 커밋하지 않도록 .gitignore에 추가합니다.

    $ echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore
    $ git add .gitignore
    $ git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore"
    > [main 051452f] Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore
    >  1 files changed, 1 insertions(+), 0 deletions(-)
    
  6. 리포지토리의 기록에서 제거하려는 모든 항목을 제거했고 모든 분기가 체크아웃되었는지 재차 확인합니다.

  7. git filter-repo 도구는 구성된 원격을 자동으로 제거합니다. git remote set-url 명령을 사용하여 원격을 복원합니다. 여기서 OWNERREPO를 리포지토리 세부 정보로 바꿉니다. 자세한 내용은 "원격 리포지토리 관리"을(를) 참조하세요.

    git remote add origin https://github.com/OWNER/REPOSITORY.git
    
  8. 리포지토리의 상태에 만족하고 적절한 원격을 설정했다면 로컬 변경 내용을 강제로 푸시하여 푸시한 모든 분기 및 GitHub Enterprise Server 인스턴스에 리포지토리를 덮어쓰세요. 커밋 기록에서 중요한 데이터를 제거하려면 강제 푸시가 필요합니다.

    $ git push origin --force --all
    > Counting objects: 1074, done.
    > Delta compression using 2 threads.
    > Compressing objects: 100% (677/677), done.
    > Writing objects: 100% (1058/1058), 148.85 KiB, done.
    > Total 1058 (delta 590), reused 602 (delta 378)
    > To https://HOSTNAME/YOUR-USERNAME/YOUR-REPOSITORY.git
    >  + 48dc599...051452f main -> main (forced update)
    
  9. 태그된 릴리스에서 중요한 파일을 제거하려면 Git 태그에 대해서도 강제로 푸시해야 합니다.

    $ git push origin --force --tags
    > Counting objects: 321, done.
    > Delta compression using up to 8 threads.
    > Compressing objects: 100% (166/166), done.
    > Writing objects: 100% (321/321), 331.74 KiB | 0 bytes/s, done.
    > Total 321 (delta 124), reused 269 (delta 108)
    > To https://HOSTNAME/YOUR-USERNAME/YOUR-REPOSITORY.git
    >  + 48dc599...051452f main -> main (forced update)
    

GitHub에서 데이터 완전히 제거

BFG 도구를 사용하거나 git filter-repo를 사용하여 중요한 데이터를 제거하고 변경 내용을 GitHub Enterprise Server에 푸시한 후에는 GitHub Enterprise Server에서 데이터를 완전히 제거하려면 몇 가지 단계를 더 수행해야 합니다.

  1. 사이트 관리자에게 문의에 문의하여 GitHub Enterprise Server에 대한 끌어오기 요청에서 캐시된 뷰 및 중요한 데이터에 대한 참조를 제거하도록 요청합니다. 리포지토리의 이름 및/또는 제거해야 하는 커밋에 대한 링크를 제공하세요. 사이트 관리자가 연결할 수 없는 Git 개체를 제거하는 방법에 대한 자세한 내용은 "명령줄 유틸리티" 항목을 참조하세요. 사이트 관리자가 도달 가능한 커밋을 식별하는 방법에 대한 자세한 내용은 "도달 가능한 커밋 식별하기"를 참조하세요.

  2. 협력자에게 이전(오염된) 리포지토리 기록에서 만든 분기를 병합하지 ‘않고’ 다시 지정하도록 지시합니다.__ 하나의 병합 커밋은 방금 제거했던 오염된 기록의 일부 또는 전부를 다시 도입할 수 있습니다.

  3. git filter-repo를 사용한 경우 이 단계를 건너뛸 수 있습니다.

    BFG 도구를 사용한 경우 다시 작성한 후 로컬 리포지토리의 참조를 이전 기록에 대한 참조 항목을 정리하여 역참조하고 다음 명령을 사용하여 가비지 수집할 수 있습니다(Git 1.8.5 이상 사용).

    $ git reflog expire --expire=now --all
    $ git gc --prune=now
    > Counting objects: 2437, done.
    > Delta compression using up to 4 threads.
    > Compressing objects: 100% (1378/1378), done.
    > Writing objects: 100% (2437/2437), done.
    > Total 2437 (delta 1461), reused 1802 (delta 1048)
    

    Note

    필터링된 기록을 새 리포지토리 또는 빈 리포지토리로 푸시한 다음 GitHub Enterprise Server에서 새로 복제하여 이를 수행할 수도 있습니다.

연결할 수 있는 커밋 식별

리포지토리에서 원치 않거나 민감한 데이터를 완전히 제거하려면 데이터를 처음 도입한 커밋이 분기, 태그, 당겨받기 요청 및 포크에서 완전히 참조되지 않도록 해야 합니다. 어디서든 단일 참조가 있으면 가비지 컬렉션이 데이터를 완전히 제거하지 못합니다.

SSH를 통해 어플라이언스에 연결할 때 다음 명령을 사용하여 기존 참조를 확인할 수 있습니다. 민감한 데이터를 처음 도입한 커밋의 SHA가 필요합니다.

ghe-repo OWNER/REPOSITORY -c 'git ref-contains COMMIT_SHA_NUMBER'
ghe-repo OWNER/REPOSITORY -c 'cd ../network.git && git ref-contains COMMIT_SHA_NUMBER'

이러한 명령 중 하나라도 결과를 반환하면 커밋이 성공적으로 가비지 컬렉션되기 전에 해당 참조를 제거해야 합니다. 두 번째 명령은 리포지토리의 포크에 존재하는 참조를 식별합니다(리포지토리에 포크가 없는 경우 실행을 건너뛸 수 있음).

  • refs/heads/ 또는 refs/tags/(으)로 시작하는 결과는 각각 문제가 있는 커밋에 대한 참조가 여전히 포함된 분기 및 태그를 나타내며, 수정된 리포지토리에서 커밋이 완전히 정리되지 않았거나 강제 푸시되지 않았음을 의미합니다.
  • refs/pull/ 또는 refs/__gh__/pull(으)로 시작하는 결과는 문제가 있는 커밋을 참조하는 당겨받기 요청을 나타냅니다. 커밋이 가비지 컬렉션되도록 허용하려면 이러한 당겨받기 요청을 삭제해야 합니다. 사이트 관리자 대시보드의 https://HOSTNAME/stafftools/repositories/OWNER/REPOSITORY/PULL_REQUESTS/<PULL-REQUEST-NUMBER>서 당겨받기 요청을 삭제할 수 있으며, 풀 리퀘스트 번호를 <PULL-REQUEST-NUMBER>(으)로 바꿀 수 있습니다.

어떤 포크에서든 참조가 발견되면 결과는 비슷하게 보이지만 refs/remotes/NWO/(으)로 시작됩니다. 이름으로 포크를 식별하려면 다음 명령을 실행하면 됩니다.

ghe-nwo NWO

리포지토리의 포크에서 민감한 데이터를 제거하려면 BFG 도구 또는 git filter-repo을(를) 사용하는 동일한 절차를 사용할 수 있습니다. 또는 포크를 모두 삭제할 수 있으며 필요한 경우 루트 리포지토리 정리가 완료되면 리포지토리를 다시 포크할 수 있습니다.

커밋의 참조를 제거한 후 명령을 다시 실행하여 다시 확인합니다.

ref-contains 명령 중 하나에서 결과가 없는 경우 다음 명령을 실행하여 --prune 플래그를 사용하여 가비지 컬렉션을 실행하여 참조되지 않은 커밋을 제거할 수 있습니다.

ghe-repo-gc -v --prune OWNER/REPOSITORY

가비지 컬렉션으로 커밋이 성공적으로 제거되면 https://HOSTNAME/stafftools/repositories/OWNER/REPOSITORY에서 리포지토리의 사이트 관리자 대시보드로 이동하여 네트워크를 선택한 다음 Git 캐시 무효화를 클릭하여 캐시된 데이터를 제거할 수 있습니다.

향후 실수로 인한 커밋 방지

기여자가 실수로 커밋하지 못하게 하면 중요한 정보가 노출되지 않도록 방지할 수 있습니다. 자세한 내용은 "조직에서 데이터 유출을 방지하기 위한 모범 사례" 항목을 참조하세요.

커밋하지 않으려는 항목을 커밋하지 않도록 하는 몇 가지 간단한 트릭이 있습니다.

  • GitHub Desktop 또는 gitk와 같은 시각적 프로그램을 사용하여 변경 내용을 커밋합니다. 시각적 프로그램을 사용하면 일반적으로 각 커밋을 통해 추가, 삭제 및 수정할 파일을 정확하고 쉽게 확인할 수 있습니다.
  • 대신 catch-all 명령 git add .와 명령줄의 git commit -a을 사용하지 말고 git add filenamegit rm filename을 사용하여 파일을 개별적으로 스테이징하세요.
  • 각 파일 내에서 변경 내용을 개별적으로 검토하고 스테이징하는 데 git add --interactive를 사용합니다.
  • 커밋을 위해 스테이징한 변경 내용을 검토하는 데 git diff --cached를 사용합니다. -a 플래그를 사용하지 않는 한 git commit에서 생성되는 정확한 차이입니다.
  • 리포지토리에 대한 푸시 보호를 사용하도록 설정하여 하드 코딩된 비밀이 포함된 푸시가 코드베이스에 커밋되지 않도록 탐지하고 방지합니다. 자세한 내용은 "푸시 보호 정보"을(를) 참조하세요.

추가 참고 자료