O blog da AWS
Padrões para construir uma API para fazer upload de arquivos para o Amazon S3
Por Thomas Moore, Arquiteto Sênior de Soluções e Josh Hart, Arquiteto Sênior de Soluções.
As aplicações frequentemente requerem uma maneira para os usuários fazerem upload de arquivos. A abordagem tradicional é usar um serviço SFTP (como o AWS Transfer Family), mas isso requer clientes específicos e gerenciamento de credenciais SSH. Aplicações modernas, em vez disso, precisam de uma maneira de fazer upload para o Amazon S3 via HTTPS. Casos de uso típicos de upload de arquivos incluem:
- Compartilhamento de conjuntos de dados entre empresas como uma substituição direta para fluxos de trabalho FTP tradicionais.
- Upload de telemetria e logs de dispositivos IoT e aplicações móveis.
- Upload de mídia como vídeos e imagens.
- Envio de documentos digitalizados e PDFs.
Se você tem controle sobre a aplicação que envia os uploads, então você pode integrar com o AWS SDK de dentro do navegador com um framework como o AWS Amplify. Para saber mais, leia Permitindo que usuários externos façam upload de arquivos de forma segura e direta para o Amazon S3.
Frequentemente você deve fornecer aos usuários finais acesso direto para fazer upload de arquivos via um endpoint. Você poderia construir um serviço personalizado para este propósito, mas isso resulta em mais código para construir, manter e proteger.
Esta publicação explora três abordagens diferentes para fazer upload de conteúdo de forma segura para um bucket do Amazon S3 via HTTPS sem a necessidade de construir uma API dedicada ou aplicação cliente.
Usando o Amazon API Gateway como um proxy direto
A opção mais simples é usar o API Gateway para fazer proxy de um bucket S3. Isso permite que você exponha objetos S3 como APIs REST sem infraestrutura adicional. Ao configurar uma integração S3 no API Gateway, isso permite que você gerencie autenticação, autorização, cache e limitação de taxa mais facilmente.
Este padrão permite que você implemente um autorizador no nível do API Gateway e não requer alterações na aplicação cliente ou chamador. A limitação com esta abordagem é que o API Gateway tem um tamanho máximo de payload de requisição de 10 MB. Para instruções passo a passo para implementar este padrão, veja este artigo do centro de conhecimento.
Esta é uma implementação de exemplo (você pode implantar isso do Serverless Land):
Usando API Gateway com URLs pré-assinadas
O segundo padrão usa URLs pré-assinadas do S3, que permitem que você conceda acesso a objetos S3 por um período específico, após o qual a URL expira. Este acesso limitado por tempo ajuda a prevenir acesso não autorizado a objetos S3 e fornece uma camada adicional de segurança.
Elas podem ser usadas para controlar o acesso a versões específicas ou intervalos de bytes dentro de um objeto. Esta granularidade permite que você ajuste finamente as permissões de acesso para diferentes usuários ou aplicações, e garante que apenas partes autorizadas tenham acesso aos dados necessários.
Isso evita o limite de 10 MB do API Gateway, pois a API é usada apenas para gerar a URL pré-assinada, que é então usada pelo chamador para fazer upload diretamente para o S3. URLs pré-assinadas são diretas de gerar e usar programaticamente, mas isso requer que o cliente faça duas requisições separadas: uma para gerar a URL e outra para fazer upload do objeto. Para saber mais, leia Fazendo upload para o Amazon S3 diretamente de uma aplicação web ou móvel.
O padrão é limitado pelo tamanho máximo de requisição de 5GB da chamada de API Put Object do S3. Uma maneira de contornar este limite com este padrão é utilizar os uploads multipartes do S3. Isso requer que o cliente divida o payload em múltiplos segmentos e envie uma requisição separada para cada parte.
Isso adiciona alguma complexidade ao cliente e é usado por bibliotecas como o AWS Amplify que abstraem a implementação de upload multipartes. Isso permite que você faça upload de objetos de até 5TB de tamanho. Para mais detalhes, veja fazendo upload de objetos grandes para o Amazon S3 usando upload multipartes e aceleração de transferência.
Um exemplo deste padrão está disponível no Serverless Land.
Usando Amazon CloudFront com Lambda@Edge
O padrão final aproveita o Amazon CloudFront em vez do API Gateway. O CloudFront é principalmente uma rede de entrega de conteúdo (CDN) que armazena em cache e entrega conteúdo de um bucket S3 ou outra origem. No entanto, o CloudFront também pode ser usado para fazer upload de dados para um bucket S3. Sem nenhuma configuração adicional, isso essencialmente tornaria o bucket S3 publicamente gravável. Para proteger a solução de modo que apenas usuários autenticados possam fazer upload de objetos, você pode usar uma função Lambda@Edge para verificar as permissões dos usuários.
O tamanho máximo do objeto que você pode fazer upload com este padrão é 5GB. Se você precisar fazer upload de arquivos maiores que 5GB, então você deve usar uploads multipartes. Para implementar isso, implante o exemplo do padrão Serverless Land:
Esta abordagema uma identidade de acesso de origem (OAI) para limitar o acesso ao bucket S3 para vir apenas do CloudFront. A OAI padrão tem permissão s3:GetObject, que é alterada para s3:PutObject para permitir uploads explicitamente e prevenir operações de leitura:
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
},
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3::: DOC-EXAMPLE-BUCKET/*"
}
]
}
Como o CloudFront não é usado para armazenar conteúdo em cache, a política de cache gerenciada é definida como CachingDisabled.
Existem múltiplas opções para implementar a autorização na função Lambda@Edge. O repositório de exemplo usa um autorizador do Amazon Cognito que valida um JSON Web Token (JWT) enviado como um cabeçalho de autorização HTTP.
Usar um JWT é seguro, pois implica que este token é fornecido dinamicamente por um Provedor de Identidade, como o Amazon Cognito. Ou seja, o chamador precisa de um mecanismo para obter este token JWT. Você está no controle desta função autorizadora, e a implementação exata depende do seu caso de uso. Você poderia, em vez disso, usar uma Chave de API ou integrar com um provedor de identidade alternativo como Auth0 ou Okta.
As funções Lambda@Edge atualmente não suportam variáveis de ambiente. Ou seja, os parâmetros de configuração são resolvidos dinamicamente em tempo de execução. No código de exemplo, o AWS Systems Manager Parameter Store é usado para armazenar o ID do pool de usuários do Amazon Cognito e o ID do cliente de aplicação que é necessário para a verificação do token. Para mais detalhes sobre como escolher onde armazenar seus parâmetros de configuração, veja Escolhendo a solução certa para parâmetros externos do AWS Lambda.
Para verificar o token JWT, o código de exemplo usa o pacote aws-jwt-verify. Isso suporta JWTs emitidos pelo Amazon Cognito e provedores de identidade de terceiros.
O padrão Serverless Land usa um provedor de identidade do Amazon Cognito para fazer autenticação na função Lambda@Edge. Este trecho de código mostra um exemplo usando uma chave pré-compartilhada para autorização básica:
import json
def lambda_handler(event, context):
print(event)
response = event["Records"][0]["cf"]["request"]
headers = response["headers"]
if 'authorization' not in headers or headers['authorization'] == None:
return unauthorized()
if headers['authorization'] == 'my-secret-key':
return request
return response
def unauthorized():
response = {
'status': "401",
'statusDescription': 'Unauthorized',
'body': 'Unauthorized'
}
return response
A função Lambda é associada à distribuição CloudFront criando um gatilho Lambda. O evento CloudFront é definido como Viewer request, o que significa que a função é invocada em reação a eventos PUT do cliente.
A solução pode ser testada com um cliente de teste de API, como o Postman. No Postman, emita uma requisição PUT para https://<your-cloudfront-domain>/<object-name> com um payload binário como o corpo. Você receberá uma resposta 401 Unauthorized.
Em seguida, adicione o cabeçalho Authorization com um token válido e envie a requisição novamente. Para mais detalhes sobre como obter um JWT do Amazon Cognito, veja o README no repositório. Agora a requisição funciona e você recebe uma mensagem 200 OK.
Para solucionar problemas, a função Lambda registra logs no Amazon CloudWatch Logs. Para funções Lambda@Edge, procure os logs na Região mais próxima da requisição, e não na mesma Região da função.
A função Lambda@Edge neste exemplo realiza autorização básica. Ela valida se o usuário tem acesso ao recurso solicitado. Você pode realizar qualquer ação de autorização personalizada aqui. Por exemplo, em um ambiente multi-tenant, você poderia restringir o prefixo para que tenants específicos tenham apenas permissão para escrever em seu próprio prefixo, e validar o nome do objeto solicitado na função.
Adicionalmente, você poderia implementar controles tradicionalmente realizados pelo API Gateway, como limitação de taxa por tenant ou usuário. Outro uso para a função é validar o tipo de arquivo. Se os usuários só podem fazer upload de imagens, você poderia validar o content-length para garantir que as imagens tenham um certo tamanho e que a extensão do arquivo esteja correta.
Conclusão
Qual opção você escolhe depende do seu caso de uso. Esta tabela resume os padrões discutidos nesta publicação:
| API Gateway como proxy | URLs pré-assinadas com API Gateway | CloudFront com Lambda@Edge | |
| Tamanho Máximo do Objeto | 10 MB | 5 GB (5 TB com upload multipartes) | 5 GB |
| Complexidade do Cliente | Requisição HTTP Única | Múltiplas Requisições HTTP | Requisição HTTP Única |
| Opções de Autorização | Amazon Cognito, IAM, Lambda Authorizer | Amazon Cognito, IAM, Lambda Authorizer | Lambda@Edge |
| Limitação de Taxa | Limitação de taxa por Chave de API | Limitação de taxa por Chave de API | Limitação de taxa personalizada |
Cada um dos métodos disponíveis tem seus pontos fortes e fracos e a escolha de qual usar depende de suas necessidades específicas. O tamanho máximo de objeto suportado pelo S3 é 5 TB, independentemente de qual método você use para fazer upload de objetos. Adicionalmente, alguns métodos têm configuração mais complexa que requer mais expertise técnica. Considerar esses fatores com seu caso de uso específico pode ajudá-lo a tomar uma decisão informada sobre a melhor opção de API para fazer upload para o S3.
Para mais recursos de aprendizado Serverless, visite o Serverless Land.
Este conteúdo foi traduzido do post original do blog, que pode ser encontrado aqui.
Autores
| Thomas Moore é Arquiteto Sênior de Soluções na Amazon Web Services. |
| Josh Hart é Arquiteto Sênior de Soluções na Amazon Web Services. |
Tradutores
![]() |
Nicolas Tarzia é Senior Technical Account Manager na AWS, com mais de 13 anos de experiência, com ampla experiência em arquitetura cloud, engenharia e design de software. Sua área de interesse são tecnologias serverless.
https://www.linkedin.com/in/nicolastarzia |
![]() |
Daniel Abib é Arquiteto de Soluções Sênior e Especialista em Amazon Bedrock na AWS, com mais de 25 anos trabalhando com gerenciamento de projetos, arquiteturas de soluções escaláveis, desenvolvimento de sistemas e CI/CD, microsserviços, arquitetura Serverless & Containers e especialização em Machine Learning. Ele trabalha apoiando Startups, ajudando-os em sua jornada para a nuvem.
https://www.linkedin.com/in/danielabib/ |






