Na maioria das vezes, nao precisamos de nada alem do AWS Certificate Manager (ACM), mas em alguns casos, se voce esta hospedando o dominio do seu cliente com ALB e nao tem como obter um certificado SSL do seu cliente, voce precisa fazer uma solucao alternativa. Neste artigo, vamos emitir um Let's Encrypt SSL no AWS Application Load Balancer e automatizar o processo!

Quando voce solicita um certificado SSL do Let's Encrypt, o LE tem alguns metodos de verificacao, como web-challenge, route53, etc. Neste cenario, decidi usar web-challenge porque a gestao de DNS dos dominios nao esta comigo. Eu apenas hospedo a aplicacao e preciso emitir um SSL.

Quando voce solicita um SSL com web-challenge, o Let's Encrypt verifica o caminho https://domain.com/.well-known/acme-challenge para garantir e validar. O que isso significa? Significa que o Let's Encrypt enviara uma requisicao ao dominio na porta 80 e fara a verificacao. Hmm, precisamos fazer alguns ajustes na configuracao do nosso Load Balancer e precisamos de outro Target Group para redirecionar especificamente as requisicoes acme-challenge.

Passo 1: Execute uma nova EC2 e Crie um Novo Target Group

Clone o Repositorio

Escrevi um script bash para facilitar o gerenciamento e manter os padroes da mesma forma para cada dominio. Voce pode conferir meu repositorio GitHub ou clonar o repositorio no caminho /opt/ dentro de acme-challange-server

Dica: # git clone https://github.com/flightlesstux/alble.git

Instale nginx, Let's Encrypt e configure-os

