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

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

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

Esse procedimento demonstra como usar AWS Lambda para escutar na Amazon EventBridge, criar notificações com o Amazon Simple Notification Service (SNS) e publicar descobertas AWS Security Hub, fornecendo visibilidade aos administradores e equipes de segurança.

Para configurar uma função do Lambda e uma função do IAM
  1. Primeiro, configure uma função AWS Identity and Access Management (IAM) e defina as permissões necessárias para a função 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 é recomendável executar a maioria das AWS operações diretamente em uma conta de usuário e, especialmente, em uma conta de administrador.

    Abra o console 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 sua própria região e detalhes AWS da conta. Para obter mais informações, consulte Criação de políticas na guia JSON.

    { "Version":"2012-10-17", "Statement":[ { "Sid":"LambdaCertificateExpiryPolicy1", "Effect":"Allow", "Action":"logs:CreateLogGroup", "Resource":"arn:aws:logs:<region>:<AWS-ACCT-NUMBER>:*" }, { "Sid":"LambdaCertificateExpiryPolicy2", "Effect":"Allow", "Action":[ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource":[ "arn:aws:logs:<region>:<AWS-ACCT-NUMBER>: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 informações sobre como criar uma função do IAM e anexar uma política, consulte Criação de uma função para um AWS serviço (console).

  4. Abra o AWS Lambda console 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 "handle-expiring-certificates" no campo 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 em uma região diferente. 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 expirado no momento em que o evento é gerado pela 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. (Esse período pode ser personalizado usando a PutAccountConfigurationoperação 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 EventBridge regra da Amazon para acionar a função Lambda. Para obter mais informações, consulte Criação de EventBridge regras da Amazon que reagem a eventos.

    No EventBridge console da Amazon em https://console.aws.amazon.com/events/, navegue até a página Eventos > Regras e escolha 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

  • CloudWatch Regra de eventos

  • CloudWatch Registros associados ao Lambda

  • Tópico do SNS