将 GitHub 仓库备份到 Amazon S3(没人提醒你的事)

发布: (2026年1月13日 GMT+8 22:05)
4 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的正文内容,我将把它完整地译成简体中文并保留原有的格式、Markdown 语法以及技术术语。谢谢!

为什么要备份 GitHub 仓库?

GitHub 可能会成为您所关心工作的单点故障。仓库被删除、账户被锁定或强制推送都可能把所有内容抹掉。平台外的自动化备份可以解决此问题。

为什么选择 Amazon S3?

  • 与 GitHub 无关
  • 费用低廉
  • 极其耐用
  • 为长期存储而构建

本指南涵盖的内容

  • 备份多个 GitHub 仓库
  • 每周运行备份
  • 保留完整的 Git 历史(分支 + 标签)
  • 使用 OIDC + 临时凭证(无需长期 AWS 访问密钥)
  • 安全地将备份存储在 Amazon S3

Git bundle 与 ZIP

ZIP 备份

  • ❌ 丢失提交历史
  • ❌ 丢失分支和标签
  • ❌ 恢复时困难

Git bundle(单个可移植文件)

  • 包含所有提交、分支和标签
git bundle create repo-backup.bundle --all

如果备份无法恢复历史,那就不是备份。

AWS 权限:常见陷阱

AWS 使用两种策略类型:

策略类型用途需要 Principal
IAM role policy身份权限
S3 bucket policy资源权限

一个常见错误是把 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

相关文章

阅读更多 »