Upload para o AWS S3 usando Django Boto3 e S3Direct
O Desafio
Um dos principais desafios no upload de arquivos diretamente de um aplicativo client-side (como um aplicativo móvel React Native) para um bucket S3 da AWS é a segurança. Os buckets S3 da AWS são privados por padrão, e você não quer expor suas credenciais AWS (chave de acesso e chave secreta) diretamente no seu código client-side, pois isso representaria um risco significativo de segurança.
Para abordar esse desafio, você pode usar URLs pré-assinadas, que fornecem uma maneira segura de conceder acesso temporário ao seu bucket S3 sem expor suas credenciais. Uma URL pré-assinada é uma URL que foi assinada com suas credenciais AWS e inclui um tempo de expiração específico. Essa URL pode ser compartilhada com um aplicativo cliente, permitindo que ele faça upload de arquivos diretamente para o seu bucket S3 sem precisar de suas credenciais AWS.
S3Direct
S3 Direct é uma biblioteca Django que fornece uma interface simples para fazer upload de arquivos diretamente para o AWS S3 a partir do client-side. Ela visa simplificar o processo de obtenção dos parâmetros de upload necessários e geração da assinatura AWS Signature Version 4 (SigV4) exigida para autenticar a solicitação de upload.
Você pode registrar destinos seguindo a documentação, e com base nesses destinos, ela fornece duas views:
1. get_upload_params: Retorna os parâmetros para upload, como: object_key, access_key_id, session_token, region, bucket, endpoint, acl e allow_existence_optimization.
2. generate_aws_v4_signature: Retorna a chave de assinatura para o upload.
Assinatura AWS
A Assinatura AWS Versão 4 é um processo para autenticar solicitações de API de entrada para os serviços AWS usando uma assinatura HMAC-SHA256. A assinatura é calculada com base nos dados da solicitação, incluindo o método HTTP, URI da solicitação, corpo da solicitação e outros cabeçalhos. Essa assinatura é então incluída nos cabeçalhos da solicitação, permitindo que a AWS verifique a autenticidade e integridade da solicitação. A documentação da AWS fornece um exemplo detalhado de como calcular a assinatura SigV4 para uma solicitação S3
Esse exemplo percorre o processo passo a passo de cálculo da assinatura, incluindo a criação da solicitação canônica, criação da string a ser assinada, cálculo da chave de assinatura e, finalmente, o cálculo da própria assinatura. Você pode usar a biblioteca EvaporateJS na web para lidar com o cálculo usando JS.
Como foi complicado para mim tornar portável esse processo de assinatura para dispositivos móveis, eu usei uma URL pré-assinada para fazer o upload do vídeo para o S3.
URL Pré-Assinada
URLs pré-assinadas são uma forma segura de fornecer acesso temporário aos recursos do AWS S3 sem expor suas credenciais AWS. Uma URL pré-assinada é uma URL que é construída usando suas credenciais AWS (chave de acesso e chave secreta), e inclui um tempo de expiração específico. Quando um cliente acessa um objeto S3 usando uma URL pré-assinada, a AWS autentica a solicitação verificando a assinatura e garantindo que a solicitação seja feita dentro da janela de tempo especificada.
Boto3
Como o S3 Direct tem a limitação de não fornecer uma maneira de gerar URLs pré-assinadas, é aí que entra o Boto3.
Boto3 é o SDK da AWS para Python, e ele fornece uma maneira conveniente de interagir com vários serviços da AWS, incluindo o S3. Em seu código, você está usando o Boto3 para gerar uma URL pré-assinada para fazer upload de arquivos para o seu bucket S3.
A documentação do Boto3 fornece mais detalhes sobre como gerar URLs pré-assinadas para o S3.
Implementação
Aqui está uma visão geral de alto nível da implementação:
Primeiro, temos as rotas registradas no arquivo urls.py:
Embedded content: https://gist.github.com/kibolho/99cd18c72baf56780ce0423a2fa7be94?file=urls.py
Em seguida, a função create_presigned_post no s3helper.py usa o método generate_presigned_url do cliente Boto3 S3 para criar uma URL pré-assinada para fazer upload de um objeto para o seu bucket S3. A URL pré-assinada é então retornada para o aplicativo cliente, que pode usá-la para fazer upload do arquivo diretamente para o S3.
Embedded content: https://gist.github.com/kibolho/99cd18c72baf56780ce0423a2fa7be94?file=s3helper.py
E finalmente, na view temos a função get_presigned_url que usa os parâmetros do S3Direct e Gera a url pré-assinada com o Boto3:
Embedded content: https://gist.github.com/kibolho/99cd18c72baf56780ce0423a2fa7be94?file=view.py
Ao combinar S3 Direct e Boto3, você pode aproveitar a conveniência do S3 Direct para lidar com o processo de upload, além de tirar proveito da capacidade do Boto3 de gerar URLs pré-assinadas seguras para fazer upload de arquivos diretamente para o seu bucket S3 a partir de um aplicativo client-side.