#!/bin/bash set -euo pipefail PROJECT_ID="sea-haven-backups" BUCKET_NAME="forgejo-backups-offsite-seahaven" LOCATION="us-central1" SA_NAME="forgejo-backup-writer" SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" RETENTION_SECONDS=$((2 * 365 * 24 * 3600)) # 2 years AWS_REGION="us-east-1" AWS_SOURCE_BUCKET="forgejo-backups-328440206208" GCLOUD="${GCLOUD:-gcloud}" GSUTIL="${GSUTIL:-gsutil}" echo "=== Forgejo 3-2-1 Offsite Backup — GCP Setup ===" # --- Project --- echo "" echo "--- Step 1: Create GCP project ---" if $GCLOUD projects describe "$PROJECT_ID" &>/dev/null; then echo "Project $PROJECT_ID already exists." else $GCLOUD projects create "$PROJECT_ID" --name="Sea Haven Backups" echo "Created project $PROJECT_ID." fi $GCLOUD config set project "$PROJECT_ID" echo "" echo "--- Step 2: Enable required APIs ---" $GCLOUD services enable storage.googleapis.com storagetransfer.googleapis.com # --- Bucket --- echo "" echo "--- Step 3: Create GCS bucket ---" if $GSUTIL ls -b "gs://$BUCKET_NAME" &>/dev/null; then echo "Bucket gs://$BUCKET_NAME already exists." else $GSUTIL mb -p "$PROJECT_ID" -l "$LOCATION" -c NEARLINE -b on "gs://$BUCKET_NAME" echo "Created bucket gs://$BUCKET_NAME." fi echo "" echo "--- Step 4: Set lifecycle rules ---" LIFECYCLE_JSON=$(cat <<'LCEOF' { "rule": [ { "action": {"type": "SetStorageClass", "storageClass": "COLDLINE"}, "condition": {"age": 90} }, { "action": {"type": "SetStorageClass", "storageClass": "ARCHIVE"}, "condition": {"age": 180} } ] } LCEOF ) echo "$LIFECYCLE_JSON" | $GSUTIL lifecycle set /dev/stdin "gs://$BUCKET_NAME" echo "Lifecycle rules applied." echo "" echo "--- Step 5: Enable object versioning ---" $GSUTIL versioning set on "gs://$BUCKET_NAME" echo "" echo "--- Step 6: Set retention policy (2 years) ---" $GSUTIL retention set "${RETENTION_SECONDS}s" "gs://$BUCKET_NAME" echo "Retention policy set to 2 years." echo "" echo "!!! IMPORTANT: Locking the retention policy is IRREVERSIBLE. !!!" echo "Once locked, objects cannot be deleted before the retention period expires." echo "Even the project owner cannot shorten or remove the policy." echo "" read -p "Lock the retention policy now? (yes/no): " CONFIRM if [ "$CONFIRM" = "yes" ]; then $GSUTIL retention lock "gs://$BUCKET_NAME" echo "Retention policy LOCKED." else echo "Retention policy set but NOT locked. Run 'gsutil retention lock gs://$BUCKET_NAME' when ready." fi # --- Service Account --- echo "" echo "--- Step 7: Create service account ---" if $GCLOUD iam service-accounts describe "$SA_EMAIL" &>/dev/null 2>&1; then echo "Service account $SA_EMAIL already exists." else $GCLOUD iam service-accounts create "$SA_NAME" \ --display-name="Forgejo Backup Verifier" \ --description="Read-only access to forgejo offsite backup bucket (verification Lambda)" echo "Created service account $SA_EMAIL." fi echo "" echo "--- Step 8: Grant bucket permissions ---" $GSUTIL iam ch "serviceAccount:${SA_EMAIL}:objectViewer" "gs://$BUCKET_NAME" echo "Granted objectViewer to $SA_EMAIL." echo "" echo "--- Step 9: Create and store service account key ---" KEY_FILE=$(mktemp) $GCLOUD iam service-accounts keys create "$KEY_FILE" --iam-account="$SA_EMAIL" echo "Service account key created." if aws secretsmanager describe-secret --secret-id forgejo/gcs-sa-key --region "$AWS_REGION" &>/dev/null 2>&1; then aws secretsmanager put-secret-value \ --secret-id forgejo/gcs-sa-key \ --secret-string "file://$KEY_FILE" \ --region "$AWS_REGION" echo "Updated existing secret forgejo/gcs-sa-key." else aws secretsmanager create-secret \ --name forgejo/gcs-sa-key \ --secret-string "file://$KEY_FILE" \ --region "$AWS_REGION" echo "Created secret forgejo/gcs-sa-key." fi rm -f "$KEY_FILE" echo "Key stored in AWS Secrets Manager, local copy deleted." # --- Storage Transfer --- echo "" echo "--- Step 10: Configure Storage Transfer Service ---" echo "" echo "Storage Transfer Service requires AWS credentials to read from S3." echo "Create a read-only IAM user 'forgejo-gcs-transfer' in AWS with access to:" echo " s3://forgejo-backups-328440206208 (GetObject, ListBucket)" echo "" echo "Then configure the transfer job in the GCP Console:" echo " 1. Go to: https://console.cloud.google.com/transfer/jobs" echo " 2. Source: Amazon S3 — bucket '$AWS_SOURCE_BUCKET'" echo " 3. Destination: GCS — bucket '$BUCKET_NAME'" echo " 4. Schedule: Daily at 10:00 UTC" echo " 5. Enter the AWS access key ID and secret for the read-only user" echo "" echo "The CDK stack creates the 'forgejo-gcs-transfer' IAM user automatically." echo "Retrieve its credentials from Secrets Manager: forgejo/gcs-transfer-credentials" echo "" echo "=== Setup complete ===" echo "" echo "Summary:" echo " GCP Project: $PROJECT_ID" echo " GCS Bucket: gs://$BUCKET_NAME" echo " Service Account: $SA_EMAIL" echo " SA Key Secret: forgejo/gcs-sa-key (AWS Secrets Manager)" echo " Retention: 2 years (check lock status above)"