Privátna subdoména s platným certifikátom od Let’s Encrypt

Certifikačná autorita (CA) Let’s Encrypt (LE) vydáva bezplatné TLS certifikáty, ktorá slúžia pre šifrovanú komunikáciu medzi serverom a klientom. O tom ako CA LE funguje som písal v roku 2019, ale aj nedávno keď sme nastavovali reverzný proxy server Nginx. Ak sú certifikáty vydávané pre verejnú doménu, tak to funguje za pomoci certbot a acme protokolu veľmi jednoducho. Pre privátne domény sa certifikáty nevydávajú aby nemohli byť zneužité. Avšak pre subdomény sa od januára 2018 vydávajú tzv wildcard certifikáty. Takýto certifikát je možné získať aj pre privátnu subdoménu. Ako som postupoval krok po kroku sa dozviete ak budete čítať ďalej.

Obsah

Topológia siete

Vzhľadom k tomu, že budeme pracovať na troch rôznych zariadeniach, tak považujem za dôležité aby bola topológia siete vysvetlená hneď na začiatku (na generovanie certifikátov to samozrejme nemá žiadny vplyv). Ak sa pozrieme na nasledujúci obrázok, tak celkom na pravo je backendový Apache2 web server na ktorom budú uložené webové adresáre (tam budeme konfigurovať aj vhosts). Ako frontend bude použitý reverzný proxy server Nginx na ktorom budú uložené certifikáty pre subdomény. Obidva servery sú linuxové kontajnery. DNS záznamy budú nastavené na lokálnom DNS resolvery (pfSense), ktorý je tiež virtuálny stroj KVM. Či budeme používať virtuálne stroje, kontajnery, alebo fyzické stroje je úplne jedno.

Topológia siete

Získanie cert. pre verejnú doménu

Majme verejnú doménu druhého radu example.com. Pre túto doménu viem získať certifikát veľmi jednoducho (predpokladajme že certbot pre nginx je nainštalovaný a funguje správne). Na generovanie certifikátov použijeme nasledujúci príkaz.

sudo certbot --nginx -d example.com -d www.example.com

To je všetko čo musíme pre získanie certifikátu spraviť. Tento príkaz hovorí aby certbot získal certifikát pre doménu example.com a subdoménu www.example.com (áno v tomto prípade je www subdoména a na DNS servery musí byť k nej CNAME záznam). Ak by sme chceli mať viac „verejných“ subdomén, tak na DNS servery vytvoríme ďalšie CNAME na doménu napr. cloud.example.com, wiki.example.com atď. a príkaz na získanie cert. bude následovný.

sudo certbot --nginx -d example.com -d www.example.com -d cloud.example.com -d wiki.example.com

My však chcem získať certifikát pre subdoménu, ktorá má byť privátna, to znamená, že z internetu nie je dostupná. Najprv si privátnu subdoménu poďme vytvoriť.

Vytvárame privátnu subdoménu

O statických DNS záznamoch som tiež písal nedávno, takže to prejdeme len v rýchlosti. Na obrázku som nastavil 3 subdomény. Doména example.com a subdoména www.example.com sú zároveň verejné a na DNS servery k ním existujú A resp. CNAME záznamy. Subdomény cloud.example.com a wiki.example.com existujú len v našom lokálnom DNS resolvery. Tieto subdomény nie sú viditeľné z internetu.

Ak po uložení Save a potvrdení Apply Changes zadáme do webového prehliadača jednú zo subdomén cloud.example.com, alebo wiki.example.com, tak budeme presmerovaný na defaultný súbor nginx. Dôvod je ten, že kvázi CNMAE už existujú, ale nemáme nakonfigurované virtuálhosts a server block na reverznom proxy servery.

Konfigurácia virtualhost

Predpokladom je už nainštalovaný a plne funkčný webový server Apache2. Teraz môžeme vytvoriť prvý aj druhý virtualhost. Ja prevádzkujem Apache2 server v linuxovom kontajnery, takže sa cez SSH prihlásim do LXC a postupujem následovne:

Prvý virtualhost

sudo mkdir /var/www/html/www.example.com/cloud
sudo nano /etc/apache2/sites-available/cloud.example.com.conf
<VirtualHost *:80>
    ServerAdmin admin@cloud.example.com
    ServerName cloud.example.com
    DocumentRoot /var/www/html/www.example.com/cloud/
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

sudo chown www-data:www-data -R /var/www/html/www.example.com/cloud
sudo a2ensite cloud.example.com.conf
sudo systemctl reload apache2

sudo echo "<html><head><title>cloud</title></head><body><h1>This is cloud on example.com</h1></body></html>" | sudo tee /var/www/html/www.example.com/cloud/index.html

Druhý virtualhost

sudo mkdir /var/www/html/www.example.com/wiki
sudo nano /etc/apache2/sites-available/wiki.example.com.conf
<VirtualHost *:80>
    ServerAdmin admin@wiki.example.com
    ServerName wiki.example.com
    DocumentRoot /var/www/html/www.example.com/wiki/
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

sudo chown www-data:www-data -R /var/www/html/www.example.com/wiki
sudo a2ensite wiki.example.com.conf
sudo systemctl reload apache2

sudo echo "<html><head><title>wiki</title></head><body><h1>This is wiki on example.com</h1></body></html>" | sudo tee /var/www/html/www.example.com/wiki/index.html

Ak si myslíme, že teraz zadaním url adries cloud.example.com, alebo wiki.example.com do webového prehliadača uvidíme obsah index.html súborov, tak sa mýlime. Stále uvidíme defaultný súbor nginx, pretože všetka komunikácia je presmerovaná na IP adresu reverzného proxy servera. Ak sa konečne chceme dostať na naše spomínané virtualhosts musíme vytvoriť server block konfiguráciu na reverznom proxy servery.

Konfigurácia server block

Obdobou virtualhost na Apache2 servery je server block na Nginx. Do jedného konfiguračného súboru server block na Nginx servery som umiestnil obidva subdomény. Čiže najprv sa cez SSH prihlásime do LXC reverzného proxy servera a začneme vytvárať konfiguráciu.

sudo nano /etc/nginx/sites-available/subdomain.example.com
# -----------cloud-subdomain------------#
server {
    listen 80;
    server_name cloud.example.com;
 
    location / {
        proxy_pass http://192.168.1.106;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# -----------wiki-subdomain------------#
server {
    listen 80;
    server_name wiki.example.com;
 
    location / {
        proxy_pass http://192.168.1.106;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Teraz skontrolujeme syntax a preveríme či je konfigurácia v poriadku. Vytvoríme symbolicky link odkiaľ bude nginx konfiguráciu čítať a reloadneme server pre načítanie novej konfigurácie.

sudo nginx -t
sudo ln -s /etc/nginx/sites-available/subdomain.example.com /etc/nginx/sites-enabled/subdomain.example.com
sudo systemctl reload nginx

Ak si myslíme, že teraz zadaním url adries cloud.example.com, alebo wiki.example.com do webového prehliadača uvidíme obsah index.html súborov, tak máme pravdu. Teraz konečne vidíme obsah našich lokálnych subdomén a v rámci LAN ich môžeme plnohodnotne využívať. Takto môže byť riešený napr. intranet v podnikovej sfére. Avšak vidíme, že weby sú nezabezpečené, resp. komunikácia medzi serverom a klientom nie je šifrovaná.

Nezabezpečená privátna subdoména cloud
Nezabezpečená privátna subdoména wiki

Šifrovanie v rámci LAN (ne)potrebujeme

Ak v rámci lokálnej (resp. podnikovej) siete dôverujeme klientom, tak nepotrebujeme komunikáciu medzi klientom a serverom šifrovať. Ak je však podniková sieť veľká a nemôžeme každej osobe dôverovať, tak sa vyžaduje TLS spojenie. Jednou z možností je vytvorenie certifikátov pomocou vlastnej CA. Tieto certifikáty určite nebude poznať žiadny webový prehliadač a môže to vyzerať napr. takto.

Aj keď v tomto prípade je spojenie šifrované (certifikát je platný), tak webový prehliadač nepozná CA a spojenie považuje za nezabezpečené. Preto je vhodnejšie použiť CA od dôveryhodného vydavateľa a tým môže byť napr. LE. Táto CA je dôveryhodná pre nasledujúce platformy.

Získanie certifikátov od LE

Keď chceme získať certifikát od LE, tak servery LE musia overiť, že skutočne máme kontrolu nad doménou a to sa deje prostredníctvom výzvy (challenge). Tieto chellenges sú pekne popísane na LE webe.

  • HTTP-01 challenge
  • DNS-01 challenge
  • TLS-SNI-01
  • TLS-ALPN-01

Vo väčšine prípadov sa používa HTTP-01 challege, ale pre wildcard musíme použiť DNS-01 challenge. V podstate to funguje tak, že LE poskytne klientovi ACME token. Klient vytvorí záznam TXT odvodený z tohto tokenu, kľúča vášho účtu a umiestni tento záznam na _acme-challenge.<YOUR_DOMAIN>. Potom LE požiada systém DNS o tento záznam. Ak nájde zhodu, môžete pristúpiť k vydaniu certifikátu!

Takže poďme na to

sudo certbot -d *.example.com --manual --preferred-challenges dns certonly
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for example.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.example.com with the following value:

X7RMZ1ompP_xXGWWPPT8TVUQ8fvGPAg-PkaxsadZFIo

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Presunieme sa na server freenom, kde zadáme vygenerovaný kód ako TXT záznam

DNS manager freenom

Teraz musíme chvíľu čakať, pokiaľ sa na DNS servery prejavia zmeny. Na niektorých DNS serveroch je to rýchle, na iných je potrebné čakať aj desiatky minút. Na freemom sa zmena prejavila do niekoľkých minút. Či je TXT záznam na servery v poriadku môžeme overiť príkazom dig

dig -t txt +short _acme-challenge.example.com

ak bude výsledkom kľúč, ktorý sme poskytli serveru vo forme TXT záznamu

X7RMZ1ompP_xXGWWPPT8TVUQ8fvGPAg-PkaxsadZFIo

je to OK a môžeme dať enter

Press Enter to Continue



Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com-0001/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com-0001/privkey.pem
   Your cert will expire on 2022-04-03. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

Certifikát sme úspešne získali na 90 dní. Po 90 dňoch musíme spraviť rovnakú procedúru. Nie je to nič zložité. Ja v súčasnej dobe stále používam doménu od freenom (vrátane DNS serverov). Na automatizáciu tohto procesu sa používajú pluginy, ktoré sú kompatibilné s certbot. Pre freenom, takýto plugin nie je, ale našiel som pythonovsky plugin, ktorý tento proces plne automatizuje. Jedna sa o plugin certbot-dns-freenom. Avšak tomuto pluginu sa budem venovať niekedy inokedy, zatiaľ mi postačuje ručná obnova 😀

Rekonfigurácia server block v Nginx

Naš konfiguračný súbor zatiaľ nemá potuchy o nejakých certifikátoch, preto musíme serveru Nginx oznámiť cestu kde sa certifikáty nachádzajú. Upravený konfiguračný súbor pre obidva subdomény bude vyzerať následovne.

# -----------cloud-subdomain------------#
server {
    server_name cloud.example.com;

    location / {
        proxy_pass http://192.168.1.106;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    listen 443 ssl; 
    ssl_certificate /etc/letsencrypt/live/example.com-0001/fullchain.pem; 
    ssl_certificate_key /etc/letsencrypt/live/example.com-0001/privkey.pem; 
    include /etc/letsencrypt/options-ssl-nginx.conf; 
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 

}

server {
    if ($host = cloud.example.com) {
        return 301 https://$host$request_uri;
    } 


    listen 80;
    server_name cloud.example.com;
    return 404; 


}

# -----------wiki-subdomain------------#
server {
    server_name wiki.example.com;

    location / {
        proxy_pass http://192.168.1.106;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    listen 443 ssl; 
    ssl_certificate /etc/letsencrypt/live/example.com-0001/fullchain.pem; 
    ssl_certificate_key /etc/letsencrypt/live/example.com-0001/privkey.pem; 
    include /etc/letsencrypt/options-ssl-nginx.conf; 
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 

}

server {
    if ($host = wiki.example.com) {
        return 301 https://$host$request_uri;
    } 


    listen 80;
    server_name wiki.example.com;
    return 404; 


}

Ak po reloade Nginix servera zadáme do url cloud.example.com, alebo wiki.example.com, tak zistíme, že web server z prehliadačom komunikuje šifrovane (šifrovanú komunikáciu symbolizuje visiaci zámok pred url adresou).

Zabezpečená privátna subdoména cloud
Zabezpečená privátna subdoména wiki

Záver

Privátne subdomény v rámci lokálnej siete môžeme vytvoriť toľko, koľko potrebujeme. Výhoda je, že certifikáty sú dôveryhodné aj keď subdomény sú privátne a nie sú viditeľné z internetu. Pokiaľ máme v správe množstvo serverov, tak je vhodné tento proces automatizovať. ako som už v blogu spomenul, veľmi som sa automatizácii nevenoval. Budem však hľadať riešenia aby som tento proces v budúcnosti mal plne automatizovaný. Z pohľadu jednoduchosti bude zrejme najvhodnejšie využiť certbot-dns-freenom, alebo zmeniť DNS server na taký, pre ktorý existuje vhodný DNS plugin (napr. clouflare).

Použitá literatúra

Leave a Reply

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *