# Terraform R2 Backend 移行手順 (O-10)

## 現状 (2026-04-28)

- **R2 bucket `parky-terraform-state`**: ✅ 既に存在 (CF account `5d8f6201...`)
- **R2 API Token**: ❌ 未発行 (CF API では発行不可、Dashboard 操作必要)
- **Terraform state**: dev のみ local 状態 (`infra/terraform/envs/dev/terraform.tfstate`)。stg / prod は state 未生成
- **Backend 設定ファイル**: scaffold (`infra/terraform/backend.tf.example`) のみ存在
- **Terraform 専用 CF API token**: ✅ 発行済 (S-11 / 1P item `3vlg2ojdtsffd6j4xde3aiveqa`)

## 移行手順

### 1. R2 API Token 発行 (Dashboard)

CF API では発行不可。Dashboard から手動で実施:

1. Cloudflare Dashboard → R2 → **Manage R2 API Tokens** → **Create API Token**
2. 設定:
   - **Token name**: `parky-terraform-state-rw`
   - **Permissions**: `Object Read & Write`
   - **Specify bucket(s)**: `parky-terraform-state` のみ
   - **TTL**: なし (永続) — Terraform CI 用なので revoke 時は手動
3. 発行された **Access Key ID** + **Secret Access Key** を控える (Secret はこの 1 回のみ表示)

### 2. 1Password に保存

```bash
# op-cache-bypass: one-time write
export OP_SERVICE_ACCOUNT_TOKEN=$(cat ~/.op/sa_token.txt)

op item create \
  --vault="p3ezteh54f3msvl4wqyw7gbiam" \
  --category="API Credential" \
  --title="Cloudflare｜R2 Access Key｜Terraform State" \
  "access_key_id[concealed]=<paste>" \
  "secret_access_key[concealed]=<paste>" \
  "bucket=parky-terraform-state" \
  "endpoint=https://5d8f6201999f8965395396c4674cbe2d.r2.cloudflarestorage.com" \
  "issued_on=YYYY-MM-DD" \
  "purpose=Terraform R2 backend state storage"
```

その後 item ID を控え、`reference_1password_items.md` に追記。

### 3. backend.tf を各 env に配置

```bash
cd infra/terraform
for env in dev stg prod; do
  cp backend.tf.example envs/$env/backend.tf
  sed -i "s|<env>|$env|g" envs/$env/backend.tf
done
```

### 4. ローカル env vars 注入 (terraform init 用)

```bash
# 1Password から R2 access key 取得
ITEM_ID="<step 2 で控えた item id>"
export AWS_ACCESS_KEY_ID=$(bash scripts/op-cache/op-cache.sh get \
  "op://p3ezteh54f3msvl4wqyw7gbiam/${ITEM_ID}/access_key_id")
export AWS_SECRET_ACCESS_KEY=$(bash scripts/op-cache/op-cache.sh get \
  "op://p3ezteh54f3msvl4wqyw7gbiam/${ITEM_ID}/secret_access_key")
# CF API token (Terraform-only) も別途
export CLOUDFLARE_API_TOKEN=$(bash scripts/op-cache/op-cache.sh get \
  "op://p3ezteh54f3msvl4wqyw7gbiam/3vlg2ojdtsffd6j4xde3aiveqa/credential")
```

### 5. State 移行 (各 env で 1 回だけ)

```bash
cd infra/terraform/envs/dev
terraform init -migrate-state
# 既存 terraform.tfstate → s3://parky-terraform-state/dev/terraform.tfstate へ転送
```

stg / prod は state 未生成なので `terraform init` だけで OK (新規 backend 取得)。

### 6. State 移行確認後、local backup 削除

```bash
cd infra/terraform/envs/dev
terraform plan  # 0 diff であること
# OK なら local state file を削除
rm -f terraform.tfstate terraform.tfstate.backup terraform.tfstate.*.backup
```

### 7. CI workflows の更新

`.github/workflows/terraform.yml` (or 該当 deploy workflow) に追加:

```yaml
- name: Load secrets from 1Password
  uses: 1password/load-secrets-action@<sha>
  with:
    export-env: true
  env:
    OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SA_TOKEN }}
    AWS_ACCESS_KEY_ID: op://...
    AWS_SECRET_ACCESS_KEY: op://...
    CLOUDFLARE_API_TOKEN: op://p3ezteh54f3msvl4wqyw7gbiam/3vlg2ojdtsffd6j4xde3aiveqa/credential
```

## ロールバック

State 移行後に問題が起きた場合:

1. R2 bucket から state を `aws s3 cp` (R2 endpoint 指定) で local にダウンロード
2. backend.tf を削除 (または `local` に戻す)
3. `terraform init -migrate-state -force-copy` で local に戻す

完全 rollback できるよう、移行直後の R2 state object を別 key (`*.bootstrap-snapshot`) に複製しておくと安全。

## 関連

- TF 専用 CF API token (S-11): 1P item `3vlg2ojdtsffd6j4xde3aiveqa` (PJ｜Parky vault)
- backend.tf scaffold: `infra/terraform/backend.tf.example`
- 元の Terraform inventory: `.work/parky/terraform-inventory/inventory_2026_04_26.md`
