Criar uma aplicação de processamento de arquivos com tecnologia sem servidor - AWS Lambda

Criar uma aplicação de processamento de arquivos com tecnologia sem servidor

Um dos casos de uso mais comuns do Lambda é a realização de tarefas de processamento de arquivos. Por exemplo, você pode usar uma função do Lambda para criar automaticamente arquivos PDF a partir de arquivos HTML ou de imagens, ou para criar miniaturas quando um usuário carrega uma imagem.

Neste exemplo, você cria uma aplicação que criptografa automaticamente os arquivos PDF quando eles são carregados em um bucket do Amazon Simple Storage Service (Amazon S3). Para implementar essa aplicação, você cria os seguintes recursos:

  • Um bucket do S3 no qual os usuários carregam arquivos PDF

  • Uma função do Lambda em Python que lê o arquivo carregado e cria uma versão dele criptografada e protegida por senha

  • Um segundo bucket do S3 no qual o Lambda salva o arquivo criptografado

Você também cria uma política do AWS Identity and Access Management (IAM) para dar à função do Lambda permissão para realizar operações de leitura e gravação nos buckets do S3.

Diagrama mostrando o fluxo de dados entre um bucket do S3, uma função do Lambda e outro bucket do S3
dica

Se você nunca tiver trabalhado com o Lambda antes, recomendamos que faça o tutorial Criar sua primeira função do Lambda antes de criar a aplicação deste exemplo.

Você pode implantar a aplicação manualmente criando e configurando os recursos com o AWS Management Console ou a AWS Command Line Interface (AWS CLI). Você também pode implantar a aplicação usando o AWS Serverless Application Model (AWS SAM). O AWS SAM é uma ferramenta de infraestrutura como código (IaC). Usando IaC, você não cria os recursos manualmente, mas os define no código e depois os implanta automaticamente.

Se você quiser saber mais sobre como usar o Lambda com IaC antes de implantar esta aplicação de exemplo, consulte Usar o Lambda com a infraestrutura como código (IaC).

Pré-requisitos

Antes de criar a aplicação de exemplo, verifique se as ferramentas de linha de comando necessárias estão instaladas.

  • AWS CLI

    Você pode implantar manualmente os recursos para a aplicação usando o AWS Management Console ou a AWS CLI. Para usar a CLI, instale-a seguindo as installation instructions do AWS Command Line Interface User Guide.

  • AWS SAM CLI

    Se você quiser implantar a aplicação de exemplo usando o AWS SAM, precisará instalar a AWS CLI e a CLI do AWS SAM. Para usar a CLI do AWS SAM, siga as installation instructions do AWS SAM User Guide.

  • módulo pytest

    Depois que implantar a aplicação, você pode testá-la usando um script de teste automatizado em Python que fornecemos. Para usar esse script, instale o pacote pytest no ambiente de desenvolvimento local executando o seguinte comando:

    pip install pytest

Para implantar a aplicação usando o AWS SAM, o Docker também deve estar instalado na máquina de compilação.

Baixar os arquivos da aplicação de exemplo

Para criar e testar a aplicação de exemplo, você cria os seguintes arquivos no diretório do projeto:

  • lambda_function.py: o código de função em Python para a função do Lambda que realiza a criptografia de arquivos

  • requirements.txt: um arquivo de manifesto que define as dependências que o código de função em Python exige

  • template.yaml: um modelo do AWS SAM que você pode usar para implantar a aplicação

  • test_pdf_encrypt.py: um script de teste que você pode usar para testar automaticamente a aplicação

  • pytest.ini: um arquivo de configuração para o script de teste

Expanda as seções a seguir para visualizar o código e saber mais sobre o papel de cada arquivo na criação e no teste da aplicação. Para criar os arquivos na máquina local, copie e cole o código abaixo ou baixe os arquivos do repositório aws-lambda-developer-guide do GitHub.

Copie e cole o código a seguir em um novo arquivo denominado lambda_function.py.

from pypdf import PdfReader, PdfWriter import uuid import os from urllib.parse import unquote_plus import boto3 # Create the S3 client to download and upload objects from S3 s3_client = boto3.client('s3') def lambda_handler(event, context): # Iterate over the S3 event object and get the key for all uploaded files for record in event['Records']: bucket = record['s3']['bucket']['name'] key = unquote_plus(record['s3']['object']['key']) # Decode the S3 object key to remove any URL-encoded characters download_path = f'/tmp/{uuid.uuid4()}.pdf' # Create a path in the Lambda tmp directory to save the file to upload_path = f'/tmp/converted-{uuid.uuid4()}.pdf' # Create another path to save the encrypted file to # If the file is a PDF, encrypt it and upload it to the destination S3 bucket if key.lower().endswith('.pdf'): s3_client.download_file(bucket, key, download_path) encrypt_pdf(download_path, upload_path) encrypted_key = add_encrypted_suffix(key) s3_client.upload_file(upload_path, f'{bucket}-encrypted', encrypted_key) # Define the function to encrypt the PDF file with a password def encrypt_pdf(file_path, encrypted_file_path): reader = PdfReader(file_path) writer = PdfWriter() for page in reader.pages: writer.add_page(page) # Add a password to the new PDF writer.encrypt("my-secret-password") # Save the new PDF to a file with open(encrypted_file_path, "wb") as file: writer.write(file) # Define a function to add a suffix to the original filename after encryption def add_encrypted_suffix(original_key): filename, extension = original_key.rsplit('.', 1) return f'{filename}_encrypted.{extension}'
nota

No código deste exemplo, uma senha para o arquivo criptografado (my-secret-password) é gravada permanentemente no código da função. Não inclua informações confidenciais, como senhas, no código de função, em uma aplicação em produção. Use o AWS Secrets Manager para armazenar parâmetros confidenciais em segurança.

O código de função em python contém três funções: a função de handler, que o Lambda executa quando a função é invocada, e duas funções separadas denominadas add_encrypted_suffix e encrypt_pdf, que o handler chama para realizar criptografia de PDF.

Quando a função é invocada pelo Amazon S3, o Lambda passa um argumento evento no formato JSON para a função que contém os detalhes do evento que causou a invocação. Nesse caso, as informações incluem o nome do bucket do S3 e as chaves de objeto dos arquivos carregados. Para saber mais sobre o formato do objeto de evento para o Amazon S3, consulte Processar notificações de eventos do Amazon S3 com o Lambda.

A função então usa o AWS SDK for Python (Boto3) para baixar os arquivos PDF especificados no objeto de evento para o diretório de armazenamento temporário local antes de criptografá-los usando a biblioteca pypdf.

Por fim, a função usa o SDK do Boto3 para armazenar o arquivo criptografado no bucket do S3 de destino.

Copie e cole o código a seguir em um novo arquivo denominado requirements.txt.

boto3 pypdf

Neste exemplo, o código da função tem apenas duas dependências que não fazem parte da biblioteca Python padrão: o SDK para Python (Boto3) e o pacote pypdf que a função usa para realizar dos arquivos PDF.

nota

Uma versão do SDK para Python (Boto3) está incluída como parte do runtime do Lambda, portanto, o código seria executado sem adicionar o Boto3 ao pacote de implantação da função. Porém, para manter total controle das dependências da função e evitar possíveis problemas de desalinhamento de versões, a prática recomendada para o Python é incluir todas as dependências da função no pacote de implantação da função. Para saber mais, consulte Dependências de runtime em Python.

Copie e cole o código a seguir em um novo arquivo denominado template.yaml.

AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Resources: EncryptPDFFunction: Type: AWS::Serverless::Function Properties: FunctionName: EncryptPDF Architectures: [x86_64] CodeUri: ./ Handler: lambda_function.lambda_handler Runtime: python3.12 Timeout: 15 MemorySize: 256 LoggingConfig: LogFormat: JSON Policies: - AmazonS3FullAccess Events: S3Event: Type: S3 Properties: Bucket: !Ref PDFSourceBucket Events: s3:ObjectCreated:* PDFSourceBucket: Type: AWS::S3::Bucket Properties: BucketName: EXAMPLE-BUCKET EncryptedPDFBucket: Type: AWS::S3::Bucket Properties: BucketName: EXAMPLE-BUCKET-encrypted

O modelo do AWS SAM define os recursos que você cria para a aplicação. Neste exemplo, o modelo define uma função do Lambda usando o tipo AWS::Serverless::Function e dois buckets do S3 usando o tipo AWS::S3::Bucket. Os nomes dos buckets especificados no modelo são espaços reservados. Antes de implantar a aplicação usando o AWS SAM, você precisa editar o modelo para renomear os buckets com nomes globalmente exclusivos que atendam às regras de nomenclatura de buckets do S3. Essa etapa é explicada com mais detalhes em Implantar recursos usando o AWS SAM.

A definição do recurso da função do Lambda configura um gatilho para a função usando a propriedade de evento S3Event. Esse gatilho faz com que a função seja invocada sempre que um objeto for criado no bucket de origem.

A definição da função também especifica uma política do AWS Identity and Access Management (IAM) a ser anexada ao perfil de execução da função. A política gerenciada da AWS AmazonS3FullAccess concede à função as permissões necessárias para ler e gravar objetos no Amazon S3.

Copie e cole o código a seguir em um novo arquivo denominado test_pdf_encrypt.py.

import boto3 import json import pytest import time import os @pytest.fixture def lambda_client(): return boto3.client('lambda') @pytest.fixture def s3_client(): return boto3.client('s3') @pytest.fixture def logs_client(): return boto3.client('logs') @pytest.fixture(scope='session') def cleanup(): # Create a new S3 client for cleanup s3_client = boto3.client('s3') yield # Cleanup code will be executed after all tests have finished # Delete test.pdf from the source bucket source_bucket = 'EXAMPLE-BUCKET' source_file_key = 'test.pdf' s3_client.delete_object(Bucket=source_bucket, Key=source_file_key) print(f"\nDeleted {source_file_key} from {source_bucket}") # Delete test_encrypted.pdf from the destination bucket destination_bucket = 'EXAMPLE-BUCKET-encrypted' destination_file_key = 'test_encrypted.pdf' s3_client.delete_object(Bucket=destination_bucket, Key=destination_file_key) print(f"Deleted {destination_file_key} from {destination_bucket}") @pytest.mark.order(1) def test_source_bucket_available(s3_client): s3_bucket_name = 'EXAMPLE-BUCKET' file_name = 'test.pdf' file_path = os.path.join(os.path.dirname(__file__), file_name) file_uploaded = False try: s3_client.upload_file(file_path, s3_bucket_name, file_name) file_uploaded = True except: print("Error: couldn't upload file") assert file_uploaded, "Could not upload file to S3 bucket" @pytest.mark.order(2) def test_lambda_invoked(logs_client): # Wait for a few seconds to make sure the logs are available time.sleep(5) # Get the latest log stream for the specified log group log_streams = logs_client.describe_log_streams( logGroupName='/aws/lambda/EncryptPDF', orderBy='LastEventTime', descending=True, limit=1 ) latest_log_stream_name = log_streams['logStreams'][0]['logStreamName'] # Retrieve the log events from the latest log stream log_events = logs_client.get_log_events( logGroupName='/aws/lambda/EncryptPDF', logStreamName=latest_log_stream_name ) success_found = False for event in log_events['events']: message = json.loads(event['message']) status = message.get('record', {}).get('status') if status == 'success': success_found = True break assert success_found, "Lambda function execution did not report 'success' status in logs." @pytest.mark.order(3) def test_encrypted_file_in_bucket(s3_client): # Specify the destination S3 bucket and the expected converted file key destination_bucket = 'EXAMPLE-BUCKET-encrypted' converted_file_key = 'test_encrypted.pdf' try: # Attempt to retrieve the metadata of the converted file from the destination S3 bucket s3_client.head_object(Bucket=destination_bucket, Key=converted_file_key) except s3_client.exceptions.ClientError as e: # If the file is not found, the test will fail pytest.fail(f"Converted file '{converted_file_key}' not found in the destination bucket: {str(e)}") def test_cleanup(cleanup): # This test uses the cleanup fixture and will be executed last pass

O script de teste automatizado executa três funções de teste para confirmar que a aplicação está funcionando corretamente:

  • O teste test_source_bucket_available confirma que o bucket de origem foi criado com sucesso carregando nele um arquivo PDF de teste.

  • O teste test_lambda_invoked interroga o último fluxo de logs do CloudWatch Logs para a função para confirmar que, quando você carregou o arquivo de teste, a função do Lambda foi executada e reportada como bem-sucedida.

  • O teste test_encrypted_file_in_bucket confirma que o bucket de destino contém o arquivo test_encrypted.pdf criptografado.

Após a execução de todos esses testes, o script executa uma etapa adicional de limpeza para excluir os arquivos test.pdf e test_encrypted.pdf dos buckets de origem e de destino.

Como no modelo do AWS SAM, os nomes de bucket especificados nesse arquivo são espaços reservados. Antes de executar o teste, você precisa editar esse arquivo com os nomes reais dos buckets da aplicação. Essa etapa é explicada com mais detalhes em Testar a aplicação com o script automatizado

Copie e cole o código a seguir em um novo arquivo denominado pytest.ini.

[pytest] markers = order: specify test execution order

Isso é necessário para especificar a ordem em que os testes do script test_pdf_encrypt.py são executados.

Implantar a aplicação

Você pode criar e implantar os recursos para a aplicação de exemplo manualmente ou usando o AWS SAM. Em um ambiente de produção, recomendamos o uso de uma ferramenta de IaC, como o AWS SAM, para implantar integralmente as aplicações de tecnologia sem servidor com rapidez, repetidas vezes, sem usar processos manuais.

Neste exemplo, siga as instruções do console ou da AWS CLI para aprender a configurar cada recurso da AWS separadamente, ou avance para Implantar recursos usando o AWS SAM e implante a aplicação rapidamente usando alguns comandos da CLI.

Implantar os recursos manualmente

Para implantar a aplicação manualmente, realize as seguintes etapas:

  • Crie os buckets do Amazon S3 de origem e de destino

  • Criar uma função do Lambda que criptografa um arquivo PDF e salva a versão criptografada em um bucket do S3

  • Configure um gatilho do Lambda que invoca a função quando os objetos são carregados no bucket de origem

Siga as instruções dos parágrafos a seguir para criar e configurar os recursos.

Criar dois buckets do S3

Primeiro, crie dois buckets do S3. O primeiro bucket corresponde ao bucket de origem no qual você vai carregar as imagens. O segundo bucket é usado pelo Lambda para salvar o arquivo criptografado quando você invoca a função.

Console
Para criar os buckets do S3 (console)
  1. Abra a página Buckets do console do Amazon S3.

  2. Selecione Criar bucket.

  3. Em General configuration (Configuração geral), faça o seguinte:

    1. Em Nome do bucket, insira um nome global exclusivo que atenda às regras de nomenclatura de buckets do Amazon S3. Os nomes dos buckets podem conter apenas letras minúsculas, números, pontos (.) e hifens (-).

    2. Em Região da AWS, escolha a Região da AWS mais próxima de sua localização geográfica. Mais adiante no processo de implantação, você deverá criar a função do Lambda na mesma Região da AWS, portanto, anote a região escolhida.

  4. Deixe todas as outras opções com seus valores padrão e escolha Criar bucket.

  5. Repita as etapas 1 a 4 para criar o bucket de destino. Em Nome do bucket, insira SOURCEBUCKET-encrypted, em que SOURCEBUCKET corresponde ao nome do bucket de origem que você acabou de criar.

AWS CLI
Criar os buckets do Amazon S3 (AWS CLI)
  1. Execute o comando da CLI apresentado a seguir para criar o bucket de origem. O nome escolhido para o bucket deve ser globalmente exclusivo e seguir as Regras de nomeação de bucket para o Amazon S3. Os nomes podem conter somente letras minúsculas, números, pontos (.) e hifens (-). Em region e LocationConstraint, escolha a Região da AWS mais próxima de sua localização geográfica.

    aws s3api create-bucket --bucket SOURCEBUCKET --region us-west-2 \ --create-bucket-configuration LocationConstraint=us-west-2

    Posteriormente no tutorial, você deverá criar a função do Lambda na mesma Região da AWS em que o bucket de origem foi criado, portanto, anote a região escolhida.

  2. Execute o comando apresentado a seguir para criar o bucket de destino. Para o nome do bucket, você deve usar SOURCEBUCKET-encrypted, em que SOURCEBUCKET é o nome do bucket de origem criado na etapa 1. Em region e LocationConstraint, escolha a mesma Região da AWS que você usou ao criar o bucket de origem.

    aws s3api create-bucket --bucket SOURCEBUCKET-encrypted --region us-west-2 \ --create-bucket-configuration LocationConstraint=us-west-2

Criar um perfil de execução (AWS CLI apenas)

Um perfil de execução é um perfil do IAM que concede a uma função do Lambda permissão para acessar os recursos e Serviços da AWS. Quando você cria uma função usando o console do Lambda, o Lambda cria automaticamente um perfil de execução. Você só precisa criar um perfil manualmente se escolher implantar a aplicação usando o AWS CLI. Para conceder à função acesso de leitura e gravação ao Amazon S3, anexe a política gerenciada da AWS AmazonS3FullAccess.

Console

Essa etapa só é necessária se você escolher implantar a aplicação usando a AWS CLI.

AWS CLI
Para criar um perfil de execução e anexar a política gerenciada da AmazonS3FullAccess (AWS CLI)
  1. Salve o JSON a seguir em um arquivo denominado trust-policy.json. Essa política de confiança permite que o Lambda use as permissões do perfil ao conceder à entidade principal de serviço a permissão lambda.amazonaws.com para chamar a ação AssumeRole do AWS Security Token Service (AWS STS).

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
  2. No diretório em que você salvou o documento de política de confiança JSON, execute o comando da CLI apresentado a seguir para criar o perfil de execução.

    aws iam create-role --role-name LambdaS3Role --assume-role-policy-document file://trust-policy.json
  3. Para anexar a política gerenciada da AmazonS3FullAccess, execute o comando da CLI a seguir.

    aws iam attach-role-policy --role-name LambdaS3Role --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess

Crie o pacote de implantação de função

Para criar sua função, crie um pacote de implantação contendo o código de função e as dependências. Para essa aplicação, o código de função usa uma biblioteca separada para a criptografia dos arquivos PDF.

Para criar o pacote de implantação
  1. Navegue até o diretório do projeto que contém os arquivos lambda_function.py e requirements.txt que você criou ou baixou anteriormente do GitHub e crie um novo diretório denominado package.

  2. Instale as dependências especificadas no arquivo requirements.txt no diretório packageexecutando o comando a seguir.

    pip install -r requirements.txt --target ./package/
  3. Crie um arquivo .zip contendo o código da aplicação e suas dependências. No Linux ou no MacOS, execute os comandos a seguir na interface da linha de comando.

    cd package zip -r ../lambda_function.zip . cd .. zip lambda_function.zip lambda_function.py

    No Windows, use sua ferramenta de zip preferida para criar o arquivo lambda_function.zip. Certifique-se de que o arquivo lambda_function.py e as pastas que contêm as dependências estejam todos na raiz do arquivo .zip.

Você também pode criar seu pacote de implantação usando um ambiente virtual Python. Consulte Trabalhar com arquivos .zip para funções do Lambda em Python

Criar a função do Lambda

Agora, você usa o pacote de implantação criado na etapa anterior para implantar a função do Lambda.

Console
Para criar a função (console)

Para criar a função do Lambda usando o console, primeiro é necessário criar uma função básica contendo algum código “Hello world”. Depois, você substitui esse código por seu próprio código de função carregando o arquivo .zip criado na etapa anterior.

Para garantir que a função não atinja o tempo limite ao criptografar arquivos PDF grandes, você define as configurações de memória e de tempo limite da função. Você também define o formato de log da função como JSON. É necessário configurar os logs no formato JSON ao usar o script de teste fornecido para que ele possa ler o status da invocação da função no CloudWatch Logs para confirmar seu sucesso.

  1. Abra a página Funções do console do Lambda.

  2. Certifique-se de estar trabalhando na mesma Região da AWS em que criou o bucket do S3. É possível alterar a região usando a lista suspensa na parte superior da tela.

    Imagem mostrando o menu suspenso de regiões no console do Lambda
  3. Escolha Create function (Criar função).

  4. Escolha Author from scratch (Criar do zero).

  5. Em Basic information (Informações básicas), faça o seguinte:

    1. Em Function name (Nome da função), insira EncryptPDF.

    2. Em Runtime, selecione Python 3.12.

    3. Em Architecture (Arquitetura), escolha x86_64.

  6. Escolha a opção Criar função.

Fazer upload do código da função (console)
  1. No painel do Código-fonte, escolha Carregar de.

  2. Escolha o arquivo .zip.

  3. Escolha Carregar.

  4. No seletor de arquivos, selecione o arquivo .zip e escolha Abrir.

  5. Escolha Salvar.

Para configurar a memória e o tempo limite da função (console)
  1. Selecione a guia Configuração para a função.

  2. No painel Configuração geral, escolha Editar.

  3. Defina Memória como 256 MB e Tempo limite como 15 segundos.

  4. Escolha Salvar.

Para configurar o formato de log (console)
  1. Selecione a guia Configuração para a função.

  2. Na barra lateral, selecione Ferramentas de monitoramento e operações.

  3. No painel Configuração de registro em log, escolha Editar.

  4. Em Configuração do registro em log, selecione JSON.

  5. Escolha Salvar.

AWS CLI
Criar a função (AWS CLI)
  • Execute o comando a seguir no diretório que contém o arquivo lambda_function.zip. No parâmetro region, substitua us-west-2 pela região em que você criou os buckets do S3.

    aws lambda create-function --function-name EncryptPDF \ --zip-file fileb://lambda_function.zip --handler lambda_function.lambda_handler \ --runtime python3.12 --timeout 15 --memory-size 256 \ --role arn:aws:iam::123456789012:role/LambdaS3Role --region us-west-2 \ --logging-config LogFormat=JSON

Configurar um gatilho do Amazon S3 para invocar a função

Para que a função do Lambda seja executada quando você carregar uma imagem no bucket de origem, é necessário configurar um gatilho para a função. Você pode configurar o acionador do Amazon S3 usando o console ou a AWS CLI.

Importante

Este procedimento configura o bucket do S3 para invocar a função sempre que um objeto é criado no bucket. Certifique-se de configurar isso somente no bucket de origem. Se a função do Lambda criar objetos no mesmo bucket que a invoca, a função poderá ser invocada continuamente em um loop. Isso pode resultar em cobranças inesperadas para sua Conta da AWS.

Console
Configurar o acionador do Amazon S3 (console)
  1. Abra a página de Funções do console do Lambda e escolha sua função (EncryptPDF).

  2. Escolha Add trigger.

  3. Selecione S3.

  4. Em Bucket, selecione o bucket de origem.

  5. Em Tipos de eventos, selecione Todos os eventos de criação de objetos.

  6. Em Invocação recursiva, marque a caixa de seleção para confirmar que entende que não é recomendável usar o mesmo bucket do S3 para entrada e saída. Saiba mais sobre padrões de invocação recursiva no Lambda lendo Recursive patterns that cause run-away Lambda functions no Serverless Land.

  7. Escolha Adicionar.

    Quando você cria um acionador usando o console do Lambda, o Lambda cria automaticamente uma política baseada em recursos para conceder permissão ao serviço selecionado para invocar a função.

AWS CLI
Configurar o acionador do Amazon S3 (AWS CLI)
  1. Para que o bucket de origem do Amazon S3 invoque a função quando você adicionar um arquivo de imagem, primeiro é necessário configurar permissões para a função usando uma política baseada em recursos. Uma instrução de política baseada em recursos concede permissão a outros Serviços da AWS para invocar sua função. Para conceder permissão ao Amazon S3 para invocar a função, execute o comando da CLI apresentado a seguir. Certifique-se de substituir o parâmetro source-account por seu ID da Conta da AWS e usar o nome do bucket de origem.

    aws lambda add-permission --function-name EncryptPDF \ --principal s3.amazonaws.com --statement-id s3invoke --action "lambda:InvokeFunction" \ --source-arn arn:aws:s3:::SOURCEBUCKET \ --source-account 123456789012

    A política que você define com este comando permite que o Amazon S3 invoque a função somente quando uma ação ocorre em seu bucket de origem.

    nota

    Embora os nomes de bucket do S3 sejam globalmente exclusivos, ao usar políticas baseadas em recursos, é uma prática recomendada especificar que o bucket deve pertencer à sua conta. Isso ocorre porque, se você excluir um bucket, é possível que outra Conta da AWS crie um bucket com o mesmo nome do recurso da Amazon (ARN).

  2. Salve o JSON a seguir em um arquivo denominado notification.json. Quando aplicado ao bucket de origem, esse JSON configura o bucket para enviar uma notificação à sua função do Lambda sempre que um novo objeto é adicionado. Substitua o número da Conta da AWS e a Região da AWS no ARN da função do Lambda por seu número de conta e sua região.

    { "LambdaFunctionConfigurations": [ { "Id": "EncryptPDFEventConfiguration", "LambdaFunctionArn": "arn:aws:lambda:us-west-2:123456789012:function:EncryptPDF", "Events": [ "s3:ObjectCreated:Put" ] } ] }
  3. Execute o comando da CLI apresentado a seguir para aplicar as configurações de notificação no arquivo JSON criado ao bucket de origem. Substitua SOURCEBUCKET pelo nome do bucket de origem.

    aws s3api put-bucket-notification-configuration --bucket SOURCEBUCKET \ --notification-configuration file://notification.json

    Para saber mais sobre o comando put-bucket-notification-configuration e a opção notification-configuration, consulte put-bucket-notification-configuration na Referência de comandos da CLI da AWS.

Implantar recursos usando o AWS SAM

Para implantar a aplicação de exemplo usando a CLI do AWS SAM, realize as etapas a seguir.

Certifique-se de que você instalou a última versão da CLI e de que o Docker está instalado na máquina de compilação.

  1. Edite o arquivo template.yaml para especificar o nome dos buckets do S3. Os buckets do S3 devem ter nomes globalmente exclusivos que atendam às regras de nomenclatura do S3.

    Substitua o nome do bucket EXAMPLE-BUCKET por um nome de sua escolha composto por letras minúsculas, números, pontos (.) e hifens (-). Para o bucket de destino, substitua EXAMPLE-BUCKET-encrypted por <source-bucket-name>-encrypted, onde <source-bucket> é o nome que você escolheu para o bucket de origem.

  2. Execute o comando a seguir no diretório em que você salvou os arquivos template.yaml, lambda_function.py e requirements.txt.

    sam build --use-container

    Esse comando reúne os artefatos de compilação da aplicação e os coloca no formato e no local adequados para implantá-los. Especificar a opção --use-container compila a função dentro de um contêiner do Docker semelhante ao Lambda. Nós o usamos aqui para que você não precise ter o Python 3.12 instalado na máquina local para que a compilação funcione.

    Durante o processo de compilação, o AWS SAM procura o código da função do Lambda no local que você especificou com a propriedade CodeUri no modelo. Neste caso, especificamos o diretório atual como o local (./).

    Se houver um arquivo requirements.txt presente, o AWS SAM o usará para coletar as dependências especificadas. Por padrão, o AWS SAM cria um pacote de implantação .zip com o código e as dependências da função. Você também pode escolher implantar a função como uma imagem de contêiner usando a propriedade PackageType.

  3. Para implantar a aplicação e criar os recursos do Lambda e do Amazon S3 especificados no modelo do AWS SAM, execute o comando a seguir.

    sam deploy --guided

    Usar o sinalizador --guided significa que o AWS SAM mostrará instruções para guiar você no processo de implantação. Para a implantação, aceite as opções padrão pressionando Enter.

Durante o processo de implantação, o AWS SAM cria os seguintes recursos na sua Conta da AWS:

  • Uma pilha do AWS CloudFormation chamada sam-app

  • Uma função do Lambda com o nome de EncryptPDF

  • Dois buckets do S3 com os nomes que você escolheu quando editou o arquivo template.yaml do modelo do AWS SAM

  • Um perfil de execução do IAM para sua função com o formato de nome sam-app-EncryptPDFFunctionRole-2qGaapHFWOQ8

Quando o AWS SAM termina de criar os recursos, você deve ver a seguinte mensagem:

Successfully created/updated stack - sam-app in us-west-2

Testando a aplicação

Para testar a aplicação, você carrega um arquivo PDF no bucket de origem e confirma que o Lambda cria uma versão criptografada do arquivo no bucket de destino. Neste exemplo, você pode testar isso manualmente usando o console ou a AWS CLI, ou usando o script de teste fornecido.

Para aplicações em produção, você pode usar os métodos e as técnicas de teste tradicionais, como testes de unidade, para confirmar o funcionamento correto do código da função do Lambda. A prática recomendada também é realizar testes como os do script de teste fornecido que realizam testes de integração com recursos reais baseados na nuvem. Os testes de integração na nuvem confirmam que a infraestrutura foi implantada corretamente e que os eventos fluem entre os diferentes serviços como esperado. Para saber mais, consulte Como testar funções e aplicações com tecnologia sem servidor.

Testar a aplicação manualmente

Você pode testar a função manualmente adicionando um arquivo PDF ao bucket de origem do Amazon S3. Quando você adiciona o arquivo ao bucket de origem, a função do Lambda deve ser invocada automaticamente e uma versão criptografada do arquivo deve ser armazenada no bucket de destino.

Console
Para testar a aplicação carregando um arquivo (console)
  1. Para carregar um arquivo PDF no bucket do S3, faça o seguinte:

    1. Abra a página Buckets do console do Amazon S3 e escolha o bucket de origem.

    2. Escolha Carregar.

    3. Escolha Adicionar arquivos e use o seletor de arquivo para escolher o arquivo de imagem que você deseja carregar.

    4. Selecione Abrir e Carregar.

  2. Verifique se o Lambda salvou uma versão criptografada do arquivo PDF no bucket de destino fazendo o seguinte:

    1. Retorne para a página Buckets do console do Amazon S3 e escolha o bucket de destino.

    2. No painel Objetos, você deve ver um arquivo com o formato de nome filename_encrypted.pdf (onde filename.pdf era o nome do arquivo que você enviou para o bucket de origem). Para baixar o PDF criptografado, selecione o arquivo e escolha Baixar.

    3. Confirme que você consegue abrir o arquivo baixado com a senha que a função do Lambda usou para protegê-lo (my-secret-password).

