Automação do gerenciamento de certificados Let's Encrypt SSL usando o desafio DNS-01 e AWS

A postagem descreve etapas para automatizar o gerenciamento de certificados SSL de Vamos criptografar CA usando Desafio DNS-01 и AWS.

acme-dns-route53 é uma ferramenta que nos permitirá implementar esse recurso. Ele pode funcionar com certificados SSL do Let's Encrypt, salvá-los no Amazon Certificate Manager, usar a API Route53 para implementar o desafio DNS-01 e, por fim, enviar notificações push para SNS. EM acme-dns-route53 Também há funcionalidade integrada para uso no AWS Lambda, e é disso que precisamos.

Este artigo está dividido em 4 seções:

  • criando um arquivo zip;
  • criando uma função IAM;
  • criando uma função lambda que executa acme-dns-route53;
  • criar um timer CloudWatch que acione uma função 2 vezes ao dia;

Observação: Antes de começar você precisa instalar GoLang 1.9+ и CLI da AWS

Criando um arquivo zip

acme-dns-route53 é escrito em GoLang e suporta versão não inferior a 1.9.

Precisamos criar um arquivo zip com um binário acme-dns-route53 dentro. Para fazer isso você precisa instalar acme-dns-route53 do repositório GitHub usando o comando go install:

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

O binário está instalado em $GOPATH/bin diretório. Observe que durante a instalação especificamos dois ambientes alterados: GOOS=linux и GOARCH=amd64. Eles deixam claro para o compilador Go que ele precisa criar um binário adequado para o sistema operacional Linux e a arquitetura amd64 - é isso que roda na AWS.
A AWS espera que nosso programa seja implantado em um arquivo zip, então vamos criar acme-dns-route53.zip arquivo que conterá o binário recém-instalado:

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

Observação: O binário deve estar na raiz do arquivo zip. Para isso usamos -j bandeira.

Agora que nosso apelido zip está pronto para implantação, resta apenas criar uma função com os direitos necessários.

Criando uma função do IAM

Precisamos configurar uma função IAM com os direitos exigidos pelo nosso lambda durante sua execução.
Vamos chamar esta política lambda-acme-dns-route53-executor e imediatamente dar a ela um papel básico AWSLambdaBasicExecutionRole. Isso permitirá que nosso lambda execute e grave logs no serviço AWS CloudWatch.
Primeiro, criamos um arquivo JSON que descreve nossos direitos. Isso essencialmente permitirá que os serviços lambda usem a função lambda-acme-dns-route53-executor:

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

O conteúdo do nosso arquivo é o seguinte:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup"
            ],
            "Resource": "arn:aws:logs:<AWS_REGION>:<AWS_ACCOUNT_ID>:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogStream"
            ],
            "Resource": "arn:aws:logs:<AWS_REGION>:<AWS_ACCOUNT_ID>: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}:<AWS_ACCOUNT_ID>:<TOPIC_NAME>",
                "arn:aws:route53:::hostedzone/*",
                "arn:aws:route53:::change/*",
                "arn:aws:acm:<AWS_REGION>:<AWS_ACCOUNT_ID>:certificate/*"
            ]
        }
    ]
}

Agora vamos executar o comando aws iam create-role para criar uma função:

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

Observação: lembre-se do ARN da política (Amazon Resource Name) - precisaremos dele nas próximas etapas.

Papel lambda-acme-dns-route53-executor criado, agora precisamos especificar permissões para ele. A maneira mais fácil de fazer isso é usar o comando aws iam attach-role-policypassando o ARN da política AWSLambdaBasicExecutionRole da seguinte maneira:

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

Observação: uma lista com outras políticas pode ser encontrada aqui.

Criando uma função lambda que é executada acme-dns-route53

Viva! Agora você pode implantar nossa função na AWS usando o comando aws lambda create-function. O lambda deve ser configurado usando as seguintes variáveis ​​de ambiente:

  • AWS_LAMBDA - deixa claro acme-dns-route53 essa execução ocorre dentro do AWS Lambda.
  • DOMAINS — uma lista de domínios separados por vírgulas.
  • LETSENCRYPT_EMAIL - contém Vamos criptografar e-mail.
  • NOTIFICATION_TOPIC — nome do tópico de notificação do SNS (opcional).
  • STAGING - pelo valor 1 ambiente de teste é usado.
  • 1024 MB - limite de memória, pode ser alterado.
  • 900 segundos (15 min) — tempo limite.
  • acme-dns-route53 — o nome do nosso binário, que está no arquivo.
  • fileb://~/acme-dns-route53.zip — o caminho para o arquivo que criamos.

Agora vamos implantar:

$ aws lambda create-function 
 --function-name acme-dns-route53 
 --runtime go1.x 
 --role arn:aws:iam::<AWS_ACCOUNT_ID>:role/lambda-acme-dns-route53-executor 
 --environment Variables="{AWS_LAMBDA=1,DOMAINS="example1.com,example2.com",[email protected],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": "[email protected]", 
            "NOTIFICATION_TOPIC": "acme-dns-route53-obtained", 
            "AWS_LAMBDA": "1"
         }
     }, 
     "Version": "$LATEST", 
     "Role": "arn:aws:iam::<AWS_ACCOUNT_ID>: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:<AWS_ACCOUNT_ID>:function:acme-dns-route53", 
     "Handler": "acme-dns-route53"
 }

Criando um timer CloudWatch que aciona uma função 2 vezes ao dia

A última etapa é configurar o cron, que chama nossa função duas vezes por dia:

  • crie uma regra do CloudWatch com o valor schedule_expression.
  • crie um destino de regra (o que deve ser executado) especificando o ARN da função lambda.
  • dê permissão à regra para chamar a função lambda.

Abaixo anexei minha configuração do Terraform, mas na verdade isso é feito de forma muito simples usando o console AWS ou 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}"
}

Agora você está configurado para criar e atualizar automaticamente certificados SSL

Fonte: habr.com

Adicionar um comentário