Monitoramento de Integridade de Arquivos com AWS Systems Manager e Amazon Security Lake

Monitoramento de Integridade de Arquivos: Uma Abordagem Escalável

As organizações enfrentam o desafio constante de rastrear mudanças em seus ambientes de nuvem. Isso inclui monitorar arquivos, softwares instalados e configurações em várias instâncias. Detectar alterações não autorizadas é crítico para a segurança, especialmente quando essas mudanças precisam ser integradas aos fluxos de trabalho existentes.

A AWS oferece uma solução altamente escalável e serverless para esse problema. O conceito apresentado utiliza o AWS Systems Manager Inventory para coletar metadados de arquivos em instâncias Amazon EC2, envia esses dados por meio do recurso de sincronização do Systems Manager para um bucket Amazon S3 com versionamento, e implementa uma função AWS Lambda que compara versões de inventário para detectar mudanças. Quando alterações são identificadas, a função cria achados no AWS Security Hub, que são posteriormente ingeridos pelo Amazon Security Lake em formato padronizado.

Fluxo de monitoramento de integridade de arquivos — fonte: Aws

Vantagens desta Abordagem

Esta solução oferece uma alternativa ao padrão de integração entre AWS Config e Security Hub, que se baseia em dados limitados sem incluir, por exemplo, timestamps de modificação de arquivos. A abordagem aqui apresentada fornece flexibilidade e controle para implementar lógica personalizada de detecção adaptada às necessidades operacionais específicas de cada organização.

Além disso, o modelo é extensível. O AWS Systems Manager Inventory pode coletar não apenas metadados de arquivos, mas também dados sobre aplicativos instalados, configurações de rede ou entradas do Windows Registry, permitindo criar lógica de detecção customizada para uma ampla gama de casos de uso operacionais e de segurança.

Etapas de Implementação

Pré-requisitos

Antes de começar, você precisará de uma conta AWS com permissões para criar e gerenciar recursos como Amazon EC2, AWS Systems Manager, Amazon S3 e Lambda.

Etapa 1: Configuração da Instância EC2

O primeiro passo é iniciar uma instância EC2 e criar um arquivo de configuração que será modificado posteriormente para simular uma alteração não autorizada.

Você precisará criar um papel AWS Identity and Access Management (IAM) para permitir que a instância EC2 se comunique com o Systems Manager. No console do IAM, crie um novo papel, selecione EC2 como caso de uso e anexe a política gerenciada AmazonSSMManagedInstanceCore. Nomeie esse papel como SSMAccessRole.

Em seguida, inicie uma instância EC2, mantendo a imagem Linux padrão e uma classe de instância como t3.micro. Nos detalhes avançados, atribua o papel SSMAccessRole que foi criado anteriormente. Para criar um arquivo de configuração de aplicativo durante a inicialização, use o script fornecido na seção User Data:

#!/bin/bash
mkdir -p /etc/paymentapp
echo "db_password=initial123" > /etc/paymentapp/config.yaml

Este script cria um diretório e um arquivo de configuração que será monitorado. Você pode deixar as demais configurações com seus valores padrão e prosseguir sem um key pair, já que o acesso será feito via Session Manager.

Etapa 2: Ativar Security Hub e Security Lake

Caso esses serviços já estejam ativados em sua conta, pule para a próxima etapa. Caso contrário, comece ativando o AWS Security Hub CSPM, que coleta e agrega achados de segurança e adiciona monitoramento contínuo.

No console do Security Hub, acesse a opção CSPM e selecione ativar. Para esta demonstração, você não necessita das opções de padrões de segurança, portanto, pode desmarcá-las.

A próxima etapa é ativar o Amazon Security Lake para começar a coletar achados do Security Hub. No console do Security Lake, selecione “Começar”, escolha ingerir fontes AWS específicas e selecione Security Hub como fonte de log e eventos. Escolha a região específica onde você está trabalhando, use a opção padrão para criar um novo papel de serviço e conclua a configuração.

Etapa 3: Configurar Systems Manager Inventory e Sincronização com S3

Com Security Hub e Security Lake ativados, o próximo passo é configurar o Systems Manager Inventory para coletar metadados de arquivos e exportar esses dados para S3.

Crie um bucket S3 seguindo as orientações da documentação AWS para sincronização de dados de recursos. Após criar o bucket, ative o versionamento em suas propriedades. O versionamento garante que cada novo snapshot de inventário seja salvo como uma versão separada, permitindo rastrear mudanças ao longo do tempo.

Em produção, recomenda-se ativar logging de acesso ao S3, forçar acesso apenas por HTTPS e ativar eventos de dados do CloudTrail para auditoria completa.

No console do Systems Manager, acesse Fleet Manager e configure o inventário, selecionando apenas o tipo de dados “File”. Defina o caminho para a coleta limitada aos arquivos relevantes, neste caso:

/etc/paymentapp/

Em seguida, create a sincronização de dados de recursos no Fleet Manager, fornecendo um nome para a sincronização e o nome do bucket S3 versionado criado anteriormente.

Etapa 4: Implementar a Função Lambda

Para completar a solução, você precisa criar uma função Lambda que detecte mudanças quando novos dados de inventário chegarem ao S3. Cada vez que o Systems Manager escreve um novo objeto no S3, uma Amazon S3 Event Notification acionará a função Lambda, que comparará as versões mais recentes e anteriores do objeto.

Se forem encontrados arquivos criados, modificados ou deletados, a função cria um achado de segurança em formato ASFF (AWS Security Finding Format) no Security Hub.

Crie a função Lambda no console com o nome fim-change-detector, selecione Python como runtime e copie o código principal da função:

import boto3, os, json, re
from datetime import datetime, UTC
from urllib.parse import unquote_plus
from helpers import is_critical, load_file_metadata, is_modified, extract_instance_id

s3 = boto3.client('s3')
securityhub = boto3.client('securityhub')

CRITICAL_FILE_PATTERNS = os.environ["CRITICAL_FILE_PATTERNS"].split(",")
SEVERITY_LABEL = os.environ["SEVERITY_LABEL"]

def lambda_handler(event, context):
    # Safe event handling
    if "Records" not in event or not event["Records"]:
        return
    
    # Extract S3 event
    record = event['Records'][0]
    bucket = record['s3']['bucket']['name']
    key = unquote_plus(record['s3']['object']['key'])
    current_version = record['s3']['object'].get('versionId')
    
    if not current_version:
        return
    
    # Fetching the region name
    account_id = context.invoked_function_arn.split(":")[4]
    region = boto3.session.Session().region_name
    
    # Get object versions (latest first)
    versions = s3.list_object_versions(Bucket=bucket, Prefix=key).get('Versions', [])
    versions = sorted(versions, key=lambda v: v['LastModified'], reverse=True)
    
    # Find previous version
    idx = next((i for i,v in enumerate(versions) if v["VersionId"] == current_version), None)
    if idx is None or idx + 1 >= len(versions):
        return
    
    prev_version = versions[idx+1]["VersionId"]
    
    # Load both versions
    current = load_file_metadata(bucket, key, current_version)
    previous = load_file_metadata(bucket, key, prev_version)
    
    # Compare
    created = {p for p in set(current) - set(previous) if is_critical(p)}
    deleted = {p for p in set(previous) - set(current) if is_critical(p)}
    modified = {p for p in set(current) & set(previous) if is_critical(p) and is_modified(p, current, previous)}
    
    # Report if changes were found
    if created or deleted or modified:
        instance_id = extract_instance_id(bucket, key, current_version)
        now = datetime.now(UTC).isoformat(timespec='milliseconds').replace('+00:00', 'Z')
        
        finding = {
            "SchemaVersion": "2018-10-08",
            "Id": f"fim-{instance_id}-{now}",
            "ProductArn": f"arn:aws:securityhub:{region}:{account_id}:product/{account_id}/default",
            "AwsAccountId": account_id,
            "GeneratorId": "ssm-inventory-fim",
            "CreatedAt": now,
            "UpdatedAt": now,
            "Types": ["Software and Configuration Checks/File Integrity Monitoring"],
            "Severity": {"Label": SEVERITY_LABEL},
            "Title": "File changes detected via SSM Inventory",
            "Description": (
                f"{len(created)} created, {len(modified)} modified, "
                f"{len(deleted)} deleted file(s) on instance {instance_id}"
            ),
            "Resources": [{"Type": "AwsEc2Instance", "Id": instance_id}]
        }
        
        securityhub.batch_import_findings(Findings=[finding])
    
    # No change – delete older S3 version
    else:
        if prev_version != current_version:
            try:
                s3.delete_object(Bucket=bucket, Key=key, VersionId=prev_version)
            except Exception as e:
                print(f"Delete previous S3 object version failed: {e}")

