AWS Inspector – Notificação CVE – EC2 e ECR

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.

Image description


Passos:

  1. 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.
  2. 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:

Image description

{ "source": ["aws.inspector2"], "detail-type": ["Inspector2 Finding"], "detail": { "severity": ["HIGH", "MEDIUM", "CRITICAL"], "status": ["ACTIVE", "CLOSED", "SUPRESSED"] }
}
Enter fullscreen mode
Exit fullscreen mode

Image description

  • Configure a função lambda para ser acionada por novas mensagens no tópico SNS.
    Image description

Variáveis de ambiente:
Image description


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
Enter fullscreen mode
Exit fullscreen mode

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": {} } } ]
}
Enter fullscreen mode
Exit fullscreen mode

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\"}}}]}}" } } ]
}
Enter fullscreen mode
Exit fullscreen mode

Notificações:

Exemplo de email fake EC2 enviado para a caixa de email
Image description

Exemplo de email fake ECR enviado para a caixa de email
Image description


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.

Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment

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

Discover more from Coursity

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top