GitHub 리포지토리를 Amazon S3에 백업하기 (아무도 경고하지 않는 것)

발행: (2026년 1월 13일 오후 11:05 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

왜 GitHub 저장소를 백업해야 할까요?

GitHub은 여러분이 소중히 여기는 작업에 대한 단일 장애 지점이 될 수 있습니다. 삭제된 저장소, 잠긴 계정, 혹은 강제 푸시가 모든 것을 사라지게 할 수 있습니다. 플랫폼 외부의 자동 백업이 이 문제를 해결합니다.

왜 Amazon S3인가?

  • GitHub와 독립적
  • 저렴함
  • 매우 내구성 높음
  • 장기 저장을 위해 설계됨

이 가이드에서 다루는 내용

  • 여러 GitHub 저장소 백업
  • 백업을 주간으로 실행
  • 전체 Git 히스토리(브랜치 + 태그) 보존
  • OIDC + 임시 자격 증명 사용(장기 AWS 액세스 키 없음)
  • Amazon S3에 백업을 안전하게 저장

Git 번들 vs. ZIP

ZIP 백업

  • ❌ 커밋 기록 손실
  • ❌ 브랜치와 태그 누락
  • ❌ 올바르게 복원하기 어려움

Git 번들 (단일 휴대용 파일)

  • 모든 커밋, 브랜치, 태그 포함
git bundle create repo-backup.bundle --all

백업이 기록을 복원할 수 없으면, 그것은 백업이 아니다.

AWS 권한: 흔히 발생하는 함정

AWS는 두 가지 정책 유형을 사용합니다:

정책 유형사용 대상Principal 필요 여부
IAM 역할 정책신원 권한
S3 버킷 정책리소스 권한

일반적인 오류는 IAM 역할 정책을 S3 버킷 정책에 붙여넣거나 잘못된 principal ARN을 사용하는 것입니다.

업로드는 두 조건이 모두 충족될 때만 성공합니다

  1. IAM 역할 정책이 해당 작업을 허용합니다.
  2. S3 버킷 정책이 동일한 역할을 허용합니다.

어느 한 쪽이 거부하면 → AccessDenied.

GitHub Actions 워크플로우

name: Weekly S3 Repo Backup

on:
  schedule:
    - cron: "15 3 * * 0"   # Weekly
  workflow_dispatch: {}

permissions:
  id-token: write
  contents: read

jobs:
  backup:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout full history
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Create git bundle
        run: |
          set -e
          REPO_NAME="${GITHUB_REPOSITORY#*/}"
          TS="$(date -u +%Y-%m-%dT%H-%M-%SZ)"
          mkdir -p backups
          git bundle create "backups/${REPO_NAME}-${TS}.bundle" --all
          sha256sum "backups/${REPO_NAME}-${TS}.bundle" > "backups/${REPO_NAME}-${TS}.sha256"

      - name: Configure AWS credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: 
          aws-region: 

      - name: Upload to S3
        run: |
          aws s3 cp backups/ \
            s3:///github-backups/${GITHUB_REPOSITORY}/ \
            --recursive

최소 Terraform 구성

resource "aws_iam_openid_connect_provider" "github" {
  url = "https://token.actions.githubusercontent.com"

  client_id_list = [
    "sts.amazonaws.com"
  ]

  thumbprint_list = [
    "6938fd4d98bab03faadb97b34396831e3780aea1"
  ]
}

resource "aws_iam_role" "github_backup" {
  name = "github-actions-s3-backup"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Action = "sts:AssumeRoleWithWebIdentity"
      Principal = {
        Federated = aws_iam_openid_connect_provider.github.arn
      }
      Condition = {
        StringLike = {
          "token.actions.githubusercontent.com:sub" = "repo:*/*:*"
        }
      }
    }]
  })
}

resource "aws_iam_role_policy" "s3_backup" {
  role = aws_iam_role.github_backup.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["s3:ListBucket"]
        Resource = "arn:aws:s3:::example-backup-bucket"
      },
      {
        Effect = "Allow"
        Action = [
          "s3:PutObject",
          "s3:AbortMultipartUpload"
        ]
        Resource = "arn:aws:s3:::example-backup-bucket/*"
      }
    ]
  })
}

백업 복원

git clone repo-backup.bundle restored-repo
cd restored-repo
git push --all origin
git push --tags origin

GitHub API가 필요하지 않습니다.

베스트 프랙티스 체크리스트

  • 정책을 작성하기 전에 신뢰 관계를 스케치하십시오.
  • AWS 오류 메시지를 무조건 신뢰하지 마세요.
  • 루트 계정을 버킷 주체로 절대 사용하지 마세요.
  • 확장하기 전에 하나의 리포지터리로 테스트하세요.
  • 백업은 지루하고 신뢰할 수 있게 유지하세요.

좋은 백업 시스템은 필요할 때까지 잊어버리는 것이며, 그때는 그냥 작동해야 합니다.

Back to Blog

관련 글

더 보기 »