Neste tutorial, vamos explicar como criar e configurar uma função Lambda na AWS que captura eventos do AWS Inspector via SNS, formata esses eventos em um email detalhado e os envia via AWS SES para um destinatário específico.
Passos:
Criar a Função Lambda:
Primeiro, você precisa criar uma função Lambda na AWS. A função Lambda será acionada pelos eventos gerados pelo AWS Inspector através do SNS.- Acesse o Console da AWS.
- Vá para o serviço Lambda.
- Clique em “Criar função”.
- Configure o nome, a runtime (Python 3.12 ou superior recomendado) e deixe as permissões de execução padrão inicialmente. (Depois adicione AmazonEC2ReadOnlyAccess, AmazonSESFullAccess, AmazonSNSReadOnlyAccess e AmazonEC2ContainerRegistryReadOnly)
- Defina como 1 minuto o timeout da lambda.
Configurar Gatilho do SNS:
- Após criar a função Lambda, adicione um gatilho SNS.
- Selecione o tópico SNS que recebe os eventos do AWS Inspector.
- Exemplo da CloudWatch Rule de detecção do Inspector que envia para o SNS:
{ "source": ["aws.inspector2"], "detail-type": ["Inspector2 Finding"], "detail": { "severity": ["HIGH", "MEDIUM", "CRITICAL"], "status": ["ACTIVE", "CLOSED", "SUPRESSED"] }
}
- Configure a função lambda para ser acionada por novas mensagens no tópico SNS.
Implementar o Código da Função Lambda:
- Troque o nome da empresa do código, para a empresa que deseja configurar o alerta.
import json
import boto3
import os # Inicialize os clientes da AWS
ses_client = boto3.client('ses')
ec2_client = boto3.client('ec2')
ecr_client = boto3.client('ecr') def send_email(subject, body): # Função para enviar o email usando SES
response = ses_client.send_email( Source=os.environ['SOURCE_EMAIL'], Destination={ 'ToAddresses': [os.environ['TARGET_EMAIL']] }, Message={ 'Subject': { 'Data': subject, 'Charset': 'UTF-8' }, 'Body': { 'Html': { 'Data': body, 'Charset': 'UTF-8' } } } ) print(f"Email enviado com sucesso: {response}") def lambda_handler(event, context): for record in event['Records']: sns_message = json.loads(record['Sns']['Message']) detail = sns_message.get('detail', {}) # Detalhes do evento
title = detail.get('title', 'N/A') description = detail.get('description', 'N/A').replace('\n', '<br>') severity = detail.get('severity', 'N/A') status = detail.get('status', 'N/A') finding_arn = detail.get('findingArn', 'N/A') first_observed = detail.get('firstObservedAt', 'N/A') last_observed = detail.get('lastObservedAt', 'N/A') updated_at = detail.get('updatedAt', 'N/A') vulnerability_id = detail.get('packageVulnerabilityDetails', {}).get('vulnerabilityId', 'N/A') resources = detail.get('resources', []) for resource in resources: resource_type = resource.get('type', '') if resource_type == 'AWS_EC2_INSTANCE': # Detalhes da instância EC2
instance_id = resource.get('id', 'N/A') instance_name = get_ec2_instance_name(instance_id) instance_profile = resource.get('details', {}).get('awsEc2Instance', {}).get('iamInstanceProfileArn', 'N/A') image_id = resource.get('details', {}).get('awsEc2Instance', {}).get('imageId', 'N/A') ipv4_addresses = ', '.join(resource.get('details', {}).get('awsEc2Instance', {}).get('ipV4Addresses', [])) platform = resource.get('details', {}).get('awsEc2Instance', {}).get('platform', 'N/A') instance_type = resource.get('details', {}).get('awsEc2Instance', {}).get('type', 'N/A') # Construir corpo do email para EC2
email_subject = f"Alerta de Segurança - {instance_name} - {title}" email_body = build_ec2_email_body(instance_name, title, description, instance_id, instance_profile, image_id, ipv4_addresses, platform, instance_type, severity, status, finding_arn, first_observed, last_observed, updated_at, vulnerability_id) send_email(email_subject, email_body) elif resource_type == 'AWS_ECR_CONTAINER_IMAGE': # Detalhes da imagem no ECR
repository_name = resource.get('details', {}).get('awsEcrContainerImage', {}).get('repositoryName', 'N/A') image_digest = resource.get('details', {}).get('awsEcrContainerImage', {}).get('imageDigest', 'N/A') image_tags = ', '.join(resource.get('details', {}).get('awsEcrContainerImage', {}).get('imageTags', [])) pushed_at = resource.get('details', {}).get('awsEcrContainerImage', {}).get('pushedAt', 'N/A') architecture = resource.get('details', {}).get('awsEcrContainerImage', {}).get('architecture', 'N/A') platform = resource.get('details', {}).get('awsEcrContainerImage', {}).get('platform', 'N/A') # Construir corpo do email para ECR
email_subject = f"Alerta de Segurança - {repository_name} - {title}" email_body = build_ecr_email_body(repository_name, title, description, image_digest, image_tags, pushed_at, architecture, platform, severity, status, finding_arn, first_observed, last_observed, updated_at, vulnerability_id) send_email(email_subject, email_body) def get_ec2_instance_name(instance_id): # Função para obter o nome da instância EC2 a partir do ID da instância
instance_name = "N/A" if instance_id != "N/A": ec2_response = ec2_client.describe_instances(InstanceIds=[instance_id]) tags = ec2_response['Reservations'][0]['Instances'][0].get('Tags', []) for tag in tags: if tag['Key'] == 'Name': instance_name = tag['Value'] break return instance_name def build_ec2_email_body(instance_name, title, description, instance_id, instance_profile, image_id, ipv4_addresses, platform, instance_type, severity, status, finding_arn, first_observed, last_observed, updated_at, vulnerability_id): # Função para construir o corpo do email para eventos de EC2
email_body = f"""
<html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Alerta de Segurança - Empresa XPTO PCI-DSS</title> <style> body {{ font-family: Arial, sans-serif; line-height: 1.6; margin: 20px; background-color: #f5f5f5; }} h2 {{ background-color: #333; color: #fff; padding: 10px; border-radius: 5px 5px 0 0; margin-top: 0; }} p {{ margin-bottom: 20px; color: #555; padding: 0 10px; }} table {{ width: 100%; border-collapse: collapse; border: 1px solid #ddd; border-radius: 5px; margin-top: 20px; }} th, td {{ padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }} th {{ background-color: #f2f2f2; color: #333; font-weight: bold; }} tr:nth-child(even) {{ background-color: #f9f9f9; }} td:first-child, th:first-child {{ width: 30%; min-width: 120px; font-weight: bold; }} </style>
</head>
<body> <h2>Alerta de Segurança - Empresa XPTO PCI-DSS</h2> <p>Recebemos uma nova notificação de vulnerabilidade no AWS Inspector:</p> <table> <tr> <th colspan="2">Detalhes da Vulnerabilidade</th> </tr> <tr> <td><b>Título</b></td> <td>{title}</td> </tr> <tr> <td><b>Descrição</b></td> <td>{description}</td> </tr> <tr> <td><b>ID da Vulnerabilidade</b></td> <td>{vulnerability_id}</td> </tr> <tr> <td><b>Severidade</b></td> <td>{severity}</td> </tr> <tr> <td><b>Status</b></td> <td>{status}</td> </tr> <tr> <td><b>Encontrado em</b></td> <td>{first_observed}</td> </tr> <tr> <td><b>Última Observação</b></td> <td>{last_observed}</td> </tr> <tr> <td><b>Atualizado em</b></td> <td>{updated_at}</td> </tr> <tr> <th colspan="2">Detalhes da Instância EC2</th> </tr> <tr> <td><b>ID da Instância</b></td> <td>{instance_id}</td> </tr> <tr> <td><b>Nome da Instância</b></td> <td>{instance_name}</td> </tr> <tr> <td><b>Perfil IAM</b></td> <td>{instance_profile}</td> </tr> <tr> <td><b>ID da Imagem</b></td> <td>{image_id}</td> </tr> <tr> <td><b>Endereços IPv4</b></td> <td>{ipv4_addresses}</td> </tr> <tr> <td><b>Plataforma</b></td> <td>{platform}</td> </tr> <tr> <td><b>Tipo da Instância</b></td> <td>{instance_type}</td> </tr> </table> <p>Para mais informações, acesse o painel do AWS Inspector.</p>
</body>
</html>
""" return email_body def build_ecr_email_body(repository_name, title, description, image_digest, image_tags, pushed_at, architecture, platform, severity, status, finding_arn, first_observed, last_observed, updated_at, vulnerability_id): # Função para construir o corpo do email para eventos de ECR
email_body = f"""
<html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Alerta de Segurança - Empresa XPTO PCI-DSS</title> <style> body {{ font-family: Arial, sans-serif; line-height: 1.6; margin: 20px; background-color: #f5f5f5; }} h2 {{ background-color: #333; color: #fff; padding: 10px; border-radius: 5px 5px 0 0; margin-top: 0; }} p {{ margin-bottom: 20px; color: #555; padding: 0 10px; }} table {{ width: 100%; border-collapse: collapse; border: 1px solid #ddd; border-radius: 5px; margin-top: 20px; }} th, td {{ padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }} th {{ background-color: #f2f2f2; color: #333; font-weight: bold; }} tr:nth-child(even) {{ background-color: #f9f9f9; }} td:first-child, th:first-child {{ width: 30%; min-width: 120px; font-weight: bold; }} </style>
</head>
<body> <h2>Alerta de Segurança - Empresa XPTO PCI-DSS</h2> <p>Recebemos uma nova notificação de vulnerabilidade no AWS Inspector:</p> <table> <tr> <th colspan="2">Detalhes da Vulnerabilidade</th> </tr> <tr> <td><b>Título</b></td> <td>{title}</td> </tr> <tr> <td><b>Descrição</b></td> <td>{description}</td> </tr> <tr> <td><b>ID da Vulnerabilidade</b></td> <td>{vulnerability_id}</td> </tr> <tr> <td><b>Severidade</b></td> <td>{severity}</td> </tr> <tr> <td><b>Status</b></td> <td>{status}</td> </tr> <tr> <td><b>Encontrado em</b></td> <td>{first_observed}</td> </tr> <tr> <td><b>Última Observação</b></td> <td>{last_observed}</td> </tr> <tr> <td><b>Atualizado em</b></td> <td>{updated_at}</td> </tr> <tr> <th colspan="2">Detalhes da Imagem no ECR</th> </tr> <tr> <td><b>Nome do Repositório</b></td> <td>{repository_name}</td> </tr> <tr> <td><b>Digest da Imagem</b></td> <td>{image_digest}</td> </tr> <tr> <td><b>Tags da Imagem</b></td> <td>{image_tags}</td> </tr> <tr> <td><b>Arquitetura</b></td> <td>{architecture}</td> </tr> <tr> <td><b>Plataforma</b></td> <td>{platform}</td> </tr> <tr> <td><b>Enviado em</b></td> <td>{pushed_at}</td> </tr> </table> <p>Para mais informações, acesse o painel do AWS Inspector.</p>
</body>
</html>
""" return email_body
Teste de eventos:
Um teste para ser feito para EC2:
{ "Records": [ { "EventSource": "aws:sns", "EventVersion": "1.0", "EventSubscriptionArn": "arn:aws:sns:sa-east-1:530929948444:AWS-CVE-Inspector:d07cd6d8-2f8d-40c9-af6a-ecc4266e0e70", "Sns": { "Type": "Notification", "MessageId": "175a2902-7430-5515-bc29-7613ec172f9f", "TopicArn": "arn:aws:sns:sa-east-1:530929948444:AWS-CVE-Inspector", "Subject": null, "Message": "{\"version\":\"0\",\"id\":\"e7b5cb0b-b7b1-6390-fdcf-4ba7c5cf572d\",\"detail-type\":\"Inspector2 Finding\",\"source\":\"aws.inspector2\",\"account\":\"530929948444\",\"time\":\"2024-07-17T09:58:46Z\",\"region\":\"sa-east-1\",\"resources\":[\"i-09cc55700f9369d04\"],\"detail\":{\"awsAccountId\":\"530929948444\",\"description\":\"In the Linux kernel, the following vulnerability has been resolved: usb: udc: remove warning when queue disabled ep It is possible trigger below warning message from mass storage function, WARNING: CPU: 6 PID: 3839 at drivers/usb/gadget/udc/core.c:294 usb_ep_queue+0x7c/0x104 pc : usb_ep_queue+0x7c/0x104 lr : fsg_main_thread+0x494/0x1b3c Root cause is mass storage function try to queue request from main thread, but other thread may already disable ep when function disable. As there is no function failure in the driver, in order to avoid effort to fix warning, change WARN_ON_ONCE() in usb_ep_queue() to pr_debug().\",\"epss\":{\"score\":4.4E-4},\"exploitAvailable\":\"NO\",\"findingArn\":\"arn:aws:inspector2:sa-east-1:530929948444:finding/7c4806a9e2c4b7230d865d1c96d20b11\",\"firstObservedAt\":\"Tue Jul 16 21:45:59.629 UTC 2024\",\"fixAvailable\":\"YES\",\"lastObservedAt\":\"Tue Jul 16 21:45:59.629 UTC 2024\",\"packageVulnerabilityDetails\":{\"cvss\":[],\"referenceUrls\":[\"https://git.kernel.org/linus/2a587a035214fa1b5ef598aea0b81848c5b72e5e(6.9-rc2)\",\"https://ubuntu.com/security/notices/USN-6817-3\",\"https://git.kernel.org/stable/c/df5cbb908f1687e8ab97e222a16b7890d5501acf\",\"https://git.kernel.org/stable/c/99731076722eb7ed26b0c87c879da7bb71d24290\",\"https://git.kernel.org/stable/c/2b002c308e184feeaeb72987bca3f1b11e5f70b8\",\"https://git.kernel.org/stable/c/68d951880d0c52c7f13dcefb5501b69b8605ce8c\",\"https://ubuntu.com/security/notices/USN-6878-1\",\"https://git.kernel.org/stable/c/30511676eb54d480d014352bf784f02577a10252\",\"https://ubuntu.com/security/notices/USN-6816-1\",\"https://ubuntu.com/security/notices/USN-6817-2\",\"https://ubuntu.com/security/notices/USN-6817-1\",\"https://www.cve.org/CVERecord?id=CVE-2024-35822\",\"https://ubuntu.com/security/notices/USN-6896-1\",\"https://ubuntu.com/security/notices/USN-6898-1\",\"https://git.kernel.org/stable/c/3e944ddc17c042945d983e006df7860687a8849a\",\"https://git.kernel.org/stable/c/f74c5e0b54b02706d9a862ac6cddade30ac86bcf\",\"https://git.kernel.org/stable/c/2a587a035214fa1b5ef598aea0b81848c5b72e5e\",\"https://git.kernel.org/stable/c/36177c2595df12225b95ce74eb1ac77b43d5a58c\"],\"relatedVulnerabilities\":[\"USN-6816-1\",\"USN-6817-1\",\"USN-6817-2\",\"USN-6817-3\",\"USN-6896-1\",\"USN-6898-1\",\"USN-6878-1\"],\"source\":\"UBUNTU_CVE\",\"sourceUrl\":\"https://people.canonical.com/~ubuntu-security/cve/2024/CVE-2024-35822.html\",\"vendorCreatedAt\":\"Fri May 17 14:15:00.000 UTC 2024\",\"vendorSeverity\":\"medium\",\"vulnerabilityId\":\"CVE-2024-35822\",\"vulnerablePackages\":[{\"arch\":\"X86_64\",\"epoch\":0,\"fixedInVersion\":\"0:5.15.0-116.126\",\"name\":\"linux-libc-dev\",\"packageManager\":\"OS\",\"release\":\"113.123\",\"remediation\":\"apt-get update && apt-get upgrade\",\"version\":\"5.15.0\"}]},\"remediation\":{\"recommendation\":{\"text\":\"None Provided\"}},\"resources\":[{\"details\":{\"awsEc2Instance\":{\"iamInstanceProfileArn\":\"arn:aws:iam::530929948444:instance-profile/ScoutSuite\",\"imageId\":\"ami-0228d19e5bf7dc391\",\"ipV4Addresses\":[\"172.30.0.243\"],\"ipV6Addresses\":[],\"keyName\":\"Empresa_lnx_sec\",\"launchedAt\":\"Tue Oct 03 03:48:54.000 UTC 2023\",\"platform\":\"UBUNTU_22_04\",\"subnetId\":\"subnet-0cf6115b2cf95ddf8\",\"type\":\"c6a.xlarge\",\"vpcId\":\"vpc-00a09194848c6e5d6\"}},\"id\":\"i-09cc55700f9369d04\",\"partition\":\"aws\",\"region\":\"sa-east-1\",\"tags\":{\"BackupEC2\":\"true\",\"Name\":\"SRV-LNX-SEC\"},\"type\":\"AWS_EC2_INSTANCE\"}],\"severity\":\"MEDIUM\",\"status\":\"CLOSED\",\"title\":\"CVE-2024-35822 - linux-libc-dev\",\"type\":\"PACKAGE_VULNERABILITY\",\"updatedAt\":\"Wed Jul 17 09:58:46.559 UTC 2024\"}}", "Timestamp": "2024-07-17T09:59:03.737Z", "SignatureVersion": "1", "Signature": "nVpeMS7rnD1WUTmp04BwMC64Dp1Db9WagxLI+Lzlray1YTnpEtgezAoguYJY4DnPrTsouX67vq7plVEnWj5oxeTDR+GFlSCGDlzM/pQf5AO8haAuWuFWatTYudcwdma9cNnSMzmVyQ8Kqn4tJOudvPaIneuL20uxstvdLYVBb/9TznCBY2N+YBwv4BLGZEcqnY35Vf6TeDcSZInSk90z8f/9tXUdFtgHo7WuMzWAX6Eoen70XE3e1SLwE6gSTSa+mSFzCfD8Tj2n+SXQB9wE/ZTLR7UBEFmdjkvmJ2WgE810JUKFRzFFH7cWLp3gyRcXhXH5G1bTsFmc1R4Jo/ZAaQ==", "SigningCertUrl": "https://sns.sa-east-1.amazonaws.com/SimpleNotificationService-60eadc530605d63b8e62a523676ef735.pem", "UnsubscribeUrl": "https://sns.sa-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:sa-east-1:530929948444:AWS-CVE-Inspector:d07cd6d8-2f8d-40c9-af6a-ecc4266e0e70", "MessageAttributes": {} } } ]
}
Um teste para ser feito para ECR:
{ "Records": [ { "Sns": { "Message": "{\"detail\":{\"title\":\"High Vulnerability in ECR Image\",\"description\":\"A high severity vulnerability was detected in the container image.\",\"severity\":\"HIGH\",\"status\":\"ACTIVE\",\"findingArn\":\"arn:aws:inspector:us-east-1:123456789012:finding/finding-id\",\"firstObservedAt\":\"2024-07-16T10:00:00Z\",\"lastObservedAt\":\"2024-07-16T10:00:00Z\",\"updatedAt\":\"2024-07-16T10:00:00Z\",\"packageVulnerabilityDetails\":{\"vulnerabilityId\":\"CVE-2024-1234\"},\"resources\":[{\"type\":\"AWS_ECR_CONTAINER_IMAGE\",\"id\":\"arn:aws:ecr:us-east-1:123456789012:repository/my-repository\",\"details\":{\"awsEcrContainerImage\":{\"repositoryName\":\"my-repository\",\"imageDigest\":\"sha256:example1234\",\"imageTags\":[\"latest\"],\"pushedAt\":\"2024-07-15T10:00:00Z\",\"architecture\":\"amd64\",\"platform\":\"linux\"}}}]}}" } } ]
}
Notificações:
Exemplo de email fake EC2 enviado para a caixa de email
Exemplo de email fake ECR enviado para a caixa de email
Explicação do Código:
- A função lambda_handler é o ponto de entrada da Lambda, que recebe eventos do SNS.
- Os detalhes da vulnerabilidade são extraídos da mensagem JSON recebida.
- Detalhes específicos da instância EC2 ou ECR são recuperados usando o cliente EC2 ou ECR.
- Um email é construído em HTML para fornecer informações detalhadas sobre a vulnerabilidade e a instância.
- O email é enviado usando o cliente SES da AWS.