Короткий ответ
Нужно скачать предыдущую валидную версию объекта state из versioning-истории бакета (например, через AWS CLI aws s3api list-object-versions/get-object с нужным VersionId), проверить её локально (terraform show -json на загруженном файле, не на активном backend), и если с момента этой версии были реальные изменения в инфраструктуре мимо Terraform — аккуратно сверить их через terraform plan после восстановления, прежде чем аплайдить; саму восстановленную версию нужно загрузить обратно как текущий объект state (или через terraform state push), а не редактировать JSON вручную повторно.
Как это работает подробнее
S3 object versioning хранит каждую предыдущую версию объекта (включая state) как отдельный VersionId, то есть повреждение последней версии не удаляет предыдущие, и committed история state физически доступна для восстановления; Terraform CLI команда state push принимает локальный файл state и перезаписывает remote state целиком, что и используется для возврата к валидной версии как к новому текущему state.
Пример кода
$ aws s3api list-object-versions --bucket acme-tfstate-prod --prefix env/prod/terraform.tfstate
$ aws s3api get-object --bucket acme-tfstate-prod --key env/prod/terraform.tfstate --version-id 3HL4kqtJlcpXroDTDmjVBH restored.tfstate
$ terraform state push restored.tfstate
$ terraform planЧто использовать на практике
- Практика. перед любым восстановлением стоит сохранить повреждённую версию (на случай, если в ней были правки, которые всё же нужно перенести вручную), восстановление делать на изолированной копии (
terraform state pull/локальный файл), проверять план на отсутствие неожиданных действий, и только после этого делатьstate push; на будущее — запретить прямое редактирование state-файла организационно и технически (права доступа), и обучать команду использовать толькоterraform state ...подкоманды.
Подводные камни
- Ошибка. частая ошибка — продолжать редактировать state вручную текстовым редактором даже для «исправления» уже возникшей проблемы, что рискует сломать JSON ещё сильнее; другая ошибка — восстановить старую версию state и сразу выполнить
applyбез предварительногоplan, не проверив, что между повреждённой и восстановленной версией не было легитимных изменений инфраструктуры, которые теперь будут выглядеть как drift или будут случайно перезаписаны.