Quando recebemos uma requisicao /.well-known/acme-challenge/*, a EC2 com nginx instalado vai lidar com todas as requisicoes acme-challenge e emitir um SSL para nos.

Instale nginx e configure para /.well-known/acme-challenge/

Voce pode instalar facilmente o nginx com o comando amazon-linux-extras install nginx1. Apos a instalacao, voce deve colocar um novo bloco location na configuracao raiz do nginx. O arquivo de configuracao raiz esta localizado em /etc/nginx/nginx.conf

        location /.well-known/acme-challenge {
           root /opt/alble/certbot-challange;
        }

O valor de server_name deve ser _; para todos os dominios. Nao podemos definir um nome DNS estatico.

Instale o Certbot com o modulo nginx

Primeiro, vamos instalar o certbot do repositorio epel e precisamos instalar o epel primeiro. Para instalacao do epel, voce pode usar o comando amazon-linux-extras install -y epel e depois executar yum install -y nginx certbot python2-certbot-nginx jq dig para cobrir os pre-requisitos.

Politica IAM Role para o Servidor acme-challenge

Este servidor acme-challenge tem uma IAM Role para acessar operacoes ACM e ALB com SSLs Let's Encrypt. Voce pode ver a Politica IAM abaixo.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AWSLEPolicy1",
            "Effect": "Allow",
            "Action": [
                "acm:DescribeCertificate",
                "acm:RemoveTagsFromCertificate",
                "acm:GetCertificate",
                "acm:AddTagsToCertificate",
                "acm:ListCertificates",
                "acm:ImportCertificate",
                "acm:ListTagsForCertificate"
            ],
            "Resource": "*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
                }
            }
        },
        {
            "Sid": "AWSLEPolicy2",
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:RemoveTags",
                "elasticloadbalancing:DescribeTags",
                "elasticloadbalancing:AddTags",
                "elasticloadbalancing:AddListenerCertificates"
            ],
            "Resource": "AWS::ALB::ARN",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
                }
            }
        },
        {
            "Sid": "AWSLEPolicy3",
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:DescribeSSLPolicies",
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:DescribeListenerCertificates"
            ],
            "Resource": "*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
                }
            }
        },
        {
            "Sid": "AWSLEPolicy4",
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:RemoveTags",
                "elasticloadbalancing:DescribeTags",
                "elasticloadbalancing:AddTags"
            ],
            "Resource": "AWS::ALB::ARN",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
                }
            }
        },
        {
            "Sid": "AWSLEPolicy5",
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:DescribeSSLPolicies",
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:AddListenerCertificates",
                "elasticloadbalancing:DescribeListenerCertificates"
            ],
            "Resource": "*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "acme-challenge-server-Elastic-IP/32"
                }
            }
        }
    ]
}

Voce pode anexar esta politica diretamente ao servidor acme-challenge sem nenhum problema de seguranca ou vazamento apos atribuir um Elastic IP a ele. Se voce quiser usar credenciais locais, tambem pode usar a mesma Politica IAM.

Crie um Novo Target Group

Apos a configuracao da instancia EC2, criei um Target Group com o nome acme-challenge e redireciono a requisicao para a EC2 com nginx instalado, com o nome acme-challange-server, e registro nosso acme-challenge-server como destino. Se tudo correr sem problemas, sua tela ficara como a abaixo.

Passo 2: Crie uma Regra de Listener no Application Load Balancer

Precisamos editar e criar uma nova regra de listener para aceitar e redirecionar as requisicoes /.well-known/acme-challenge/* para o Target Group acme-challenge. Quando voce fizer este passo, sua tela ficara como a abaixo.

Agora, estamos prontos para solicitar um Let's Encrypt SSL do ACME, emitir sem problemas, importar para o ACM e atribuir ao AWS ALB : ) Esta operacao contem tres passos diferentes para emissao.

  1. Solicitar um SSL do Let's Encrypt
  2. Importar o SSL solicitado se o dominio ou subdominio corresponder ao registro CNAME do AWS ALB
  3. Atribuir o certificado SSL importado ao AWS ALB para uso em producao

Vamos Emitir e Solicitar um Let's Encrypt SSL do ACME

Quando voce clonar o repositorio git, deve mover a pasta /opt/alble/renewal-hooks para o caminho /etc/letsencrypt/. Caso contrario, voce nao conseguira renovar o certificado no ACM e a seguranca sua e dos seus clientes sera comprometida. Voce pode copiar e colar mv /opt/alble/renewal-hooks /etc/letsencrypt/

Basta ler o arquivo README.md no repositorio git e escrever suas variaveis no arquivo env. Depois disso, voce pode facilmente executar/gerenciar/criar os certificados Let's Encrypt SSL no AWS Application Load Balancer. Recomendo usar AWS SSM para executar o comando no acme-challange-server para emitir um SSL. Para isso, voce deve adicionar a politica AmazonEC2RoleforSSM a sua IAM Role.

Decidi usar um subdominio para testes, mas nao importa. Voce tambem pode usar um dominio raiz. Meus dominios de teste sao awsle-1.ercanermis.com e awsle-2.ercanermis.com

Quando voce estiver no caminho /opt/alble/, pode executar o comando como ./create-new-site.sh awsle-1.ercanermis.com e vera a saida como abaixo.

Meu script ALBLe verifica primeiro o registro CNAME do dominio e/ou subdominio e garante antes de continuar. Se voce escrever um dominio/subdominio errado ou cometer um erro de digitacao, ele avisara via alertas do Slack. Alertas sao realmente importantes para automacao. Voce pode configurar Alertas do Slack no arquivo env. Aqui esta um exemplo se voce ja emitiu o Let's Encrypt SSL antes;

Producao

Meu nome DNS do AWS ALB e web-application-elb-1302305711.us-east-1.elb.amazonaws.com e posso acessa-lo via https://web-app.ercanermis.com. Ele usa AWS Certificate Manager para obter um SSL.

Meus dominios de teste sao https://awsle-1.ercanermis.com e https://awsle-2.ercanermis.com e eles estao usando Let's Encrypt com AWS Application Load Balancer, isso ai! : )

https://web-app.ercanermis.com esta usando SSL fornecido pela Amazon
https://awsle-1.ercanermis.com esta usando SSL fornecido pelo Let's Encrypt
https://awsle-2.ercanermis.com esta usando SSL fornecido pelo Let's Encrypt

Como ficam os Certificados SSL do AWS ALB e ACM?

Aqui esta a captura de tela dos Certificados SSL do ALB
Aqui esta a captura de tela no Amazon Certificate Manager

Espero que este artigo ajude voce! P.S. Nao esqueca de configurar um cron para solicitacoes de renovacao.
Codigo fonte: https://github.com/flightlesstux/alble/