Configurar Variáveis de Ambiente

A função Lambda requer duas variáveis de ambiente. No console Lambda, acesse a aba Configuração e defina:

  • CRITICAL_FILE_PATTERNS: ^/etc/paymentapp/config.*$
  • SEVERITY_LABEL: MEDIUM

Definir Permissões

A função Lambda precisa de permissões específicas. Crie uma política inline no papel de execução da função com as seguintes permissões (substitua <bucket-name>, <region> e <account-id> pelos seus valores):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "securityhub:BatchImportFindings",
      "Resource": "arn:aws:securityhub:::product//default"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:GetObjectVersion",
        "s3:ListBucketVersions",
        "s3:DeleteObjectVersion"
      ],
      "Resource": [
        "arn:aws:s3:::",
        "arn:aws:s3:::/*"
      ]
    }
  ]
}

Adicionar Funções Auxiliares via Lambda Layer

Para melhor modularidade, crie um Lambda layer contendo funções auxiliares. Abra o AWS CloudShell e execute o seguinte script:

#!/bin/bash
set -e

FUNCTION_NAME="fim-change-detector"
LAYER_NAME="fim-change-detector-layer"

mkdir -p python

cat > python/helpers.py << 'EOF'
import json, re, os
from dateutil.parser import parse as parse_dt
import boto3

s3 = boto3.client('s3')
CRITICAL_FILE_PATTERNS = os.environ.get("CRITICAL_FILE_PATTERNS", "").split(",")

def is_critical(path):
    return any(re.match(p.strip(), path) for p in CRITICAL_FILE_PATTERNS if p.strip())

def load_file_metadata(bucket, key, version_id):
    obj = s3.get_object(Bucket=bucket, Key=key, VersionId=version_id)
    data = {}
    for line in obj['Body'].read().decode().splitlines():
        if line.strip():
            i = json.loads(line)
            n, d, m = i.get("Name","").strip(), i.get("InstalledDir","").strip(), i.get("ModificationTime","").strip()
            if n and d and m:
                data[f"{d.rstrip('/')}/{n}"] = m
    return data

def is_modified(path, current, previous):
    try:
        return parse_dt(current[path]) != parse_dt(previous[path])
    except:
        return current[path] != previous[path]

def extract_instance_id(bucket, key, version_id):
    obj = s3.get_object(Bucket=bucket, Key=key, VersionId=version_id)
    for line in obj['Body'].read().decode().splitlines():
        if line.strip():
            r = json.loads(line)
            if "resourceId" in r:
                return r["resourceId"]
    return None
EOF

zip -r helpers_layer.zip python >/dev/null

LAYER_VERSION_ARN=$(aws lambda publish-layer-version \
  --layer-name "$LAYER_NAME" \
  --description "Helper functions for File Integrity Monitoring" \
  --zip-file fileb://helpers_layer.zip \
  --compatible-runtimes python3.13 \
  --query 'LayerVersionArn' \
  --output text)

aws lambda update-function-configuration \
  --function-name "$FUNCTION_NAME" \
  --layers "$LAYER_VERSION_ARN" >/dev/null

