NOTE: WHEN WRITING THIS GUIDE, IT WAS BASED ON AUTHELIA v4.38.16 AND CLOUDFLARE TUNNEL v2024.9.1
First, we start with Cloudflare platform
- Generating Hashed Secrets
- Setting Up Authentication Methods
- Adding Applications Rules and Policies
- Adding Firewall Rules
Second, we move to Authelia self-hosted
- Generating Secrets and OpenID Issuer Private Key
- Generating Random Alphanumeric String
- Editing Authelia Configuration File
Finally, we test our setup
This step will be used in a later step as the link where both Authelia and Cloudflare are integrated together.
In the terminal, execute the command docker run authelia/authelia:latest authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986
and take note of the both the Random Password and Digest outputs.
On the same page, you are now, and on the left side, click on Settings, then choose Authentication
In the next window, under the Login methods, click Add new, and then Choose the OpenID Connect from the available options
Now, this has to be filled in carefully, and remember each entry for later use.
- Fill in the name, i.e. "Authelia"
Considering the URL for Authelia as "auth.mydomain.com", then in each field that follows enter:
- cloudflare
- The Random Password generate in the previous step
- https://auth.mydomain.com/api/oidc/authorization
- https://auth.mydomain.com/api/oidc/token
- https://auth.mydomain.com/jwks.json
- Enable the Proof Key for Code Exchange (PKCE)
- Add new OIDC Claims, preferred_username and mail
Click on Save
Before leaving the Cloudflare platform and moving to the Authelia part, take note of the Cloudflare team name, and have it saved somewhere safe for later use. To do that, click on Settings on the left side list, then choose Custom Pages. On the top right side, you will see the team name in the format myteam.cloudflareaccess.com. So, in this case, it will be only *myteam
This is where you define for each subdomain if Authelia is needed to be an intermediate gate between the Cloudflare Tunnel and the final URL requested
On the left side, click on Access, then choose Applications, then click on Add an application and choose the Self-hosted option.
In the Configure app screen, give the application a name, i.e. "Portainer-CE". Choose a subdomain, i.e. "portainer", and choose your domain, which we agreed on to be mydomain.com. You can change the application logo if needed, or just keep the Default one. Click on Next on the top right.
In the Add policies screen, give this policy a name, i.e. "portainer_auth_policy". In the Action, select the "Allow", and duration make it "1 month". Then in Configure rules, set the Selector to "Login Methods", and the Value, choose the "OpenID Connect Authelia" option and click on Next on the top right.
In the Setup screen, leave everything as is, and click on Add application on the top right
What we need now is to allow specific countries to access the domain, and block all other countries to avoid external attacks.
In the Cloudfare dashboard, click on the Websites on the top left side, then choose the domain name that needs to have the firewall rules added to.
From that screen, Security from the Home screen, then choose WAF. On the right side, click on Create rule.
Follow the steps below:
- Enter the desired Rule Name
- Choose "Continent" from the Field list, Operator to be "equals", and then choose the first option in the Value list. Do this step for all items in the "Value" list by choosing the "Or" next to each rule line
- Choose the "Block" from action
By doing this, you have blocked all countries from accessing your domain.
Now, you need to unblock your country (or more than one if needed).
After you have added all continents as Block, check your desired country is in which continent, i.e. Cyprus, which is in Europe. You go to the Europe option you have added, and then click on And, then choose "Country" from the Field list, Operator to be "does not equals", and then choose "Cyprus" from the Value list.
Click on Deploy firewall rule at the bottom of the page
Your final result should look like below
In case you have Home Assistant installed, and have the Google Home Devices integrated with it, you need to allow Google to bypass the firewall rule. In order to do that, with the North America rule, add an And rule, then choose "AS Num" from the Field list, Operator as "does not equal" and set the Value to "15169"
In case you have MariaDB installed, you need to allow it to bypass the firewall rule. In order to do that, with the North America rule, add an And rule, then choose "AS Num" from the Field list, Operator as "does not equal" and set the Value to "396982"
What we need now is to generate an encrypted pair of RSA files to be used to encrypt Authelia public requests.
To do so, SSH into the host machine having the Authelia container installed on, and considering that: UID="1000", GID="100" , and PEM file output directory="/rsa"
Enter and execute the following command: docker run -u "$(id -u):$(id -g)" -v "$(pwd)":/keys authelia/authelia:latest authelia crypto pair rsa generate --bits 4096 --directory /keys
2 .pem
files will be generated in the current working folder as defined in the command executed
We are only in need of the private.pem file, keep it somewhere safe for later use.
This step is to generate an alphanumeric string to be used as a secret hash for Authelia when accessing it from Cloudflare
In the same SSH terminal, execute the following command tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1 | tr -d '\n' ; echo
An output string will be shown on the terminal window, also copy that and keep it in a safe place for later use.
Because Cloudflare has different settings to be configured, and are different compared to the one previously used with any reverse proxy, a new configuration.yml file should be created with the relevant parameters in it
In case an existing "configuration.yml" file is available in the Authelia folder, make a backup copy of that, or simply download the sample one from here and make sure to change all CAPITALISED parameters to match your setup
As a quick summary, just delete the "rules:" part under the "access_control:", and keep the rest untouched. Also make sure that you change all "URLs" from the previous one to Cloudflare's ones, i.e. from "DuckDNS"
Considering the team's name in Cloudflare is named as "myteam", then, we need to add the following at the end of the file:
identity_providers:
oidc:
hmac_secret: **PUT THE GENERATED RSA STRING FROM THE PREVIOUS STEP**
jwks:
- key_id: 'example'
algorithm: 'RS256'
use: 'sig'
key: |
-----BEGIN RSA PRIVATE KEY-----
**HERE GOES WHATEVER IS IN THE _private.pem_ FILE**
-----END RSA PRIVATE KEY-----
lifespans.access_token: 1h
lifespans.authorize_code: 1m
lifespans.id_token: 1h
lifespans.refresh_token: 90m
enable_client_debug_messages: false
enforce_pkce: public_clients_only
cors:
endpoints:
- authorization
- token
- revocation
- introspection
allowed_origins:
- "*"
allowed_origins_from_client_redirect_uris: false
clients:
- client_id: cloudflare
client_name: Cloudflare ZeroTrust
client_secret: **PUT THE _Digest_ PASSPHRASE PREVIOUSLY GENERATED **
public: false
authorization_policy: two_factor
pre_configured_consent_duration: '365d'
redirect_uris:
- https://**myteam**.cloudflareaccess.com/cdn-cgi/access/callback
scopes:
- openid
- profile
- email
userinfo_signed_response_alg: none
Now, restart Authelia container and make sure that no errors are in the logs. If this is successful, it is time now to test the integration from Cloudflare.
In case there was an error, it is most probably due to the generated RSA encoding not matching.
level=error msg="Configuration: error occurred during unmarshalling configuration: decoding failed due to the following error(s):\n\nerror decoding 'identity_providers.oidc.jwks[0].key': could not decode to a schema.CryptographicKey: x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)"
level=fatal msg="Can't continue due to the errors loading the configuration" stack="github.com/authelia/authelia/v4/internal/commands/context.go:327 (*CmdCtx).ConfigValidateLogRunE\ngithub.com/authelia/authelia/v4/internal/commands/context.go:186 NewRootCmd.(*CmdCtx).ChainRunE.func1\ngithub.com/spf13/[email protected]/command.go:970 (*Command).execute\ngithub.com/spf13/[email protected]/command.go:1117 (*Command).ExecuteC\ngithub.com/spf13/[email protected]/command.go:1041 (*Command).Execute\ngithub.com/authelia/authelia/v4/cmd/authelia/main.go:10 main\ninternal/runtime/atomic/types.go:194 (*Uint32).Load\nruntime/asm_amd64.s:1700 goexit"
To resolve this, execute the following command in the same terminal window
openssl rsa -in private.pem -out key.pem -traditional
A new file will be generated named key.pem, copy the contents of this file into the above configuration and then run the container. All should be fine now
This is the last step to make sure that nothing wrong is done during the setup, and Authelia is successfully integrated into Cloudflare as a 2FA platform
Now to make sure that, so far, everything is set up correctly, open the Cloudflare Zero Trust page. Click on Settings, then Authentication. Under the Login methods you will see the previously added "OpenID Connect Authelia" method. Click on Test beside it.
If the below is seen, then Authelia is now a gateway for your Cloudflare's selected domains for 2FA authentication. Otherwise, re-check what have you missed from this guide, as it is 100% guaranteed if followed as is, the integration will be successful.
This document guide is licensed under the CC0 1.0 Universal license. The terms of the license are detailed in LICENSE