HTTPS com Golang no Linux

Um tutorial bem simples de como usar certificados HTTPS com Go

Gerando as chaves com letsencrypt.org

Como eu mencionei no post sobre redirecionar tudo para HTTPS todas as comunicações entre cliente e servidor precisam ser criptografadas e com letsencrypt.org isso pode ser feito sem custo, com código aberto e muita documentação, o que no meu ponto de vista acaba com todas as desculpas para não usar HTTPS.

Uma ressalva importante é que podem haver razões legais para preferir usar outra entidade certificadora, por exemplo se eu não estou enganado para ter valor legal no Brasil a entidade precisa ser brasileira. Claro que isso só importa se você estiver querendo processar alguém, eu estou interessado apenas na segurança.

Chega de papo, lets encrypt! :)

Instale o certbot

Você vai precisar rodar esses comandos no servidor que esta respondendo pelo seu domínio e também vai precisar de acesso root para instalar o certificado e as dependências.

Primeiro baixe o certbot do GitHub.

git clone https://github.com/certbot/certbot

Vamos usar o certbot para criar os certificados e também para fazer renew quando for necessário, então mova o diretório do certbot para onde você achar mais conveniente. Para efeito desse tutorial eu deixei o diretório em /root/certbot.

Entre no diretório do certboot “cd certbot” e vamos instalar as dependências. Meu servidor esta rodando Debian mas o sistema é compatível com todos os Linux populares.

Instalar as dependências é um passo que você pode pular tranquilamente, o certbot vai verificar elas para você quando for emitir os certificados, mas eu gosto de saber se esta tudo ok antes de continuar.

Instalando dependências

./certbot-auto --os-packages-only

Aceite a instalação dos pacotes requeridos e vamos prosseguir.

Gerando e instalando os certificados

Se algum sistema estiver ouvindo a porta 80, você precisa feche ele, o gerador do certificado vai usar essa porta.

E então basta executar o seguinte comando fazendo as devidas substituições:

./certbot-auto certonly --standalone --email voce@exemplo.com.br -d exemplo.com.br

Aceite os termos do letsencrypt.org e em poucos instantes os certificados estarão gerados e já nos diretórios apropriados, o certbot vai te avisar quais são esses diretórios mas provavelmente vai ser algo como /etc/letsencrypt/live/exemplo.com.br/

Preparando scripts para renew

De tempos em tempos os certificados precisam ser renovados e você pode deixar essa tarefa automatizada usando cron facilmente.

Esse é um exemplo de comando para você colocar no cron:

/root/certbot/certbot-auto renew --standalone \
--pre-hook "/root/redirect/stop.sh" \
--post-hook "/root/redirect/start.sh"

Os scripts nos parâmetros pre-hook e post-hook são bem simples, o stop.sh no meu caso apenas executa um killall redirectToHTTPS para derrubar o meu pequeno redirecionador e o start.sh simplesmente coloca ele no ar novamente. Assim a porta 80 fica livre para o certbot usar.

Eu recomendo parametrizar o cron para rodar essa linha duas vezes por dia nos horários de menor trafego, se ainda não estiver na data para fazer renew não se preocupe, o certbot simplesmente não vai fazer nada nem mesmo rodar os scripts de pre/post hook.

Agora finalmente vamos passar para o código em Go

package main

import (
    "io"
    "net/http"
    "log"
)

// lembre de substituir o nome do domínio pelo correto :D
const fullchain = "/etc/letsencrypt/live/exemplo.com.br/fullchain.pem"
const privkey = "/etc/letsencrypt/live/exemplo.com.br/privkey.pem"

func helloHandle(w http.ResponseWriter, req *http.Request) {
    io.WriteString(w, "Olá Mundo HTTPS!\n")
}

func main() {
    http.HandleFunc("/", helloHandle)

    err := http.ListenAndServeTLS(":443", fullchain, privkey, nil)
    if err != nil {
        log.Fatal("ListenAndServeTLS: ", err)
    }
}

É só isso, super simples não é?

Claro que você pode sofisticar muito mais o seu servidor, por exemplo no seu HTTP handler você pode colocar uma linha para mandar um header HSTS e avisar os navegadores que devem usar HTTP Strict Transport Security.

w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")

Tem um excelente artigo sobre outras alterações que você pode fazer escrito por Peter Lambert no blog.bracelab.com

Bonus!

Criando seus próprios certificados

Digamos que você não quer usar uma entidade certificadora nem nada disso, você quer simplesmente certificados de chave assíncrona para instalar no seu sistema e fazer testes locais.

Para gerar esses certificados use os seguintes comandos:

openssl ecparam -genkey -name secp384r1 -out server.key
openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650

Com isso você vai gerar os arquivos server.key e server.pem e para usar no nosso exemplo basta mudar as constantes da seguinte forma:

const fullchain = "server.pem"
const privkey = "server.key"

Importante!

Lembre que segurança não é um comando nem um programa, é um processo em que todos devem estar envolvidos. Nesse post usei vários comandos que e não detalhei todos os parâmetros e detalhes, não pare sua leitura aqui, leia a manpage do openssl e descubra o que faz cada parâmetro que usamos, leia outras fontes e aprenda o máximo possível, conhecimento é a única arma efetiva para tornar os sistemas seguros.

comments powered by Disqus