CloudFlare SSL/TSL Modes and How to Use Them

CloudFlare has following SSL/TSL modes:

  • Off - no encryption
  • Flexible - encrypts traffic between the browser and Cloudflare
  • Full - encrypts end-to-end, using a self signed certificate on the server
  • Full (Strict) - encrypts end-to-end, but requires a trusted CA or Cloudflare Origin CA certificate on the server

Also this settings can be overriden in page rules section, so for example one subdomain might work in flexible mode and another in full

For experiments we have dedicated VM with a public network and subdomain

  • IP: 161.35.222.169
  • DNS: cf.mac-blog.org.ua

On server all we did is:

apt update
apt install -y nginx
curl http://161.35.222.169

Flexible

Is the easiest way to become "secure"

Cloudflare will handle all TLS related things and you do not to do anything at all

Underneath it will be something like:

G user user cloudflare cloudflare user->cloudflare :443 https server server cloudflare->server :80 http

Take a note that if user knows server ip address he can send requests directly to it bypassing cloudflare

Cloudflare has a list of its ip addresses so we can do something like:

/etc/nginx/cloudflare.conf

allow 173.245.48.0/20;
allow 103.21.244.0/22;
allow 103.22.200.0/22;
allow 103.31.4.0/22;
allow 141.101.64.0/18;
allow 108.162.192.0/18;
allow 190.93.240.0/20;
allow 188.114.96.0/20;
allow 197.234.240.0/22;
allow 198.41.128.0/17;
allow 162.158.0.0/15;
allow 104.16.0.0/13;
allow 104.24.0.0/14;
allow 172.64.0.0/13;
allow 131.0.72.0/22;

allow 2400:cb00::/32;
allow 2606:4700::/32;
allow 2803:f800::/32;
allow 2405:b500::/32;
allow 2405:8100::/32;
allow 2a06:98c0::/29;
allow 2c0f:f248::/32;

deny all;

And inside our site config add somewhere this line:

include /etc/nginx/cloudflare.conf;

Reload nginx: systemctl reload nginx

And test it from outside: curl --resolve cf.mac-blog.org.ua:80:161.35.222.169 http://cf.mac-blog.org.ua/

If everything ok you should receive forbidden response, but if you open it in browser, everything will work fine

flexible

Full

This time our schema will look like

G user user cloudflare cloudflare user->cloudflare :443 https server server cloudflare->server :443 https (self signed)

First of all we need self signed certificate:

openssl req -subj "/CN=cf.mac-blog.org.ua/" -newkey rsa:2048 -nodes -keyout tls.key -x509 -days 365 -out tls.pem

Notes:

  • this cert without SAN so can be used only for a given CN
  • tls.key will hold private key which should be keept safe
  • tls.pem is a certificate which may be publisheed

And here is config:

server {
        # for experiment to be sure that cloudflare will not land here
        # listen 80 default_server;
        # listen [::]:80 default_server;

        # added
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;
        ssl_certificate /etc/nginx/tls.pem;
        ssl_certificate_key /etc/nginx/tls.key;

        # include /etc/nginx/cloudflare.conf;

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                try_files $uri $uri/ =404;
        }
}

Now your server should listen only 433 but not 80, e.g:

curl https://cf.mac-blog.org.ua/

Also you can watch for logs:

tail /var/log/nginx/access.log -f

You will see your requests, comming from cloudflare ip addresses

Lets try to bypass cloudflare

curl --resolve cf.mac-blog.org.ua:80:161.35.222.169 http://cf.mac-blog.org.ua/
# curl: (7) Failed to connect to cf.mac-blog.org.ua port 80: Connection refused

curl --resolve cf.mac-blog.org.ua:443:161.35.222.169 https://cf.mac-blog.org.ua/
# curl: (77) schannel: next InitializeSecurityContext failed: SEC_E_UNTRUSTED_ROOT (0x80090325) - The certificate chain was issued by an authority that is not trusted.

curl -k --resolve cf.mac-blog.org.ua:443:161.35.222.169 https://cf.mac-blog.org.ua/
# works - but only because we commented out cloudflare ip rules

Strict

Is same as Full, the only difference now that CloudFlare wont believe self signed requests and will require valid certificates, or certificates signed by CloudFlare

If you turn this on, immediatelly you will start receive invalid certifiacte errors

Error 526: Invalid SSL certificate

There are two options, you can let cloudflare to do its work and generate certs for you, or you can create private key and certificate signing request and ask cloudflare to sign it

Cloudflare Strict - aka LetsEncrypt for 15 years

Easiest way will be to let Cloudflare generate certs, good thing here is that by default they are generated for 15 year, yep it might be not secure but for home lab it is much better than 1 month certs from letsencrypt

So navigate to SSL/TLS \ Origin Server \ Origin Certifiacetes \ Create Certificate

Cloudflare Origin Certificate

Leave all settings as is and press Create button

Cloudflare Generated Certificate Result

Replace contents of tls.pem and tls.key created earlier by Origin Certificate and Private Key respecively and reload nginx

And everything should work again

Note that technically it is same as with self signed certificates, so if you will try to bypass cloudflare it will behave exactly the same, the only difference here is that this certificate is trusted by cloudflare out of the box

Cloudflare Strict - with Certificate Signing Request

Suppose for some reason you can not use given certs, there is another options then

Firstly create private key

# cleanup
systemctl stop nginx
rm tls.*

# create private key and certificate signing request (csr)
openssl req -new -newkey rsa:2048 -nodes -keyout tls.key -out tls.csr
# Country Name (2 letter code) [AU]:UA
# State or Province Name (full name) [Some-State]:Kiev
# Locality Name (eg, city) []:Kiev
# Organization Name (eg, company) [Internet Widgits Pty Ltd]:mac-blog.org.ua
# Organizational Unit Name (eg, section) []:cf
# Common Name (e.g. server FQDN or YOUR name) []:cf.mac-blog.org.ua
# Email Address []:[email protected]

# Please enter the following 'extra' attributes
# to be sent with your certificate request
# A challenge password []:
# An optional company name []:

# you can check what is inside our tls.csr like so
openssl req -noout -text -in tls.csr

Once again navigate to SSL/TLS \ Origin Server \ Origin Certifiacetes \ Create Certificate

But now choose "Use my private key and CSR" and paste contents of tls.csr

Cloudflare creating certificate from certificate signing request

Press create and you will get your certificate which should be saved to tls.pem

screensho

Now you can start nginx and everything should work

CloudFlare Access or get rid of VPN

Technicaly, because of wildcard and 15 years this approach can be used for a home lab without dealing with LetsEncrypt

Also we can put this certificates for Kubernetes instead of its self signed ones

And even more, because of CloudFlare Access project we can restrict access without dealing with VPN, it is free up to 50 users

At the very minimum all you need to do:

  • restrict access only to cloudflare
  • inside cloudflare enable access
  • add single rule

CloudFlare example of Access Rule

And from now on if you will try to connect to your app you will see something like:

CloudFlare Acccess in action

Just submit your email and you will get your TOTP token to login