Certificati X509 da LetsEncrypt utilizzando ACME

di | Novembre 28, 2024

Avevo necessità di attivare la comunicazione sicura, al mio blog. Ho riconfigurato quindi, il web server per esporre il servizio in HTTPS (HTTP Over SSL), fornendo l’identità digitale del dominio, firmata da un ente di certificazione, riconosciuto come tale.

In questo appunto, descriverò la procedura utilizzata per ottenere l’identità digitale certificata, in maniera tale che i visitatori possano fruire dei contenuti senza problemi, e contestualmente mettere in sicurezza il canale di amministrazione, sul quale viaggiano le mie credenziali di blogger.

Mi son rivolto quindi all’ente di certificazione LetsEncrypt, che fornisce il servizio di signing tramite protocollo acme (acronimo di Automatic Certificate Management Environment), grazie al quale potrò automatizzare l’intero ciclo di vita di certificato X509 (richiesta, revoca e rinnovo).

PASSO 1 : installare un acme client.

E’ necessario installare un acme client, sul server che eroga il servizio web. Nel mio caso ho usato l’implementazione acme-client, perchè già preinstallato in OpenBSD 7.x. Letsencrypt consiglia Certbot di EFF (Electronic Frontier Foundation), disponibile per sistemi GNU/Linux, BSD (OpenBSD, FreeBSD) ed altri.

PASSO 2 : configurare acme-client.

Ho creato un file di configurazione, partendo da un modello presente in /etc/examples

alfree$ cat /etc/examples/acme-client.conf                                                                                                                                                     
#
# $OpenBSD: acme-client.conf,v 1.4 2020/09/17 09:13:06 florian Exp $
#
authority letsencrypt {
        api url "https://acme-v02.api.letsencrypt.org/directory"
        account key "/etc/acme/letsencrypt-privkey.pem"
}

authority letsencrypt-staging {
        api url "https://acme-staging-v02.api.letsencrypt.org/directory"
        account key "/etc/acme/letsencrypt-staging-privkey.pem"
}

domain example.com {
        alternative names { secure.example.com }
        domain key "/etc/ssl/private/example.com.key"
        domain full chain certificate "/etc/ssl/example.com.fullchain.pem"
        sign with letsencrypt
}

Nei primi 2 blocchi son definite le Authority, ossia i canali per raggiungere il servizio di signing fornito. Letsencrypt-staging definisce l’ambiente di test, molto consigliato per effettuare tutte le prove preventive del caso, in maniera tale da non sovraccaricare l’Autority di produzione. Account key è un’identità temporanea, generata a run-time da acme-client per potersi autenticare a Letsencrypt.

Il blocco di domain definisce il dominio da certificare, in cui bisognerà specificare :

  • fqdn (e gli eventuali altervative names separati da virgola o spazi)
  • identità digitale (chiave privata, certificato richiesto etc.)
  • authority (tra quelle precedentemente definite) da contattare per il signing, revoca o rinnovo.

Non è necessario creare nessuno di questi file, ci penserà acme-client a gestire il tutto, noi dobbiamo occuparci semplicemente del file di configurazione.

Di seguito la mia versione del file di configurazione per acme-client, utilizzata per i primi test :

alfree$ cat /home/granito/ssl/letsencrypt/acme-client.conf                                                                                                                                                     
#
# $OpenBSD: acme-client.conf,v 1.4 2020/09/17 09:13:06 florian Exp $
#
authority letsencrypt {
        api url "https://acme-v02.api.letsencrypt.org/directory"
        account key "/home/granito/ssl/letsencrypt/letsencrypt-privkey.pem"
}

authority letsencrypt-staging {
        api url "https://acme-staging-v02.api.letsencrypt.org/directory"
        account key "/home/granito/ssl/letsencrypt/letsencrypt-staging-privkey.pem"
}

domain granito.org.uk {
        alternative names { www.granito.org.uk }
        domain key "/home/granito/ssl/letsencrypt/granito.org.uk.key"
        domain certificate "/home/granito/ssl/letsencrypt/granito.org.uk.crt"
        domain full chain certificate "/home/granito/ssl/letsencrypt/granito.org.uk.fullchain.pem"
        sign with letsencrypt-staging
}

Le impostazioni modificate le ho evidenziate. Essenzialmente ho posizionato tutti i file necessari: configurazione acme-client ed identità digitale (privata, certificato e chain) nella home directory dell’owner (/home/granito) che amministra il dominio (granito.org.uk). In questa prima fase invocherò il servizio di staging (sign with).

Passo 3: Creazione della directory acme-challenge.

E’ necessario infine creare la directory .well-known/acme-challenge al di sotto della document-root del webserver. In questa directory acme-client andrà a run-time a copiare un token generato da letsencrypt, e servirà a verificare che il richiedente sia attestato sul medesimo server collegato al nome di dominio (fqdn) da validare.
Sembra complicato ma in realtà il processo è molto semplice, l’unica difficoltà è la mia, nel cercare descrivere il tutto, senza impicciarmi troppo : – )

Passo 4: Richiesta di Signing (TEST/Staging)

Quindi il processo di richiesta di signing può o meno funzionerà così :

  • acme-client genera un’identità per l’autenticazione a letsencrypt (account key), con cui quest’ultimo lo identificherà e traccerà, valido per le successive richieste
  • acme-client invocherà il servizio di signing di letsencrypt puntanto all’endpoint specificato (sign with), fornendo l’account key per l’autenticazione.
  • letsencrypt per verificare che il richiedente sia realmente l’amministratore del dominio, genererà un token usa-e-getta che fornirà al client, chiamato challenge. Tale token-file verrà copiato da acme-client nella seguente directory $WEBSERVER_DOCUMENT_ROOT/.well-known/acme-challenge. Letsencrypt si aspetta di trovarlo, puntanto alla url https://granito.org.uk/.well-known/acme-challenge. Effettuerà la stessa verifica per ogni “Alternative Names” definito nel file di configurazione, quindi nel mio caso specifico si aspetterà di trovare il challenge anche alla url http://www.granito.org.uk/.well-known/acme-challenge/
  • acme-client a questo punto genererà la chiave privata e la richiesta di certificato, interstata al dominio specificato (domain). Invierà la richiesta di certificato alla CA Letsencrypt per il signing.
  • letsencrypt in risposta fornirà il certificato (richiesta di certificato, firmata)

A questo punto facciamo un test, continuando a puntare all’ambiente letsencrypt di staging :

(***Annotazione*** Non so perché ma alcune volte il processo di signing, si interrompe sulla verifica del token, oi rilanciandolo riprende dal punto in cui si è fermato).

alfree$ doas ./granito.org.uk_acme-client.sh
acme-client: /home/granito/ssl/letsencrypt/staging/granito.org.uk.key: generated RSA domain key
acme-client: /home/granito/ssl/letsencrypt/staging/letsencrypt-privkey.pem: generated RSA account key
acme-client: https://acme-staging-v02.api.letsencrypt.org/directory: directories
acme-client: acme-staging-v02.api.letsencrypt.org: DNS: 172.65.46.172
acme-client: acme-staging-v02.api.letsencrypt.org: DNS: 2606:4700:60:0:f41b:d4fe:4325:6026
acme-client: dochngreq: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/14070714883
acme-client: challenge, token: MpwYvA-ADwhWDEFY8rOYghwY0Qtf_876To83eNm0Z5w, uri: https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/14070714883/VMD6fg, status: 0
acme-client: /home/granito/granito.org.uk/.well-known/acme-challenge/MpwYvA-ADwhWDEFY8rOYghwY0Qtf_876To83eNm0Z5w: created
acme-client: dochngreq: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/14070714893
acme-client: challenge, token: AolrK3kgZrdqCRRiRSK0BfBUEYPUEIdj_oQEAIznFzI, uri: https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/14070714893/8Oim_Q, status: 0
acme-client: /home/granito/granito.org.uk/.well-known/acme-challenge/AolrK3kgZrdqCRRiRSK0BfBUEYPUEIdj_oQEAIznFzI: created
acme-client: https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/14070714883/VMD6fg: challenge
acme-client: https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/14070714893/8Oim_Q: challenge
acme-client: order.status 0
acme-client: dochngreq: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/14070714883
acme-client: challenge, token: MpwYvA-ADwhWDEFY8rOYghwY0Qtf_876To83eNm0Z5w, uri: https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/14070714883/VMD6fg, status: 2
acme-client: dochngreq: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/14070714893
acme-client: challenge, token: AolrK3kgZrdqCRRiRSK0BfBUEYPUEIdj_oQEAIznFzI, uri: https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/14070714893/8Oim_Q, status: 2
acme-client: order.status 1
acme-client: https://acme-staging-v02.api.letsencrypt.org/acme/finalize/163892463/19226354123: certificate
acme-client: order.status 2
acme-client: unhandled status: 2
acme-client: bad exit: netproc(28371): 1

[===--- Rieseguo ---===]

alfree$ doas ./granito.org.uk_acme-client.sh
acme-client: https://acme-staging-v02.api.letsencrypt.org/directory: directories
acme-client: acme-staging-v02.api.letsencrypt.org: DNS: 172.65.46.172
acme-client: acme-staging-v02.api.letsencrypt.org: DNS: 2606:4700:60:0:f41b:d4fe:4325:6026
acme-client: https://acme-staging-v02.api.letsencrypt.org/acme/finalize/163892463/19226363633: certificate
acme-client: order.status 3
acme-client: https://acme-staging-v02.api.letsencrypt.org/acme/cert/2bbe9ae72438da313960ef27fb3353b46b5c: certificate
acme-client: /home/granito/ssl/letsencrypt/staging/granito.org.uk.crt: created
acme-client: /home/granito/ssl/letsencrypt/staging/granito.org.uk.fullchain.pem: created

alfree$

Il certificato creato puntando allo staging sono firmati da una Autority fittizia, quindi chiaramente non sono utilizzabili.

alfree# openssl x509 -in /home/granito/ssl/letsencrypt/staging/granito.org.uk.crt -text

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            2b:be:9a:e7:24:38:da:31:39:60:ef:27:fb:33:53:b4:6b:5c
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=(STAGING) Let's Encrypt, CN=(STAGING) Counterfeit Cashew R10
        Validity
            Not Before: Sep 19 11:49:36 2024 GMT
            Not After : Dec 18 11:49:35 2024 GMT
        Subject: CN=granito.org.uk
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (4096 bit)
                Modulus:
                           __CUT__

                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Key Identifier:
                A4:46:93:D9:E0:3A:AE:A5:BE:58:03:BF:26:BA:EC:BE:B8:B3:79:83
            X509v3 Authority Key Identifier:
                keyid:A4:52:46:EA:58:A8:8F:68:D8:B7:B1:90:D1:4A:42:4A:8F:6B:28:71

            Authority Information Access:
                OCSP - URI:http://stg-r10.o.lencr.org
                CA Issuers - URI:http://stg-r10.i.lencr.org/

            X509v3 Subject Alternative Name:
                DNS:granito.org.uk, DNS:www.granito.org.uk
            X509v3 Certificate Policies:
                Policy: 2.23.140.1.2.1

            CT Precertificate SCTs:
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : __CUT__
                    Timestamp : Sep 19 12:48:06 2024 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                __CUT__
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : __CUT__
                    Timestamp : Sep 19 12:48:06 2024 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                __CUT__
    Signature Algorithm: sha256WithRSAEncryption
         __CUT__
-----BEGIN CERTIFICATE-----
__CUT__
-----END CERTIFICATE-----

[to be continue]

Riferimenti

[1] Protocollo IEFT/ACME (Automatic Certificate Management Environment)
[2] Wikipedia ACME Protocol
[3] LetsEncrypt (Ente di Certificazione)
[4] OpenBSD acme-client man
[5] EFF Certbot
[6] EFF (Electronic Frontier Foundation)

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *