Hey everyone,
From March 13, 2018 – Let’s Encrypt are issuing Wildcard SSL Certificates. One step forward to encrypt the net.
Currently only base DNS validation is available, which means that you have to add a TXT record to the domain that you want to validate. It is a good practice to create different subdomains for the particular cases, for example – if you want to access your networking devices from web using a domain, it is nice to have: .net.maindomain.com and to list all the devices under this domain. Let’s Encrypt Certificates expire after 90 days.
The benefits from using HTTPS are endless.
Webfig is one of the widely used tools to configure Mikrotik devices. Unfortunately it is all through HTTP and in such case many vulnerabilities and exploits are waiting behind the door. With SSL certificate you can secure your device and what’s better – Let’s Encrypt made it even easier for the administrator.
Thankfully it can all be automated.
In the following article I will show you the terminal commands to do that and a bash script, which automatically:
check if certificate presents and if it has expired
check if the required files are uploaded to the device and if they need to be reuploaded
Install the Certbot
Certbot is a tool to obtain certs from Let’s Encrypt. It has to be executed for example once a week in order to check if cert.pem and privkey.pem are not older than 90 days.
wget https://dl.eff.org/certbot-auto chmod a+x ./certbot-auto sudo ./certbot-auto
Get the Certificate
sudo ./certbot-auto certonly \ --server https://acme-v02.api.letsencrypt.org/directory \ --manual --preferred-challenges dns \ -d *.net.maindomain.com
Verify the Domain
In order to verify the domain, you will need to add the txt record provided into the terminal to your subdomain.
You can check if the record has populated correctly by typing:
dig txt net.maindomain.com
Fun part, Let’s automate:
Add into your crontab the execution of certbot:
24 4 * * 3 certbot renew
In this way certbot will automatically try to renew and check if the certificate is older than 90 days. If it is, it will generate and replace the cert.pem and privkey.pem
Below, you will find the automation script which checks the files and certificate and keep them up to date. It has to be executed once a week, after the certbot:
24 4 * * 4 /home/user/name_of_your_script.sh
The script below checks if there is a certificate and if the cert.pem and privkey.pem are up to date (certbot is changing them if there are less than 30 days from expiry of domain). If there is no certificate on the Mikrotik device, script automatically upload and configure it. If the cert.pem and privkey.pem are not up to date, it deletes the old ones, upload the new ones to the Mikrotik device and configures new certificates on the devices.
#!/bin/bash #Mikrotik Wildcard Let’s Encrypt SSL Certificate Automation script #MIlieva_noneblah@sdnix #Change DEBUG to "on", if you want to debug the script, or "off" if you don't need this function. Currently it acts as "#", when it is in the begging of the line. _DEBUG="on" function DEBUG() { [ "$_DEBUG" == "on" ] && $@ } mikUser=yourUser hostKey=/home/user/.ssh/user_key #In this section add your own variables - your domain on “maindomain.com”. In most cases the #letsencrypt directory is the same: /etc/letsencrypt/live/. certDomain=net.maindomain.com certComNa=*.net.maindomain.com certFile=cert.pem prkeyFile=privkey.pem certPath=/etc/letsencrypt/live/$certDomain/$certFile prkeyPath=/etc/letsencrypt/live/$certDomain/$prkeyFile #Here we check the initial stat of the files: cert.pem and privkey.pem and save them into variables, which we check. If certbot has updated the files, the stat will be different. statCertCU=$(stat -c %Z /etc/letsencrypt/live/$certDomain/$certFile) statPrkeyCU=$(stat -c %Z /etc/letsencrypt/live/$certDomain/$prkeyFile) touch /etc/letsencrypt/live/$certDomain/certstat_$(date +'%Y-%m-%d').txt DEBUG echo "certstat_$(date +'%Y-%m-%d').txt for $certDomain has been created. " touch /etc/letsencrypt/live/$certDomain/prkeystat_$(date +'%Y-%m-%d').txt DEBUG echo "prkeystat_$(date +'%Y-%m-%d').txt for $certDomain has been created." cat /etc/letsencrypt/live/$certDomain/certstat_$(date +'%Y-%m-%d').txt > statCertIni cat /etc/letsencrypt/live/$certDomain/prkeystat_$(date +'%Y-%m-%d').txt > statPrkeyIni #We enter this function if there is no certificate, or if the stats of cert.pem and privkey.pem don't match. #The script deletes the cert.pem and privkey.pem and scp the new one. function transKeyCert(){ local mikHostFun="$1" local hostKeyFun="$2" local mikUserFun="$3" mikKey=$(ssh -i $hostKeyFun $mikUserFun@$mikHostFun '/if ([:len [/file find name='$prkeyFile']] > 0) do={:put "yes"}') DEBUG echo "Info: $mikKey" if [[ $mikKey =~ .*yes.* ]]; then DEBUG echo "Key on $mikHost do exist." DEBUG echo "Key on $mikHost will be deleted." ssh -i $hostKeyFun $mikUserFun@$mikHostFun /file remove $prkeyFile scp -i $hostKeyFun $certPath $mikUserFun@$mikHostFun:cert.pem else DEBUG echo "Key on $mikHost doesn't exist." scp -i $hostKeyFun $prkeyPath $mikUserFun@$mikHostFun:privkey.pem fi mikCert=$(ssh -i $hostKeyFun $mikUserFun@$mikHostFun '/if ([:len [/file find name='$prkeyFile']] > 0) do={:put "yes"}') DEBUG echo "Info: $mikCert" if [[ $mikCert =~ .*yes.* ]]; then DEBUG echo "Certificate on $mikHost do exist." DEBUG echo "Certificate on $mikHost will be deleted." ssh -i $hostKeyFun $mikUserFun@$mikHostFun /file remove $certFile scp -i $hostKeyFun $certPath $mikUserFun@$mikHostFun:cert.pem else DEBUG echo "Certificate on $mikHost doesn't exist." scp -i $hostKeyFun $certPath $mikUserFun@$mikHostFun:cert.pem fi } DEBUG echo "Domain is: $certDomain" DEBUG echo "Path to certificate is: $certPath" DEBUG echo "Path to private key is: $prkeyPath" #In this section we check every Mikrotik device in the list below if their stats of privkey.pem and cert.pem are the same # and if they are it gives answer that everything is up to date, otherwise we enter the function: transKeyCert for mikHost in `cat /home/user/youMikListFile.txt`; do DEBUG echo "Debug $mikHost" DEBUG echo "Debug $mikUser" DEBUG echo "Debug $hostKey" checkCert=$(ssh -i $hostKey $mikUser@$mikHost '/if ([:len [/certificate find common-name='$certComNa']] > 0) do={:put "yes"}') if [[ $checkCert =~ .*yes.* || $statPrkeyCU == $statPrkeyIni || $statCertCU == $statCertIni ]]; then DEBUG echo "On $mikHost device in mikList.txt, the ssl certificates seems to be up to dated." else DEBUG echo "Removal of old certificate, cert and key file will be executed. Transfer of the new key and cert file wil function is going to be executed." transKeyCert "$mikHost","$hostKey","$mikUser" ssh -i $hostKey $mikUser@$mikHost /certificate import file-name=cert.pem passphrase=\"\" DEBUG echo "Cert.pem file has been imported." ssh -i $hostKey $mikUser@$mikHost /certificate import file-name=privkey.pem passphrase=\"\" DEBUG echo "PrivKey.pem file has been imported." ssh -i $hostKey $mikUser@$mikHost /ip service set certificate=cert.pem_0 www-ssl DEBUG echo "Cert.pem_0 has been set as certificate." ssh -i $hostKey $mikUser@$mikHost /ip service enable www-ssl DEBUG echo "WWW-SSL service has been enabled." stat -c %Z /etc/letsencrypt/live/$certDomain/$certFile > /etc/letsencrypt/live/$certDomain/certstat_$(date +'%Y-%m-%d').txt DEBUG echo "Stat of $certFile for $certDomain has been saved to certstat_$(date +'%Y-%m-%d').txt in $certDomain ." stat -c %Z /etc/letsencrypt/live/$certDomain/$prkeyFile > /etc/letsencrypt/live/$certDomain/prkeystat_$(date +'%Y-%m-%d').txt DEBUG echo "Stat of $prkeyFile for $certDomain has been saved to prkeystat_$(date +'%Y-%m-%d').txt in $certDomain ." fi done
Unfortunately there is no http-to-https redirection in Mikrotik devices, so if you type, just:
mik1.net.maindomain.com
Nothing will happen, you will need to type the full https path:
https://mik1.net.maindomain.com
Awesome! Saved the day! Thanks!
Hi! This script can be installed directly in mikrotik or it has to be installed in a computer that is connected to the mikotik?
It has to be scheduled on a server which has connection to the Mikrotik.
its for linux?
any solution foe windows?
Hey,
Yeah, currently it is only for linux. The solution for Windows will be to rewrite the script in powershell (I am actually thinking about this 😀 ).
Keep up the good work, thanks!
Hi,
Thanks for the Mikrotik update script, great article!
How does the Certbot Cron job renew the certificate without the DNS TXT record being updated manually? It looks like, that one step is missing: you need to use a Certbot plugin, eg. certbot-dns-cloudflare if you use Cloudflare, to update the TXT record automatically using the DNS service provider’s API, or the record has to be updated locally if you are hosting your own DNS server for the given domain.
The challenge string you need to add to the TXT record will change for each renewal.
Thanks,
Tamas.