echo "Layer created and attached to the Lambda function."

Etapa 5: Configurar Notificações de Eventos S3

Configure as S3 Event Notifications para acionar a função Lambda quando novos dados de inventário chegarem. No console S3, abra o bucket de inventário, acesse propriedades e crie uma notificação de evento com o seguinte configuração:

  • No prefixo, defina AWS%3AFile/ para limitar os acionadores apenas aos objetos de inventário de arquivos
  • Selecione o tipo de evento “Put”
  • Aponte para a função Lambda recém-criada

A coleta de inventário é executada a cada 30 minutos por padrão, mas pode ser ajustada conforme os requisitos de segurança da organização.

Etapa 6: Testar a Detecção de Mudanças

Com a instância EC2 em execução e o arquivo de configuração inicializado, você está pronto para simular uma alteração não autorizada.

Use o Session Manager para conectar à instância e modificar o arquivo:

echo "db_password=hacked456" | sudo tee /etc/paymentapp/config.yaml

Para acelerar o teste, force uma execução imediata do inventário através do State Manager no console do Systems Manager. Após a conclusão bem-sucedida, verifique o bucket S3 e o console do Security Hub. Você deve ver um novo achado relatando a mudança detectada no arquivo.

Análise e Visualização de Dados

Enquanto o Security Hub oferece uma visão centralizada de achados, é possível aprofundar a análise utilizando o Amazon Athena para executar consultas SQL diretamente nos dados normalizados do Security Lake armazenados em S3, que seguem o padrão Open Cybersecurity Schema Framework (OCSF).

Um exemplo de consulta:

SELECT finding_info.desc AS description, class_uid AS class_id, severity AS severity_label, type_name AS finding_type, time_dt AS event_time, region, accountid
FROM amazon_security_lake_table_us_east_1_sh_findings_2_0

Ajuste a cláusula FROM conforme a região utilizada. O Security Lake processa os achados antes deles aparecerem no Athena, portanto, espere um pequeno atraso.

Para exploração visual e insights em tempo real, integre o Security Lake com o Amazon OpenSearch Service e Amazon QuickSight, ambos com suporte amplo a IA generativa. Consulte a documentação para um guia detalhado sobre visualização de achados.

Limpeza de Recursos

Após testar a solução, remova os recursos criados para evitar custos contínuos:

  • Termine a instância EC2
  • Delete a sincronização de dados de recursos e a associação de inventário
  • Remova a função Lambda
  • Desative o Security Lake e Security Hub CSPM
  • Delete os papéis IAM criados
  • Delete os buckets S3 utilizados para sincronização de dados e Security Lake

Considerações para Ambientes Produtivos

Em produção, considere as seguintes práticas recomendadas para a função Lambda:

  • Configure concorrência reservada para evitar escalabilidade sem limite
  • Configure uma fila de letra morta para capturar invocações que falharam
  • Opcionalmente, anexe a função a uma Amazon VPC para isolamento de rede

Além disso, o Security Lake suporta coleta de dados em múltiplas contas e regiões utilizando o AWS Organizations. Um Systems Manager resource data sync também pode ser configurado para enviar dados de inventário a um bucket S3 centralizado, simplificando a gestão em ambientes de múltiplas contas.

Conclusão

A solução apresentada demonstra como combinar o Systems Manager Inventory, Security Hub e Security Lake para criar um sistema robusto de monitoramento de integridade de arquivos. A abordagem oferece flexibilidade, controle e escalabilidade para organizações que buscam aprofundar a visibilidade sobre mudanças em seus ambientes AWS.

O código completo da solução está disponível no AWS Samples repository. Para uma visão mais ampla sobre implementações em múltiplas contas e regiões, consulte a documentação sobre Getting Started with Amazon Security Lake and Systems Manager Inventory.

Fonte

File integrity monitoring with AWS Systems Manager and Amazon Security Lake (https://aws.amazon.com/blogs/security/file-integrity-monitoring-with-aws-systems-manager-and-amazon-security-lake/)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *