O blog da AWS

Monitorando o tráfego de rede nas funções do AWS Lambda

Escrito por Anton Aleksandrov, Principal Specialist Solutions Architect para Serverless na AWS.

O monitoramento de rede fornece visibilidade essencial dos padrões de tráfego de aplicações em nuvem em grandes organizações. Ele permite que as equipes de segurança e conformidade detectem anomalias e mantenham a conformidade, ao mesmo tempo em que permite que as equipes de desenvolvimento solucionem problemas, otimizem o desempenho e monitorem os custos em ambientes de software como serviço (SaaS) multi-tenant. A implementação de um monitoramento de rede robusto permite que as organizações gerenciem com eficiência seus requisitos operacionais, de segurança e de conformidade, ao mesmo tempo em que aprimoram continuamente suas aplicações.

Neste post, você aprenderá métodos para monitoramento de rede nas funções do AWS Lambda e como aplicá-los aos seus cenários.

Visão geral

O Lambda é um serviço de computação Serverless seguro e altamente escalável em que cada função opera em um ambiente de execução isolado com limites de segurança estrito. Essa arquitetura oferece vantagens importantes, como segurança aprimorada, escalabilidade automática da capacidade computacional e sobrecarga operacional mínima. Minimizar o gerenciamento da infraestrutura permite que o Lambda ajude as organizações a redirecionarem seu foco do gerenciamento de servidores para outros aspectos críticos, como otimização de desempenho e análise de tráfego de rede. Por sua vez, isso permite que as organizações criem aplicações mais seguras e eficientes.

O monitoramento de rede do Lambda atende a diversas necessidades organizacionais, como requisitos de conformidade para logs de auditoria e detecção de anomalias, necessidades comerciais de medição de tráfego e cobrança de clientes e necessidades de desenvolvimento para solucionar problemas de rede. Os métodos tradicionais de monitoramento baseados em agentes ou hosts geralmente não são compatíveis com o ambiente de execução efêmero e altamente isolado do Lambda, que exige abordagens alternativas para atender a esses requisitos críticos.

Você pode usar soluções de monitoramento de rede integradas e nativas da AWS, como Amazon Virtual Private Cloud (Amazon VPC) Flow Logs, ou criar sua própria solução personalizada, conforme detalhado nesta postagem. Cada solução oferece recursos distintos com níveis variados de granularidade e visibilidade em tempo real. Ao escolher uma abordagem, você deve avaliar os principais fatores, como a granularidade de dados desejada, a complexidade operacional, a tolerância à latência e as implicações de custo.

Usando o VPC Flow Logs

O VPC Flow Logs é a ferramenta recomendada pela AWS para monitoramento de atividades de rede. Se seu cenário exigir o monitoramento da atividade de rede das funções do Lambda, você poderá anexar essas funções a uma VPC e ativar o Flow Logs. Isso captura dados detalhados do tráfego de rede, como IPs de origem e destino, portas, protocolos e volume de todo o tráfego que flui pelas interfaces de rede usadas por suas funções.

Quando você anexa suas funções a uma VPC, o serviço Lambda cria automaticamente uma interface de rede elástica (ENI) para que as funções se comuniquem com recursos baseados em VPC. Por padrão, as funções anexadas à VPC só podem acessar recursos privados dentro da VPC. Se você precisar que suas funções se comuniquem com outros serviços da AWS, use VPC Endpoints. Se sua função precisar se comunicar com a Internet pública, você deverá usar um NAT Gateway para tráfego de saída. O diagrama a seguir mostra como você pode usar o VPC Flow Logs para funções Lambda.

O Flow Logs fornece informações detalhadas sobre o tráfego IP que flui de e para as interfaces de rede em uma VPC, oferecendo dados valiosos para auditorias de rede e monitoramento de atividades. Essa abordagem promove uma separação clara de preocupações entre as camadas de aplicações e de rede, com construções de VPC normalmente gerenciadas por uma equipe dedicada de operações ou infraestrutura.

O VPC Flow Logs fornece uma solução robusta de monitoramento de rede. No entanto, ao usá-lo com funções do Lambda, você deve avaliar as seguintes considerações:

  • Ele captura informações a nível de ENI. Os ENIs podem ser reutilizados em várias funções, portanto, não fornecerão granularidade por função ou por invocação.
  • Ele registra apenas endereços IP, não nomes DNS (se a captura de nomes DNS for um requisito para você).
  • Ele introduz gerenciamento de infraestrutura em suas aplicações Serverless. Você deve aprender oa conceitos da VPC ou envolver sua equipe de infraestrutura.
  • Possíveis custos adicionais de transferência de dados. Consulte os preços do NAT Gateway, VPC Endpoints e Flow Logs para obter mais detalhes.

As seções a seguir exploram os métodos de monitoramento de rede do Lambda que podem ser enriquecidos com o VPC Flow Logs para melhor granularidade ou usados sem anexar suas funções a uma VPC.

Proxy do tráfego de rede

Você pode configurar a runtime do Lambda para rotear o tráfego de saída da rede por meio de um proxy auxiliar que é executado como uma Lambda Layer no ambiente de execução do Lambda e registra as atividaded de rede. A camada de proxy deve ser independente da runtime da linguagem. A AWS recomenda que você use linguagens compiladas, como Rust ou Golang, para máxima reutilização e mínima latência adicional. O diagrama a seguir mostra a emissão de logs de uma camada de proxy de rede.

Aplicar configuração de proxy difere dependendo da runtime das linguagens. Em Python, você define as variáveis de ambiente proxy_http e proxy_https. Java usa sinalizadores JVM. O Node.js não fornece uma forma nativa de configurar o proxy usando sinalizadores de linha de comando ou variáveis de ambiente. Portanto, você precisa fazer alterações no código, como configurar um proxy para a sua SDK da AWS ou usar bibliotecas de código aberto de terceiros, como global-agent ou Interceptors.

A abordagem de proxy é mais adequada se você concorda em fazer alterações no código da função ou na configuração que pode variar entre runtimes. Além disso, adicionar um processo de servidor proxy de rede dentro do ambiente de execução consome recursos compartilhados com o código da função, o que pode aumentar a latência da rede.

Consulte o post “Enhancing runtime security and governance with the AWS Lambda Runtime API proxy extension” (“Aprimorando a segurança e a governança de runtime com a extensão AWS Lambda Runtime API proxy”) para ver formas de interceptar solicitações/respostas de entrada entre a Lambda Runtime API e o processo da Runtime.

Técnicas agnósticas à Runtimes

As técnicas a seguir usam o fato de que o ambiente de execução do Lambda é uma micro-VM baseada em Linux. As runtimes do Lambda operam em um espaço de usuário restrito que impede o uso de ferramentas tradicionais de monitoramento à nível de sistema operacional que precisam de privilégios elevados, como tcpdump, iptables, ptrace ou eBPF. As técnicas a seguir foram projetadas especificamente para funcionar sob essas restrições de espaço do usuário, permitindo seu uso sem a necessidade de privilégios elevados.

Lendo informações da camada de rede do sistema operacional a partir do procfs

Use esse método quando precisar obter as informações à nível de sistema operacional, como medir os bytes transferidos, ou ver todas as conexões abertas. Você pode usá-lo para implementar cobranças retroativas de tenant ou detectar alterações no padrão de tráfego de rede. O método é baseado no proc pseudo-filesystem (também conhecido como procfs) disponível no sistema operacional Linux, que fornece uma interface para os dados de kernel e permite que você leia informações à nível de sistema operacional. Por exemplo, os pseudo-arquivos /proc/cpuinfo e /proc/meminfo fornecem informações sobre o uso atual da CPU e da memória, enquanto /proc/net/* fornece informações sobre a camada de rede. A leitura de /proc/net/tcp e /proc/net/udp fornece uma lista de conexões TCP/UDP ativas, como portas e endereços IP remotos. A leitura de /proc/net/dev fornece a lista de dispositivos de rede com estatísticas de uso detalhadas, como bytes transferidos e recebidos.

“O método procfs fornece uma maneira simples, mas poderosa, de coletar dados críticos de telemetria de rede das funções do Lambda, como estatísticas de rede atualizadas e contagens de descritores de arquivos, o que nos permite monitorar conexões de saída das funções do Lambda. Melhor ainda, ele nos permite oferecer suporte a várias runtimes do Lambda com uma única implementação em nossa extensão do Lambda baseada em Rust” — AJ Stuyvenberg, engenheiro de equipe da Datadog.

O projeto de exemplo fornece a stack LambdaNetworkMonitor-ProCFS para mostrar essa técnica. Para cada invocação, a função lê /proc/net/dev e envia estatísticas de rede para o log e para o Amazon CloudWatch Metrics, conforme mostrado na figura a seguir.

A leitura do pseudo-arquivo /proc/net/dev é uma maneira simples e eficaz de monitorar a rede de funções do Lambda sem adicionar latência. No entanto, ele não captura os nomes DNS e os endereços IP para os quais eles são resolvidos.

Interceptando chamadas libc relacionadas à rede

As operações de rede de baixo nível no Linux, como pesquisa de DNS e criação de conexão, são gerenciadas pela C Standard Library (libc). Você pode interceptar chamadas de função libc feitas por runtimes do Lambda para monitorar o tráfego de rede à nível de sistema operacional. Esse é um mecanismo significativamente mais avançado e complexo, permitindo a visibilidade das atividades à nível de sistema operacional, conforme mostrado na figura a seguir.

Interceptar chamadas de função libc, como getaddrinfo (pesquisa de DNS) e connect, permite registrar detalhes como nome DNS, endereços IP, portas e protocolos em um nível granular, conforme mostrado na figura a seguir. Esse método permite capturar informações abrangentes sobre consultas de DNS e conexões de rede iniciadas. Ele pode fornecer monitoramento de rede preciso por função e por chamada, como nomes de host e endereços IP.

O exemplo a seguir é um fluxo simplificado:

  1. Uma função envia uma solicitação para example.com.
  2. A runtime chama libc getaddrinfo para resolver o nome DNS.
  3. Você intercepta essa chamada, registra o nome DNS e encaminha a chamada para a libc getaddrinfo original.
  4. O libc getaddrinfo original retorna endereços IP resolvidos. Você os registra e retorna a runtime.
  5. A runtime chama o método libc connect para criar uma nova conexão.
  6. Você intercepta essa chamada, registra o endereço IP, encaminha a chamada para libc connect original e assim por diante.

Para implementar essa técnica, você precisa usar uma linguagem que compila em um arquivo de objeto compartilhado (.so). Para implementar as assinaturas do método libc, você deve usar uma linguagem como C, C++ ou Rust. O código de exemplo a seguir usa o Rust por suas fortes garantias de segurança e implementa a substituição da função libc getaddrinfo (consulta de DNS).

pub extern "C" fn getaddrinfo(
    node: *const c_char,
    service: *const c_char,
    hints: *const addrinfo,
    res: *mut *mut addrinfo,
) -> c_int {
    let printable_node = format!("{}", PrintableCString::from(node));
    let printable_service = format!("{}", PrintableCString::from(service));

    log::debug!("> getaddrinfo node={printable_node} service={printable_service}");

    LIBC_GETADDRINFO(node, service, hints, res)
}

O seguinte deve ser considerado:

  • A assinatura do método corresponde totalmente à assinatura da função libc com o mesmo nome.
  • Os argumentos do e do serviço normalmente seriam nome e porta do DNS.
  • No final, a função invoca a libc getaddrinfo real e retorna o resultado.

Quando compilado em um arquivo .so, você deve empacotá-lo como uma Lambda Layer, anexar a layer às suas funções e configurar o ambiente de execução para usá-lo por meio do recurso de vinculador dinâmico do Linux chamado pré-carregamento. Defina a variável de ambiente LD_PRELOAD para apontar para seu arquivo .so e instruir o sistema operacional a pré-carregá-lo antes de carregar qualquer outra biblioteca, como libc. Você pode configurar isso como uma variável de ambiente de função ou por meio de um script de wrapper, conforme mostrado na figura a seguir.

#!/bin/sh
echo "running wrapper..."
args=("$@")
export LD_PRELOAD=/opt/liblambda_network_monitor.so
exec "${args[@]}"

Essa técnica permite que você obtenha monitoramento detalhado à nível de conexão, como pesquisas de DNS, endereços IP resolvidos, portas, protocolos e contagem de bytes transferidos. Dependendo de suas necessidades, ele pode ser adaptado para rastrear mais informações relacionadas à rede, conforme necessário.

O projeto de exemplo fornece a stack LambdaNetworkMonitor-LDPreload para mostrar essa técnica, conforme mostrado na figura a seguir. Para cada invocação, a função imprime funções libc interceptadas, nomes DNS e endereços IP de conexão.

Considerações

  • As técnicas à nível de sistema operacional exigem uma forte compreensão dos fundamentos do Linux e uma implementação cuidadosa. A AWS recomenda que você avalie cuidadosamente quais métodos usar e mantenha sua solução minimamente invasiva.
  • O LD_PRELOAD é uma técnica avançada de baixo nível que permite substituir os métodos libc e o comportamento do sistema operacional. Hooks implementados incorretamente podem levar a comportamentos indefinidos e falhas. Certifique-se de que seu código seja robusto à recursão e seguro para encadeamentos. Teste-o minuciosamente em um ambiente controlado antes de usá-lo na produção.
  • A técnica LD_PRELOAD depende de vinculação dinâmica. Ela funciona com runtimes vinculadas dinamicamente, como Node.js, Python e Java. Ela não funciona com runtimes que usam vinculação estática, como Golang.
  • Ao usar funcionalidade dependente de runtime, considere usar os controles de atualização de runtime do Lambda para garantir que as runtimes sejam atualizadas somente quando a próxima atualização da função ocorrer.
  • Sempre instale layers somente de fontes confiáveis. Use ferramentas de infraestrutura como código (IaC) para anexar e auditar configurações de layers, como permissões do AWS Identity and Access Management (IAM).

Conclusão

Monitorar o tráfego de rede nas funções do Lambda é um requisito comum para muitas organizações. Caso você precise auditar registros de rede em nível de IP, a AWS recomenda que você anexe suas funções a uma VPC e use Flow Logs. Se você precisar de granularidade por função ou por chamada, poderá enriquecê-la com as técnicas descritas nesta postagem.

Essas técnicas fornecem informações valiosas para depuração, auditoria e monitoramento, mas também exigem uma compreensão sólida dos fundamentos do Linux e uma implementação cuidadosa. Elas oferecem uma solução prática para organizações que precisam de monitoramento de rede Lambda, permitindo que elas solucionem problemas e mantenham a conformidade.

Para saber mais sobre arquiteturas serverless e padrões de invocação assíncrona do Lambda, acesse Serverless Land.

Este conteúdo foi traduzido da postagem original do blog, que pode ser encontrada aqui.

Biografia do autor

Anton Aleksandrov é Principal Specialist Solutions Architect para Serverless na AWS

Biografia da tradutora

Bianca Mota é Solutions Architect para o segmento de Startups e iniciou sua jornada na AWS em 2019 ajudando clientes em suas jornadas na nuvem. Além disso, Bianca é parte da comunidade Serverless na AWS e já apresentou sobre o assunto em diversos eventos, como o AWS Summit São Paulo e o AWS re:Invent.

https://www.linkedin.com/in/bianca-smota/

Biografia do revisor

Daniel Abib é Senior Specialist Solutions Architect para 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 segurança.

https://www.linkedin.com/in/danielabib/