AWS CLI
Para testar a aplicação carregando um arquivo (AWS CLI)
  1. No diretório que contém o arquivo PDF que você deseja carregar, execute o comando da CLI a seguir. Substitua o parâmetro --bucket pelo nome do bucket de origem. Para os parâmetros --key e --body, use o nome de arquivo do arquivo de teste.

    aws s3api put-object --bucket SOURCEBUCKET --key test.pdf --body ./test.pdf
  2. Confirme que a função criou uma versão criptografada do arquivo e salvou-a no bucket do S3 de destino. Execute o comando da CLI apresentado a seguir, substituindo SOURCEBUCKET-encrypted pelo nome do bucket de destino.

    aws s3api list-objects-v2 --bucket SOURCEBUCKET-encrypted

    Se a função for executada com êxito, você visualizará uma saída semelhante à apresentada a seguir. O bucket de destino deve conter um arquivo com o formato de nome <your_test_file>_encrypted.pdf, onde <your_test_file> é o nome do arquivo que você carregou.

    { "Contents": [ { "Key": "test_encrypted.pdf", "LastModified": "2023-06-07T00:15:50+00:00", "ETag": "\"7781a43e765a8301713f533d70968a1e\"", "Size": 2763, "StorageClass": "STANDARD" } ] }
  3. Para baixar o arquivo que o Lambda salvou no bucket de destino, execute o comando da CLI a seguir. Substitua o parâmetro --bucket pelo nome do bucket de destino. Para o parâmetro --key, use o nome do arquivo <your_test_file>_encrypted.pdf, onde <your_test_file> é o nome do arquivo de teste que você carregou.

    aws s3api get-object --bucket SOURCEBUCKET-encrypted --key test_encrypted.pdf my_encrypted_file.pdf

    Esse comando baixa o arquivo para o diretório atual e salva-o como my_encrypted_file.pdf.

  4. Confirme que você consegue abrir o arquivo baixado com a senha que a função do Lambda usou para protegê-lo (my-secret-password).

Testar a aplicação com o script automatizado

Para testar a aplicação usando o script de teste fornecido, primeiro certifique-se de que o módulo pytest esteja instalado no ambiente local. Você pode instalar o pytest executando o seguinte comando:

pip install pytest

Você também precisa editar o código no arquivo test_pdf_encrypt.py para substituir os nomes de bucket de espaço reservado pelos nomes dos buckets de origem e destino do Amazon S3. Faça as seguintes alterações em test_pdf_encrypt.py:

  • Na função test_source_bucket_available, substitua EXAMPLE-BUCKET pelo nome do bucket de origem.

  • Na função test_encrypted_file_in_bucket, substitua EXAMPLE-BUCKET-encrypted por <source-bucket>-encrypted, onde <source-bucket> é o nome do bucket de origem.

  • Na função cleanup, substitua EXAMPLE-BUCKET pelo nome do bucket de origem e substitua EXAMPLE-BUCKET-encrypted por ≪source-bucket>-encrypted, onde <source-bucket> é o nome do seu bucket de origem.

Para executar os testes, faça o seguinte:

  • Salve um arquivo PDF denominado test.pdf no diretório que contém os arquivos test_pdf_encrypt.py e pytest.ini.

  • Abra um terminal ou um programa shell e execute o comando a seguir no diretório que contém os arquivos de teste.

    pytest -s -v

Quando o teste for concluído, você verá uma saída como a seguinte:

============================================================== test session starts ========================================================= platform linux -- Python 3.12.2, pytest-7.2.2, pluggy-1.0.0 -- /usr/bin/python3 cachedir: .pytest_cache hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/pdf_encrypt_app/.hypothesis/examples') Test order randomisation NOT enabled. Enable with --random-order or --random-order-bucket=<bucket_type> rootdir: /home/pdf_encrypt_app, configfile: pytest.ini plugins: anyio-3.7.1, hypothesis-6.70.0, localserver-0.7.1, random-order-1.1.0 collected 4 items test_pdf_encrypt.py::test_source_bucket_available PASSED test_pdf_encrypt.py::test_lambda_invoked PASSED test_pdf_encrypt.py::test_encrypted_file_in_bucket PASSED test_pdf_encrypt.py::test_cleanup PASSED Deleted test.pdf from EXAMPLE-BUCKET Deleted test_encrypted.pdf from EXAMPLE-BUCKET-encrypted =============================================================== 4 passed in 7.32s ==========================================================

Próximas etapas

Agora que você criou esta aplicação de exemplo, pode usar o código fornecido como base para criar outros tipos de aplicação de processamento de arquivos. Modifique o código no arquivo lambda_function.py para implementar a lógica de processamento de arquivos para seu caso de uso.

Muitos casos de uso típicos de processamento de arquivos envolvem processamento de imagens. Ao usar o Python, as bibliotecas de processamento de imagens mais populares, como a pillow, normalmente contêm componentes em C ou C++. Para garantir que o pacote de implantação da função seja compatível com o ambiente de execução do Lambda, é importante usar o binário de distribuição do fonte correto.

Ao implantar os recursos com o AWS SAM, você precisa tomar algumas medidas adicionais para incluir a distribuição do fonte correto no pacote de implantação. Como o AWS SAM não instala dependências para uma plataforma diferente da plataforma da máquina de compilação, especificar a distribuição do fonte correto (arquivo .whl) no arquivo requirements.txt não funcionará se sua máquina de compilação usar um sistema operacional ou uma arquitetura diferente do ambiente de execução do Lambda. Em vez disso, você deve realizar um dos seguintes procedimentos: