Adds minio_s3_bucket_versioning (Enabled) for all four Hetzner Object
Storage buckets (renner-uno-k8s-cnpg, renner-uno-k8s-velero, renner-uno-k8s-secrets, renner-uno-tfstate), plus minio_s3_bucket_lifecycle noncurrent-version expiration (30 days) on
the two high-churn backup buckets (cnpg, velero) to bound storage growth.
Why object_locking is NOT flipped to true
Verified against the aminueza/minio provider source
(resource_minio_s3_bucket.go): object_locking is only consumed on
bucket Create — there's no Update handling and no ForceNew, so
setting object_locking = true on these already-live buckets (all four
were created with enable_hetzner_buckets = true, i.e. real data
already lives there) would be silently accepted by tofu apply and do nothing. That's worse than not fixing it — it reads as fixed but
isn't.
Real object-lock requires destroying and recreating each bucket
(S3/MinIO semantics: object lock can only be enabled at bucket-creation
time), which means a full data migration for buckets holding live CNPG
WAL archives, Velero backups, and the Terraform state backend itself.
That's an operator decision (acceptable downtime/migration window,
verify Hetzner's S3 impl actually supports Object Lock at all), not
something to do blind in an automated PR. Left as a follow-up —
proposal posted on #191.
No backend/state touched; this only adds resources, tofu plan will
run automatically in CI on push (opentofu/** path trigger); actual apply still requires the existing manual TOFU_APPLY=true gate.
Fixes #191.
## What
Adds `minio_s3_bucket_versioning` (Enabled) for all four Hetzner Object
Storage buckets (`renner-uno-k8s-cnpg`, `renner-uno-k8s-velero`,
`renner-uno-k8s-secrets`, `renner-uno-tfstate`), plus
`minio_s3_bucket_lifecycle` noncurrent-version expiration (30 days) on
the two high-churn backup buckets (cnpg, velero) to bound storage growth.
## Why object_locking is NOT flipped to true
Verified against the `aminueza/minio` provider source
(`resource_minio_s3_bucket.go`): `object_locking` is only consumed on
bucket **Create** — there's no `Update` handling and no `ForceNew`, so
setting `object_locking = true` on these already-live buckets (all four
were created with `enable_hetzner_buckets = true`, i.e. real data
already lives there) would be silently accepted by `tofu apply` and do
**nothing**. That's worse than not fixing it — it reads as fixed but
isn't.
Real object-lock requires destroying and recreating each bucket
(S3/MinIO semantics: object lock can only be enabled at bucket-creation
time), which means a full data migration for buckets holding live CNPG
WAL archives, Velero backups, and the Terraform state backend itself.
That's an operator decision (acceptable downtime/migration window,
verify Hetzner's S3 impl actually supports Object Lock at all), not
something to do blind in an automated PR. Left as a follow-up —
proposal posted on #191.
## Verification
- `tofu fmt -check` and `tofu validate` pass locally (provider
`aminueza/minio` 3.38.1, matches `~> 3.33` pin).
- No backend/state touched; this only adds resources, `tofu plan` will
run automatically in CI on push (`opentofu/**` path trigger); actual
`apply` still requires the existing manual `TOFU_APPLY=true` gate.
## Retention numbers used
- CNPG Barman `ObjectStore.retentionPolicy: "30d"` —
`kubernetes/seed/{authentik,immich,paperless}/objectstore.yaml`
- Velero `Schedule.ttl: 720h0m0s` (30d) —
`kubernetes/infrastructure/post-crds/velero-schedules.yaml`
object_storage.tf provisioned all four Hetzner buckets (CNPG WAL/base
backups, Velero PVC backups, cluster bootstrap secrets, tfstate) with
object_locking = false and no versioning, so a single leaked/misused S3
credential could irrecoverably delete backups and state.
Add minio_s3_bucket_versioning for all four buckets: a plain
DeleteObject no longer destroys data, the prior version survives until
purged by version ID.
object_locking is NOT flipped to true here: per the aminueza/minio
provider source, object_locking is only consumed on bucket Create, has
no Update handling and no ForceNew, so setting it on these
already-live buckets would be silently ignored -- not a real fix.
Enabling it requires destroying and recreating each bucket (full data
migration), which needs an operator decision; left as a follow-up
(see gitea issue #191 comments).
Also add minio_s3_bucket_lifecycle noncurrent-version expiration
(30 days) on the two high-churn backup buckets (cnpg, velero) to match
the retention window already enforced at the app layer (CNPG Barman
ObjectStore retentionPolicy, Velero Schedule ttl), so old S3 versions
don't accumulate indefinitely. secrets/tfstate buckets are low-churn
and left uncapped.
Fixes#191
Co-Authored-By: Claude Bot <claude-bot@renner.uno>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #191.
What
Adds
minio_s3_bucket_versioning(Enabled) for all four Hetzner ObjectStorage buckets (
renner-uno-k8s-cnpg,renner-uno-k8s-velero,renner-uno-k8s-secrets,renner-uno-tfstate), plusminio_s3_bucket_lifecyclenoncurrent-version expiration (30 days) onthe two high-churn backup buckets (cnpg, velero) to bound storage growth.
Why object_locking is NOT flipped to true
Verified against the
aminueza/minioprovider source(
resource_minio_s3_bucket.go):object_lockingis only consumed onbucket Create — there's no
Updatehandling and noForceNew, sosetting
object_locking = trueon these already-live buckets (all fourwere created with
enable_hetzner_buckets = true, i.e. real dataalready lives there) would be silently accepted by
tofu applyand donothing. That's worse than not fixing it — it reads as fixed but
isn't.
Real object-lock requires destroying and recreating each bucket
(S3/MinIO semantics: object lock can only be enabled at bucket-creation
time), which means a full data migration for buckets holding live CNPG
WAL archives, Velero backups, and the Terraform state backend itself.
That's an operator decision (acceptable downtime/migration window,
verify Hetzner's S3 impl actually supports Object Lock at all), not
something to do blind in an automated PR. Left as a follow-up —
proposal posted on #191.
Verification
tofu fmt -checkandtofu validatepass locally (provideraminueza/minio3.38.1, matches~> 3.33pin).tofu planwillrun automatically in CI on push (
opentofu/**path trigger); actualapplystill requires the existing manualTOFU_APPLY=truegate.Retention numbers used
ObjectStore.retentionPolicy: "30d"—kubernetes/seed/{authentik,immich,paperless}/objectstore.yamlSchedule.ttl: 720h0m0s(30d) —kubernetes/infrastructure/post-crds/velero-schedules.yaml