Recuperando Arquivos Deletados no S3 com Versionamento

Você deletou um arquivo no S3 e só percebeu depois. Se o bucket tinha versionamento habilitado no momento da deleção, o objeto não foi destruído — ele foi ocultado por um delete marker. Este guia mostra exatamente como localizar e restaurar a versão anterior usando AWS CLI e Console.

TL;DR — Recuperando Arquivos Deletados no S3

SituaçãoO que aconteceuComo recuperar
Versionamento ativo, DELETE simplesDelete marker criado, versão anterior intactaRemover o delete marker via CLI ou Console
Versionamento ativo, DELETE com version IDVersão específica permanentemente removidaRestaurar a versão imediatamente anterior
Versionamento nunca habilitadoObjeto destruído permanentementeNão há recuperação nativa
Versionamento suspensoComportamento misto — depende do histórico do objetoVerificar se existe versão com ID não-null

Como o Versionamento do S3 Funciona na Prática

Antes de executar qualquer comando de recuperação, é essencial entender o mecanismo — caso contrário, você pode deletar a versão errada e tornar a recuperação impossível.

Quando o versionamento está ativo, o S3 não sobrescreve nem apaga objetos. Cada operação de escrita gera uma nova versão com um ID único. Uma operação DELETE sem especificar um version ID não remove nenhuma versão — ela insere um objeto especial chamado delete marker, que passa a ser a versão atual da chave.

sequenceDiagram participant Cliente participant S3 Cliente->>S3: PUT objeto (sem version ID) S3-->>Cliente: 200 OK, VersionId: v1 Cliente->>S3: PUT objeto (nova versão) S3-->>Cliente: 200 OK, VersionId: v2 Cliente->>S3: DELETE objeto (sem version ID) S3-->>Cliente: 204 No Content, Delete Marker criado Note over S3: v1 e v2 ainda existem no bucket Cliente->>S3: GET objeto (sem version ID) S3-->>Cliente: 404 Not Found (delete marker é a versão atual) Cliente->>S3: DELETE delete marker (com VersionId do marker) S3-->>Cliente: 204 No Content Cliente->>S3: GET objeto (sem version ID) S3-->>Cliente: 200 OK, retorna v2 (versão mais recente)
  1. PUT inicial: objeto criado com version ID v1.
  2. PUT subsequente: nova versão v2 criada; v1 permanece armazenada.
  3. DELETE simples: um delete marker é inserido como versão atual. As versões v1 e v2 continuam no bucket, apenas ocultas.
  4. GET após DELETE: o S3 encontra o delete marker como versão atual e retorna HTTP 404 Not Found — não um erro de método, mas de recurso não encontrado.

Recuperar o arquivo significa, na maioria dos casos, apenas remover esse delete marker.

Pense no delete marker como um post-it colado na frente do arquivo numa gaveta. O arquivo continua lá — você só precisa tirar o post-it.

Comportamento com Versionamento Suspenso

Um bucket com versionamento suspenso tem comportamento misto. Objetos que já possuíam versões com IDs não-null antes da suspensão continuam com esse histórico preservado — uma operação DELETE nesses objetos ainda cria um delete marker. Já objetos criados após a suspensão recebem version ID null, e uma operação DELETE neles remove permanentemente essa versão null sem criar delete marker. Se você opera em um bucket suspenso, verifique o histórico de versões antes de assumir que a recuperação é possível.

Pré-requisito: Confirmar que o Versionamento Estava Ativo

Antes de qualquer tentativa de recuperação, confirme o estado atual do versionamento. Um bucket pode estar Enabled, Suspended, ou nunca ter sido configurado.

aws s3api get-bucket-versioning \
  --bucket nome-do-seu-bucket

Se a resposta retornar {} (objeto vazio), o versionamento nunca foi habilitado e não há versões anteriores para recuperar. Se retornar "Status": "Enabled", prossiga com os passos abaixo.

Passo 1 — Localizar o Delete Marker e as Versões Anteriores

Liste todas as versões e delete markers da chave deletada. Esse comando retorna o histórico completo do objeto, incluindo o delete marker inserido pela operação DELETE.

aws s3api list-object-versions \
  --bucket nome-do-seu-bucket \
  --prefix caminho/para/seu-arquivo.txt

A saída terá duas seções relevantes: Versions (versões reais do objeto) e DeleteMarkers. Identifique e anote dois valores:

  • O VersionId do delete marker (em DeleteMarkers, com "IsLatest": true).
  • O VersionId da versão que você quer restaurar (em Versions, geralmente a mais recente antes do delete marker).
🔽 Exemplo de saída do list-object-versions (clique para expandir)
{
    "DeleteMarkers": [
        {
            "Owner": { "DisplayName": "...", "ID": "..." },
            "Key": "caminho/para/seu-arquivo.txt",
            "VersionId": "abc123XYZdeleteMarkerID",
            "IsLatest": true,
            "LastModified": "2024-01-15T10:30:00.000Z"
        }
    ],
    "Versions": [
        {
            "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"",
            "Size": 204800,
            "StorageClass": "STANDARD",
            "Key": "caminho/para/seu-arquivo.txt",
            "VersionId": "xyz789ABCversionID",
            "IsLatest": false,
            "LastModified": "2024-01-14T08:00:00.000Z"
        }
    ]
}

Passo 2 — Remover o Delete Marker para Recuperar Arquivos Deletados no S3

Remover o delete marker é o que efetivamente restaura o objeto. Quando o delete marker é deletado, a versão anterior mais recente volta a ser a versão atual da chave — sem necessidade de copiar ou mover nada.

aws s3api delete-object \
  --bucket nome-do-seu-bucket \
  --key caminho/para/seu-arquivo.txt \
  --version-id abc123XYZdeleteMarkerID

Substitua abc123XYZdeleteMarkerID pelo VersionId do delete marker identificado no Passo 1. Note que você está usando delete-object para deletar o próprio delete marker — é contra-intuitivo, mas é o mecanismo correto.

Após executar o comando, verifique se o objeto está acessível novamente:

aws s3api head-object \
  --bucket nome-do-seu-bucket \
  --key caminho/para/seu-arquivo.txt

Uma resposta HTTP 200 com os metadados do objeto confirma a restauração bem-sucedida.

Passo 3 — Restaurar uma Versão Específica (Alternativa)

Se você precisa restaurar uma versão específica que não é a mais recente — por exemplo, o arquivo foi sobrescrito várias vezes e você quer uma versão de dois dias atrás — o processo é diferente. Em vez de remover o delete marker, você copia a versão desejada sobre a chave atual, tornando-a a nova versão mais recente.

aws s3api copy-object \
  --bucket nome-do-seu-bucket \
  --copy-source nome-do-seu-bucket/caminho/para/seu-arquivo.txt?versionId=xyz789ABCversionID \
  --key caminho/para/seu-arquivo.txt

Esse comando cria uma nova versão do objeto com o conteúdo da versão xyz789ABCversionID. O histórico anterior permanece intacto. Substitua xyz789ABCversionID pelo VersionId da versão que você quer restaurar, identificado no Passo 1.

Permissões IAM Necessárias

Para executar os comandos acima, a identidade IAM precisa das seguintes permissões no bucket e nos objetos. Aplique o princípio do menor privilégio — restrinja ao bucket e prefixo específicos.

🔽 Política IAM mínima para recuperação (clique para expandir)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListVersions",
      "Effect": "Allow",
      "Action": [
        "s3:ListBucketVersions",
        "s3:GetBucketVersioning"
      ],
      "Resource": "arn:aws:s3:::nome-do-seu-bucket"
    },
    {
      "Sid": "RestoreObject",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion",
        "s3:DeleteObjectVersion",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::nome-do-seu-bucket/caminho/para/*"
    }
  ]
}

A ação s3:DeleteObjectVersion é necessária especificamente para remover o delete marker no Passo 2. Sem ela, o comando retorna AccessDenied mesmo que a identidade tenha permissão de s3:DeleteObject.

Diagnóstico: Quando a Recuperação Não Funciona Como Esperado

Esse é o tipo de situação que aparece às 2h da manhã: você executou os passos, o head-object retorna 200, mas o conteúdo está errado. Ou pior — o list-object-versions não mostra nenhuma versão anterior ao delete marker.

flowchart TD A["Objeto não recuperável após DELETE"] --> B{"list-object-versions mostra DeleteMarker?"} B -- Sim --> C{"Existe versão antiga em Versions?"} C -- Sim --> D["Remover delete marker Passo 2 deste guia"] C -- Não --> E["Versões antigas expiradas por Lifecycle Policy"] B -- Não --> F{"Bucket tinha versionamento suspenso?"} F -- Sim --> G["Objeto tinha version ID null DELETE foi permanente"] F -- Não --> H["DELETE usou version ID explícito Versão removida permanentemente"]

Sintoma → Diagnóstico incorreto → Causa real:

O erro mais comum é assumir que qualquer DELETE cria um delete marker recuperável. A suposição falha quando o objeto foi criado em um bucket com versionamento suspenso — nesse caso, a versão tem ID null e um DELETE a remove permanentemente, sem criar delete marker. O list-object-versions vai mostrar a seção DeleteMarkers vazia para essa chave.

Outros cenários que bloqueiam a recuperação:

  • Lifecycle Policy com NoncurrentVersionExpiration: versões antigas podem ter sido expiradas automaticamente. Verifique com aws s3api get-bucket-lifecycle-configuration --bucket nome-do-seu-bucket.
  • DELETE com version ID explícito: se o DELETE original especificou um version ID, aquela versão foi permanentemente removida — não há delete marker, e não há recuperação para essa versão específica.
  • Object Lock com modo COMPLIANCE: versões bloqueadas não podem ser deletadas antes do período de retenção, mas também não podem ser restauradas por cima se o lock estiver ativo.

Recuperação pelo Console AWS (Alternativa Visual)

Se preferir o Console, o processo é equivalente:

  1. Acesse o bucket no Console do S3.
  2. Ative a exibição de versões clicando em 'Mostrar versões' no topo da listagem de objetos.
  3. Localize o arquivo — ele aparecerá com uma entrada marcada como 'Marcador de exclusão' com ícone diferenciado.
  4. Selecione o delete marker e clique em 'Excluir'. Confirme a operação digitando o texto solicitado.
  5. O objeto original voltará a aparecer na listagem normal.

Próximos Passos e Prevenção

Recuperar o arquivo resolve o problema imediato. Para evitar a recorrência, considere as seguintes configurações:

  • MFA Delete: exige autenticação multifator para deletar versões específicas ou alterar o estado do versionamento. Habilitado via aws s3api put-bucket-versioning com MFADelete: Enabled — requer credenciais root da conta.
  • S3 Object Lock: para objetos críticos, o modo GOVERNANCE ou COMPLIANCE impede deleção durante o período de retenção configurado.
  • Lifecycle Policy para versões antigas: sem uma política, versões antigas acumulam indefinidamente e geram custo. Configure NoncurrentVersionExpiration com um período adequado ao seu RTO.
  • S3 Replication: replicação cross-region ou cross-account como camada adicional de proteção contra deleção acidental em nível de bucket.

Documentação oficial de referência: Restoring previous versions — Amazon S3 User Guide.

Glossário

TermoDefinição
Delete MarkerObjeto especial inserido pelo S3 quando um DELETE é executado sem version ID em um bucket com versionamento ativo. Não contém dados — apenas sinaliza que a chave está 'deletada' para requisições sem version ID.
Version IDIdentificador único e imutável atribuído a cada versão de um objeto em um bucket com versionamento ativo.
Versionamento SuspensoEstado em que o bucket para de gerar novos version IDs para objetos criados após a suspensão. Versões existentes com IDs não-null são preservadas.
MFA DeleteCamada adicional de proteção que exige autenticação multifator para operações de deleção de versões específicas ou alteração do estado de versionamento.
NoncurrentVersionExpirationRegra de Lifecycle Policy que expira automaticamente versões não-atuais de objetos após um número configurável de dias.

Comentários

Postagens mais visitadas deste blog

Variáveis de Ambiente no Lambda: Configuração, Acesso e Criptografia com KMS

Monitoramento de Memória RAM no EC2: Por que o CloudWatch Agent é Obrigatório

S3 Access Denied: Por que 'Bloquear Acesso Público' impede seu objeto mesmo após torná-lo público