Automatización de la gestión de certificados SSL de Let's Encrypt utilizando el desafío DNS-01 y AWS

La publicación describe los pasos para automatizar la gestión de certificados SSL de Let’s Encrypt CA usando desafío DNS-01 y AWS.

acme-dns-route53 — es una herramienta que nos permitirá implementar esta función. Puede trabajar con certificados SSL de Let’s Encrypt, almacenarlos en Amazon Certificate Manager, utilizar la API de Route53 para realizar el desafío DNS-01 y, al final, enviar notificaciones a SNS. Además, acme-dns-route53 también cuenta con funcionalidad incorporada para ser utilizada dentro de AWS Lambda, y eso es exactamente lo que necesitamos.

Este artículo se divide en 4 secciones:

  • creación de un archivo zip;
  • creación de un rol IAM;
  • creación de una función Lambda que ejecuta acme-dns-route53;
  • creación de un temporizador de CloudWatch que activa la función 2 veces al día;

Nota: antes de empezar, es necesario instalar GoLang 1.9+ y AWS CLI

Creación de un archivo zip

acme-dns-route53 está escrito en GoLang y soporta versiones no inferiores a 1.9.

Necesitamos crear un archivo zip con el binario acme-dns-route53 en su interior. Para ello, es necesario instalarlo acme-dns-route53 desde el repositorio de GitHub utilizando el comando go install:

$ env GOOS=linux GOARCH=amd64 go install github.com/begmaroman/acme-dns-route53

El binario se instala en la $GOPATH/bin directorio. Tenga en cuenta que al instalar, especificamos dos variables de entorno: GOOS=linux y GOARCH=amd64. Estas le indican al compilador de Go que necesita crear un binario adecuado para el sistema operativo Linux y la arquitectura amd64 — esto es lo que se ejecuta en AWS.
AWS prevé que despleguemos nuestro programa en un archivo zip, así que vamos a crear acme-dns-route53.zip un archivo que contendrá el binario que acabamos de instalar:

$ zip -j ~/acme-dns-route53.zip $GOPATH/bin/acme-dns-route53

Nota: el binario debe estar en la raíz del archivo zip. Para ello, usamos -j la opción flag.

Ahora nuestro zip está listo para el despliegue, solo queda crear un rol con los permisos necesarios.

Creación de un rol IAM

Necesitamos configurar un rol IAM con los permisos requeridos por nuestra Lambda durante su ejecución.
Llamemos a esta política lambda-acme-dns-route53-executor y le daremos inmediatamente un rol básico AWSLambdaBasicExecutionRole. Esto permitirá que nuestra Lambda se ejecute y registre logs en el servicio AWS CloudWatch.
Primero, creamos un archivo JSON en el que describimos nuestros permisos. Esto, en esencia, permitirá a los servicios Lambda utilizar el rol lambda-acme-dns-route53-executor:

$ touch ~/lambda-acme-dns-route53-executor-policy.json

El contenido de nuestro archivo es el siguiente:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup"
            ],
            "Resource": "arn:aws:logs:::*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogStream"
            ],
            "Resource": "arn:aws:logs:::log-group:/aws/lambda/acme-dns-route53:*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "cloudwatch:PutMetricData",
                "acm:ImportCertificate",
                "acm:ListCertificates"
            ],
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "sns:Publish",
                "route53:GetChange",
                "route53:ChangeResourceRecordSets",
                "acm:ImportCertificate",
                "acm:DescribeCertificate"
            ],
            "Resource": [
                "arn:aws:sns:${var.region}::",
                "arn:aws:route53:::hostedzone/*",
                "arn:aws:route53:::change/*",
                "arn:aws:acm:::certificate/*"
            ]
        }
    ]
}

Ahora vamos a ejecutar el comando aws iam create-role para crear el rol:

$ aws iam create-role --role-name lambda-acme-dns-route53-executor 
 --assume-role-policy-document ~/lambda-acme-dns-route53-executor-policy.json

Nota: recuerde el ARN de la política (Nombre de Recurso de Amazon) — lo necesitaremos en las siguientes etapas.

El rol lambda-acme-dns-route53-executor ha sido creado, ahora necesitamos especificar los permisos para él. La forma más sencilla de hacerlo es usar el comando aws iam attach-role-policy, pasando el ARN de la política AWSLambdaBasicExecutionRole de la siguiente manera:

$ aws iam attach-role-policy --role-name lambda-acme-dns-route53-executor 
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

Nota: puede encontrar la lista de otras políticas aquí.

Creación de la función Lambda que lanza acme-dns-route53

¡Genial! Ahora también podemos desplegar nuestra función en AWS usando el comando aws lambda create-function. La Lambda debe configurarse utilizando las siguientes variables de entorno:

  • AWS_LAMBDA — indica acme-dns-route53 que la ejecución ocurre dentro de AWS Lambda.
  • DOMAINS — lista de dominios, separados por comas.
  • LETSENCRYPT_EMAIL — contiene el correo electrónico de Let’s Encrypt..
  • NOTIFICATION_TOPIC — nombre del Tema de Notificación de SNS (opcional).
  • STAGING — cuando se establece como 1 se utiliza el entorno de pruebas.
  • 1024 MB — límite de memoria, que puede ser cambiado.
  • 900 secs (15 min) — tiempo de espera.
  • acme-dns-route53 — nombre de nuestro binario, que se encuentra en el archivo.
  • fileb://~/acme-dns-route53.zip — ruta al archivo, que hemos creado.

Ahora desplegamos:

$ aws lambda create-function 
 --function-name acme-dns-route53 
 --runtime go1.x 
 --role arn:aws:iam:::role/lambda-acme-dns-route53-executor 
 --environment Variables="{AWS_LAMBDA=1,DOMAINS="example1.com,example2.com",LETSENCRYPT_EMAIL=begmaroman@gmail.com,STAGING=0,NOTIFICATION_TOPIC=acme-dns-route53-obtained}" 
 --memory-size 1024 
 --timeout 900 
 --handler acme-dns-route53 
 --zip-file fileb://~/acme-dns-route53.zip

 {
     "FunctionName": "acme-dns-route53", 
     "LastModified": "2019-05-03T19:07:09.325+0000", 
     "RevisionId": "e3fadec9-2180-4bff-bb9a-999b1b71a558", 
     "MemorySize": 1024, 
     "Environment": {
         "Variables": {
            "DOMAINS": "example1.com,example2.com", 
            "STAGING": "1", 
            "LETSENCRYPT_EMAIL": "your@email.com", 
            "NOTIFICATION_TOPIC": "acme-dns-route53-obtained", 
            "AWS_LAMBDA": "1"
         }
     }, 
     "Version": "$LATEST", 
     "Role": "arn:aws:iam:::role/lambda-acme-dns-route53-executor", 
     "Timeout": 900, 
     "Runtime": "go1.x", 
     "TracingConfig": {
         "Mode": "PassThrough"
     }, 
     "CodeSha256": "+2KgE5mh5LGaOsni36pdmPP9O35wgZ6TbddspyaIXXw=", 
     "Description": "", 
     "CodeSize": 8456317,
"FunctionArn": "arn:aws:lambda:us-east-1::function:acme-dns-route53", 
     "Handler": "acme-dns-route53"
 }

Creación de un temporizador de CloudWatch que activa la función dos veces al día

El último paso es configurar un cron que llame a nuestra función dos veces al día:

  • crear una regla de CloudWatch con el valor schedule_expression.
  • crear un objetivo de la regla (lo que debe ejecutarse), especificando el ARN de la función Lambda.
  • dar permiso a la regla para invocar la función Lambda.

A continuación, adjunté mi configuración de Terraform, pero en realidad se hace muy fácilmente a través de la consola de AWS o de la AWS CLI.

# Cloudwatch event rule that runs acme-dns-route53 lambda every 12 hours
resource "aws_cloudwatch_event_rule" "acme_dns_route53_sheduler" {
  name                = "acme-dns-route53-issuer-scheduler"
  schedule_expression = "cron(0 */12 * * ? *)"
}

# Specify the lambda function to run
resource "aws_cloudwatch_event_target" "acme_dns_route53_sheduler_target" {
  rule = "${aws_cloudwatch_event_rule.acme_dns_route53_sheduler.name}"
  arn  = "${aws_lambda_function.acme_dns_route53.arn}"
}

# Give CloudWatch permission to invoke the function
resource "aws_lambda_permission" "permission" {
  action        = "lambda:InvokeFunction"
  function_name = "${aws_lambda_function.acme_dns_route53.function_name}"
  principal     = "events.amazonaws.com"
  source_arn    = "${aws_cloudwatch_event_rule.acme_dns_route53_sheduler.arn}"
}

Ahora también ustedes tienen configurada la creación automática y actualización de certificados SSL

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster