GitHub 리포지토리를 Amazon S3에 백업하기 (아무도 경고하지 않는 것)
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을 사용하는 것입니다.
업로드는 두 조건이 모두 충족될 때만 성공합니다
- IAM 역할 정책이 해당 작업을 허용합니다.
- 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 오류 메시지를 무조건 신뢰하지 마세요.
- 루트 계정을 버킷 주체로 절대 사용하지 마세요.
- 확장하기 전에 하나의 리포지터리로 테스트하세요.
- 백업은 지루하고 신뢰할 수 있게 유지하세요.
좋은 백업 시스템은 필요할 때까지 잊어버리는 것이며, 그때는 그냥 작동해야 합니다.