Resposta a um evento com uma função do Lambda - AWS Certificate Manager

Resposta a um evento com uma função do Lambda

Este procedimento demonstra como usar o AWS Lambda para atender ao Amazon EventBridge, criar notificações com o Amazon Simple Notification Service (SNS) e publicar descobertas no AWS Security Hub CSPM, fornecendo visibilidade aos administradores e às equipes de segurança.

Para configurar uma função do Lambda e uma função do IAM
  1. Primeiro, configure uma função do AWS Identity and Access Management (IAM) e defina as permissões necessárias para a função do Lambda. Essa prática recomendada de segurança oferece flexibilidade na designação de quem tem autorização para chamar a função e na limitação das permissões concedidas a essa pessoa. Não é recomendado executar a maioria das operações do AWS diretamente em uma conta de usuário e, especialmente, não em uma conta de administrador.

    Abra o console do IAM, em https://console.aws.amazon.com/iam/.

  2. Use o editor de políticas JSON para criar a política definida no modelo abaixo. Forneça a sua própria região e detalhes da conta da AWS. Para obter mais informações, consulte Criação de políticas na guia JSON.

    JSON
    { "Version":"2012-10-17", "Statement": [ { "Sid": "LambdaCertificateExpiryPolicy1", "Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "arn:aws:logs:us-east-1:123456789012:*" }, { "Sid": "LambdaCertificateExpiryPolicy2", "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/handle-expiring-certificates:*" ] }, { "Sid": "LambdaCertificateExpiryPolicy3", "Effect": "Allow", "Action": [ "acm:DescribeCertificate", "acm:GetCertificate", "acm:ListCertificates", "acm:ListTagsForCertificate" ], "Resource": "*" }, { "Sid": "LambdaCertificateExpiryPolicy4", "Effect": "Allow", "Action": "SNS:Publish", "Resource": "*" }, { "Sid": "LambdaCertificateExpiryPolicy5", "Effect": "Allow", "Action": [ "SecurityHub:BatchImportFindings", "SecurityHub:BatchUpdateFindings", "SecurityHub:DescribeHub" ], "Resource": "*" }, { "Sid": "LambdaCertificateExpiryPolicy6", "Effect": "Allow", "Action": "cloudwatch:ListMetrics", "Resource": "*" } ] }
  3. Criar uma função do IAM e associar a ela a nova política. Para obter mais informações sobre como criar uma função do IAM e anexar uma política, consulte Criação de uma função para um serviço da AWS (console).

  4. Abra o console AWS Lambda em https://console.aws.amazon.com/lambda/.

  5. Criar a função do Lambda. Para obter mais informações, consulte Criar uma função do Lambda no console. Execute as etapas a seguir:

    1. Na página Create function (Criar função), selecione Author from scratch (Criar do zero).

    2. Especifique um nome como "lidar–expiração-certificados" no campo Function name (Nome da função).

    3. Na lista Runtime (Tempo de execução), escolha Python 3.8.

    4. Amplie Change default execution role (Alterar função de execução padrão) e escolha Use an existing role (Usar uma função existente).

    5. Na lista Existing role (Função existente), escolha a função criada acima.

    6. Escolha Create function (Criar função).

    7. Em Function code (Código da função), cole o seguinte código:

      # Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 # # Permission is hereby granted, free of charge, to any person obtaining a copy of this # software and associated documentation files (the "Software"), to deal in the Software # without restriction, including without limitation the rights to use, copy, modify, # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import json import boto3 import os from datetime import datetime, timedelta, timezone # ------------------------------------------- # setup global data # ------------------------------------------- utc = timezone.utc # make today timezone aware today = datetime.now().replace(tzinfo=utc) # set up time window for alert - default to 45 if its missing if os.environ.get('EXPIRY_DAYS') is None: expiry_days = 45 else: expiry_days = int(os.environ['EXPIRY_DAYS']) expiry_window = today + timedelta(days = expiry_days) def lambda_handler(event, context): # if this is coming from the ACM event, its for a single certificate if (event['detail-type'] == "ACM Certificate Approaching Expiration"): response = handle_single_cert(event, context.invoked_function_arn) return { 'statusCode': 200, 'body': response } def handle_single_cert(event, context_arn): cert_client = boto3.client('acm') cert_details = cert_client.describe_certificate(CertificateArn=event['resources'][0]) result = 'The following certificate is expiring within ' + str(expiry_days) + ' days: ' + cert_details['Certificate']['DomainName'] # check the expiry window before logging to Security Hub and sending an SNS if cert_details['Certificate']['NotAfter'] < expiry_window: # This call is the text going into the SNS notification result = result + ' (' + cert_details['Certificate']['CertificateArn'] + ') ' # this call is publishing to SH result = result + ' - ' + log_finding_to_sh(event, cert_details, context_arn) # if there's an SNS topic, publish a notification to it if os.environ.get('SNS_TOPIC_ARN') is None: response = result else: sns_client = boto3.client('sns') response = sns_client.publish(TopicArn=os.environ['SNS_TOPIC_ARN'], Message=result, Subject='Certificate Expiration Notification') return result def log_finding_to_sh(event, cert_details, context_arn): # setup for security hub sh_region = get_sh_region(event['region']) sh_hub_arn = "arn:aws:securityhub:{0}:{1}:hub/default".format(sh_region, event['account']) sh_product_arn = "arn:aws:securityhub:{0}:{1}:product/{1}/default".format(sh_region, event['account']) # check if security hub is enabled, and if the hub arn exists sh_client = boto3.client('securityhub', region_name = sh_region) try: sh_enabled = sh_client.describe_hub(HubArn = sh_hub_arn) # the previous command throws an error indicating the hub doesn't exist or lambda doesn't have rights to it so we'll stop attempting to use it except Exception as error: sh_enabled = None print ('Default Security Hub product doesn\'t exist') response = 'Security Hub disabled' # This is used to generate the URL to the cert in the Security Hub Findings to link directly to it cert_id = right(cert_details['Certificate']['CertificateArn'], 36) if sh_enabled: # set up a new findings list new_findings = [] # add expiring certificate to the new findings list new_findings.append({ "SchemaVersion": "2018-10-08", "Id": cert_id, "ProductArn": sh_product_arn, "GeneratorId": context_arn, "AwsAccountId": event['account'], "Types": [ "Software and Configuration Checks/AWS Config Analysis" ], "CreatedAt": event['time'], "UpdatedAt": event['time'], "Severity": { "Original": '89.0', "Label": 'HIGH' }, "Title": 'Certificate expiration', "Description": 'cert expiry', 'Remediation': { 'Recommendation': { 'Text': 'A new certificate for ' + cert_details['Certificate']['DomainName'] + ' should be imported to replace the existing imported certificate before expiration', 'Url': "https://console.aws.amazon.com/acm/home?region=" + event['region'] + "#/?id=" + cert_id } }, 'Resources': [ { 'Id': event['id'], 'Type': 'ACM Certificate', 'Partition': 'aws', 'Region': event['region'] } ], 'Compliance': {'Status': 'WARNING'} }) # push any new findings to security hub if new_findings: try: response = sh_client.batch_import_findings(Findings=new_findings) if response['FailedCount'] > 0: print("Failed to import {} findings".format(response['FailedCount'])) except Exception as error: print("Error: ", error) raise return json.dumps(response) # function to setup the sh region def get_sh_region(event_region): # security hub findings may need to go to a different region so set that here if os.environ.get('SECURITY_HUB_REGION') is None: sh_region_local = event_region else: sh_region_local = os.environ['SECURITY_HUB_REGION'] return sh_region_local # quick function to trim off right side of a string def right(value, count): # To get right part of string, use negative first index in slice. return value[-count:]
    8. Em Environment variables (Variáveis de ambiente), escolha Edit (Editar) e, opcionalmente, adicione as seguintes variáveis.

      • (Opcional) EXPIRY_DAY

        Especifica quanto tempo antes, em dias, será enviado o aviso de expiração de validade do certificado. O padrão da função é 45 dias, mas você pode especificar valores personalizados.

      • (Opcional) SNS_TOPIC_ARN

        Especifica um ARN para um Amazon SNS. Forneça o ARN completo no formato arn:aws:sns:<região>:<número-conta>:<nome-tópico>.

      • (Opcional) SECURITY_HUB_REGION

        Especifica um AWS Security Hub CSPM em outra região. Se isso não for especificado, a região da função Lambda em execução será usada. Se a função for executada em várias regiões, é melhor que todas as mensagens de certificado sejam enviadas para o Security Hub em uma única região.

    9. Em Basic settings (Configurações básicas), defina o valor Timeout (Tempo limite) como 30 segundos.

    10. Na parte superior da página, escolha Deploy (Implantar).

Conclua as tarefas do procedimento a seguir para começar a usar essa solução.

Para automatizar um aviso de expiração de validade por e-mail

Neste exemplo, fornecemos um único e-mail para cada certificado cuja validade está expirando no momento em que o evento é gerado por meio do Amazon EventBridge. Por padrão, o ACM gera um evento por dia para um certificado a 45 dias ou menos da expiração da validade. (Este período pode ser personalizado usando a operação PutAccountConfiguration da API do ACM.) Cada um desses eventos dispara a seguinte cascata de ações automatizadas:

ACM raises Amazon EventBridge event → >>>>>>> events Event matches Amazon EventBridge rule → Rule calls Lambda function → Function sends SNS email and logs a Finding in Security Hub
  1. Criar a função do Lambda e configurar permissões. (Já concluído – consulte Para configurar uma função do Lambda e uma função do IAM).

  2. Criar um tópico padrão do SNS para a função do Lambda usar para enviar notificações. Para obter mais informações, consulte Criação de um tópico do Amazon SNS.

  3. Inscreva todas as partes interessadas no novo tópico SNS. Para obter mais informações, consulte Assinatura de um tópico do Amazon SNS.

  4. Crie uma regra do Amazon EventBridge para acionar a função do Lambda. Para obter mais informações, consulte Creating Amazon EventBridge rules that react to events (Criar regras do Amazon EventBridge que reagem a eventos).

    No console do Amazon EventBridge, em https://console.aws.amazon.com/events/, navegue até a página Events > Rules ([Eventos] > [Regras]) e escolha Create rule (Criar regra). Especifique o nome do serviço, o tipo de evento, e a função do Lambda. No editor Event Pattern preview (Previsualização do padrão de evento), cole o seguinte código:

    { "source": [ "aws.acm" ], "detail-type": [ "ACM Certificate Approaching Expiration" ] }

    Um evento como o que o Lambda recebe é exibido em Show sample event(s) (Mostrar exemplo de evento (s)):

    { "version": "0", "id": "9c95e8e4-96a4-ef3f-b739-b6aa5b193afb", "detail-type": "ACM Certificate Approaching Expiration", "source": "aws.acm", "account": "123456789012", "time": "2020-09-30T06:51:08Z", "region": "us-east-1", "resources": [ "arn:aws:acm:us-east-1:123456789012:certificate/61f50cd4-45b9-4259-b049-d0a53682fa4b" ], "detail": { "DaysToExpiry": 31, "CommonName": "My Awesome Service" } }
Para limpar

Quando você não precisar mais do exemplo de configuração, ou de qualquer configuração, é uma prática recomendada remover todos os traços para evitar problemas de segurança e cobranças futuras inesperadas:

  • Política e função do IAM

  • Função do Lambda

  • Regra do CloudWatch Events

  • CloudWatch Logs associados ao Lambda

  • Tópico do SNS