Respuesta a un evento con una función Lambda - AWS Certificate Manager

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Respuesta a un evento con una función Lambda

Este procedimiento muestra cómo AWS Lambda escuchar en Amazon EventBridge, crear notificaciones con Amazon Simple Notification Service (SNS) y publicar los resultados en Amazon, lo que proporciona visibilidad a AWS Security Hub los administradores y equipos de seguridad.

Para configurar una función Lambda y un rol de IAM
  1. En primer lugar, configure un rol AWS Identity and Access Management (de IAM) y defina los permisos que necesita la función Lambda. Esta práctica recomendada de seguridad brinda flexibilidad a la hora de designar quién tiene autorización para llamar a la función y de limitar los permisos concedidos a esa persona. No se recomienda ejecutar la mayoría de AWS las operaciones directamente con una cuenta de usuario y, especialmente, con una cuenta de administrador.

    Abra la consola de IAM en https://console.aws.amazon.com/iam/.

  2. Utilice el editor de políticas de JSON para crear la política definida en la siguiente plantilla. Proporcione su propia región y los detalles AWS de su cuenta. Para obtener más información, consulte Creación de políticas en la pestaña de 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. Cree un rol de IAM y adjúntele la política nueva. Para obtener información sobre cómo crear un rol de IAM y adjuntar una política, consulte Crear un rol para un AWS servicio (consola).

  4. Abra la AWS Lambda consola en https://console.aws.amazon.com/lambda/.

  5. Cree la función Lambda. Para obtener más información, consulte Crear una función Lambda con la consola. Realice los siguientes pasos:

    1. En la página Create function (Crear función), elija la opción Author from scratch (Crear desde cero) para crear la función.

    2. Especifique un nombre como «handle-expiring-certificates» en el campo Nombre de la función.

    3. En la lista Runtime (Tiempo de ejecución), elija Python 3.8.

    4. Expanda Change default execution role (Cambiar rol de ejecución predeterminado) y elija Use an existing role (Utilizar un rol existente).

    5. En la lista Existing role (Rol existente), elija el rol que creó antes.

    6. Elija Crear función.

    7. En Function code (Código de la función), inserte el siguiente 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. En Environment variables (Variables de entorno), elija Edit (Editar) y, opcionalmente, agregue las siguientes variables.

      • (Opcional) EXPIRY_DAYS

        Especifica el tiempo de espera, en días, antes de que se envíe el aviso de vencimiento del certificado. La función tiene un valor predeterminado de 45 días, pero puede especificar valores personalizados.

      • (Opcional) SNS_TOPIC_ARN

        Especifica un ARN para un Amazon SNS. Proporcione el ARN completo en el formato arn:aws:sns:<region>:<account-number>:<topic-name>.

      • (Opcional) SECURITY_HUB_REGION

        Especifica AWS Security Hub uno en una región diferente. Si no se especifica, se utiliza la región de la función Lambda en ejecución. Si la función se ejecuta en varias regiones, puede ser conveniente que todos los mensajes de certificado vayan a Security Hub en una sola región.

    9. En Basic settings (Configuración básica), establezca el valor Timeout (Tiempo de espera) en 30 segundos.

    10. En la parte superior de la página, elija Deploy (Implementar).

Complete las tareas del siguiente procedimiento para comenzar a utilizar esta solución.

Automatizar un aviso de vencimiento por correo electrónico

En este ejemplo, proporcionamos un solo correo electrónico para cada certificado que caduca en el momento en que Amazon EventBridge genera el evento. De forma predeterminada, cada día ACM genera un evento para un certificado al que le quedan 45 días o menos para vencer. (Este período se puede personalizar mediante el PutAccountConfigurationfuncionamiento de la API ACM). Cada uno de estos eventos activa la siguiente cadena de acciones 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. Cree la función Lambda y configure los permisos. (Ya se ha completado, consulte Para configurar una función Lambda y un rol de IAM).

  2. Cree un tema de SNS estándar para la función Lambda que se utilizará a fin de enviar notificaciones. Para obtener más información, consulte Creación de un tema de Amazon SNS.

  3. Suscriba las partes interesadas al tema de SNS nuevo. Para obtener más información, consulte Suscripción a un tema de Amazon SNS.

  4. Cree una EventBridge regla de Amazon para activar la función Lambda. Para obtener más información, consulta Cómo crear EventBridge reglas de Amazon que reaccionen a los eventos.

    En la EventBridge consola de Amazon, en https://console.aws.amazon.com/events/, dirígete a la página Eventos > Reglas y selecciona Crear regla. Especifique el Service Name (Nombre del servicio), Event Type (Tipo de evento) y Lambda function (Función Lambda). En el editor Event Pattern preview (Vista previa de patrón de eventos), pegue el siguiente código:

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

    Un evento como el que recibe Lambda se muestra en Show sample event(s) (Mostrar eventos de muestra):

    { "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" } }
Eliminación

Una vez que ya no necesite la configuración de ejemplo, o cualquier configuración, es una práctica recomendada eliminar todos los rastros de esta para evitar problemas de seguridad y cargos futuros inesperados:

  • Política y rol de IAM

  • Función de Lambda

  • CloudWatch Regla de eventos

  • CloudWatch Registros asociados a Lambda

  • Tema de SNS