O blog da AWS

Como restaurar objetos acidentalmente deletados do Amazon S3

Por Melissa Ravanini, arquiteta de soluções da AWS

O serviço de armazenamento de objetos Amazon S3 foi um dos primeiros serviços lançados pela AWS, em 2006. Desde então, ele tem se tornado peça fundamental na arquitetura de muitos dos nossos milhões de clientes ativos pelo mundo. Hoje ele armazena mais de 200 trilhões de objetos, e é projetado para prover para seus usuários 11-noves de durabilidade e um conjunto completo de funcionalidades que permitem com que os arquivos nele armazenados estejam seguros na nuvem da AWS.

Uma destas funcionalidades chama-se versionamento. Uma vez habilitada, a versão anterior de um objeto alterado ou excluído será preservada. Clientes com arquivos críticos ou produtivos no Amazon S3 são aconselhados a habilitar a funcionalidade de versionamento. Para mais informações sobre versionamento de objetos no Amazon S3, acesse este link.

Agora, imagine chegar ao trabalho e descobrir que parte dos seus objetos de produção foi removida acidentalmente por um funcionário de pouca sorte. Ao seguir as boas práticas, podemos ficar calmos pois é possível restaurar objetos deletados de um bucket versionado do Amazon S3.

Restauração dos objetos

Com fins de restaurar objetos removidos acidentalmente, compusemos um script em Python 3 que percorre todos os buckets do Amazon S3 de uma determinada conta AWS, e para todos que tiverem versionamento habilitado, ele restaura a última versão do objeto então apagado.

for bucket in buckets['Buckets']:

	[...]

	bucket_versioning = s3.meta.client.get_bucket_versioning(Bucket=bucket_name)

	# If Status is present in the response, versioning is enabled
	if 'Status' in bucket_versioning:

		[...]

		all_versions = all_objects['Versions']        

		for version in all_versions:
			if not version['IsLatest']:
				revive_object(bucket, version['Key'])

Observe que o script itera em todas as versões de todos os objetos de todos os buckets com versionamento habilitado. Se alguma versão encontrada não for a última, ele assume que esta versão pode ter deixado de ser a última em virtude da remoção acidental. Neste caso, a função revive_object será invocada, e, como o próprio nome indica, ela tentará restaurar o objeto.

Para detalhar a função revive_object, vamos explicar o que acontece quando um objeto é adicionado e posteriormente removido de um bucket versionado do Amazon S3.

Em um bucket versionado, todo objeto apagado ganha uma nova versão de si mesmo – sem conteúdo – chamada de Delete Marker. Ao tentar recuperar a última versão de um objeto apagado, o usuário receberá um erro. No entanto, ao listar todas as versões de um objeto, a última versão de um objeto apagado será o próprio Delete Marker.

Então, restaurar um objeto apagado em um bucket versionado nada mais é do que remover a versão Delete Marker. Veja na figura 1 abaixo como isso se dá:

Figura 1 – Simulação de remoção de um arquivo e sua posterior restauração

  1. Usuário inclui o objeto no bucket do Amazon S3 com versionamento habilitado, criando assim a versão 1 (V1)
  2. Usuário altera o objeto, ação esta que gera uma nova versão (V2), preservando a anterior (V1)
  3. Usuário remove o objeto, criando assim um marcador de Delete Marker
  4. Usuário remove o Delete Marker da lista de versões
  5. A versão final torna-se então a versão restaurada (V2)

Com base na teoria descrita acima, o primeiro passo antes de acionar o método revive_object é descobrir quando foi criada a versão Delete Marker, aqui no script chamada de last_modified.

Logo, antes de executar o script, você precisa configurar a data em que ocorreu a deleção acidental, no script chamada de point_of_restore, para que o script restaure apenas objetos apagados a partir desta data.

No exemplo abaixo, assumimos que o incidente se passou em 10 de Maio de 2022, pouco depois das 16h horário de Greenwich (UTC-00:00). Então escolhemos 16 horas como arredondamento para baixo.

# datetime(year, month, day, hour, minute, second, microsecond, UTC-00:00)
point_of_restore = datetime.datetime(2022, 5, 10, 16, 0, 0, 0, pytz.UTC)

Se a data de criação do Delete Marker (last_modified) for posterior à data do incidente (point_of_restore), assume-se que o objeto em questão faz parte do conjunto de arquivos apagado acidentalmente e deverá, portanto, ser restaurado. Caso contrário, nenhuma ação será feita.

def revive_object(bucket, object_key):

    response = s3.meta.client.list_object_versions(Bucket=bucket.name, Prefix=object_key, MaxKeys=1)
    
    if 'DeleteMarkers' in response:
        latest_version = response['DeleteMarkers'][0]
        
        if latest_version['IsLatest']:
            
            if point_of_restore < last_modified:
    
                logger.info("Object was deleted after point of restore. Activation will continue for object %s ",
                           object_key)
            
                obj = bucket.Object(object_key)
                obj.Version(latest_version['VersionId']).delete()

Observe pelo trecho de código acima, que o método revive_object detecta se há Delete Markers na lista de versões. No caso de sua existência, ele verifica se o Delete Marker é a última versão. Em caso afirmativo, ele verifica se a data do incidente (point_of_restore) é anterior à data de criação do Delete Marker (last_modified). Em assim sendo, o método remove então a última versão da lista de versões, restaurando assim o objeto.

O script usado neste blog post pode ser obtido neste repositório do GitHub, assim como um arquivo que serve de exemplo de política de acesso com as permissões necessárias para execução do script. Parte do conteúdo do script lida com a paginação ao iterar na lista de buckets e também com logs e exceções, que não serão escopo deste blog post.

Próximos passos

Se você precisou recorrer a este script de restauração, possivelmente a remoção acidental que ocorreu nos seus arquivos ocasionou uma instabilidade no seu sistema de produção, cuja restauração dependeu da execução de um script e da existência e integridade das versões anteriores do arquivo. Então aproveitamos o contexto para recomendar o uso do AWS Backup, que tem por finalidade gerar um backup dos arquivos do Amazon S3, com possibilidade de armazená-lo em um cofre criptografado e altamente seguro. No caso de uma remoção acidental, o backup poderá ser restaurado, recuperando assim o ambiente de produção.

Para saber mais sobre como o AWS Backup pode viabilizar a restauração do backup dos seus arquivos do Amazon S3, siga a leitura da Parte 2 deste blogpost.

Links adicionais

Para um controle de custos com relação a versões antigas de objetos, recomendamos a leitura deste blog post: https://aws.amazon.com/pt/blogs/storage/reduce-storage-costs-with-fewer-noncurrent-versions-using-amazon-s3-lifecycle/

Para saber mais sobre como gerenciar o Delete Marker, leia esta documentação.


Sobre o Autor

Melissa Ravanini tem 18 anos de experiência na área de TI e atualmente é arquiteta de soluções na AWS com foco em clientes da área da saúde, particularmente aqueles sem fins lucrativos. Ela apoia clientes em sua jornada para a nuvem e já atuou em projetos de processamento de genoma, telemedicina, data lakes, blockchain, PACs/RIS, interoperabilidade e mais. Antes da AWS, Melissa trabalhou como arquiteta de sistemas em empresas como IBM, SERPRO e PRODESP.