First test for Cloudflare Access

Today I will show you my first attempt to work with Cloudflare Access service.

As a proof of concept, I created a small instance (code) with the Racktables application installed (in Docker) and protected its access with Cloudflare.

At this point, I didn’t configure external IdP, but used the built-in ‘One-Time Pin Login’ feature (Cloudflare Access can send a one-time PIN to approved email addresses). Essentially it’s password-less access to the application.

In this test, I didn’t validate the JWT tokens on the origin (I will walk you through the JWT scenario in the next posts), but instead extracted the ‘Cf-Access-Authenticated-User-Email’ value and used it for authorization on application (Racktables) level.

Here the diagram:

racktables_and_cloudflare_diagram
  1. Visitor open application URL. The request hits the Cloudflare load balancer and gets redirected to a separate portal for authentication.
  2. Enter the email address and get the one time code.
  3. After successful authentication visitors get redirected back to the application.

Step by step instruction to reproduce the environment:

  1. Clone the repo with Dockerized Racktables application: kariedo/racktables-docker
  2. Replace MYSQL_PASSWORD, DBPASS and MYSQL_RANDOM_ROOT_PASSWORD values in the docker-compose.yml
  3. Start the environment:
   docker-compose up
  1. In the separate shell review the list of started containers. You should have 4 of them up and running:
docker ps
CONTAINER ID        IMAGE                            COMMAND                  CREATED             STATUS              PORTS                          NAMES
ae5bf0205930        racktables-docker_nginx          "/docker-entrypoint.…"   20 hours ago        Up 20 hours         80/tcp, 0.0.0.0:443->443/tcp   racktables-docker_nginx_1
b0b81dd6fe65        brndnmtthws/nginx-echo-headers   "/usr/local/openrest…"   23 hours ago        Up 20 hours         8080/tcp                       racktables-docker_nginx-echo-headers_1
78fb03fb67e6        racktables-docker_racktables     "/entrypoint.sh /usr…"   24 hours ago        Up 20 hours         9000/tcp                       racktables-docker_racktables_1
b52b00a70165        mariadb                          "docker-entrypoint.s…"   24 hours ago        Up 20 hours         3306/tcp                       racktables-docker_mariadb_1

I left the extra container with nginx-echo as found it very useful for header debug purposes.

  1. Open the HTTPS page with the server IP address, skip the TLS cert warning.
    Add /?module=installer&step=5 to the URL and finilize the Racktables setup:

racktables_installation_step_5 racktables_installation_step_6 racktables_installation_step_6_1 racktables_installation_step_7

  1. Open “Configuration” > “Permissions” > “Edit” and add extra line to allow new user to authenticate.
    Username should be the text before the @ in the email address.

In my case, I used email address [email protected], so the resulting username is just stas

allow {$username_stas}
racktables_permissions

Transformation is done with the nginx map:

    map $http_cf_access_authenticated_user_email $cf_remote_user {
        ~^(?<prefix>.*)@(?<suffix>.*)$ "${prefix}";
    }
  1. Open /opt/racktables/wwwroot/inc/secret.php file from racktables-docker_nginx_1 container and replace the lines 5 and 6 with the following:
dockerhost# docker exec -ti racktables-docker_nginx_1 sh
racktables-docker_nginx_1# chmod 644 /opt/racktables/wwwroot/inc/secret.php
racktables-docker_nginx_1# vi /opt/racktables/wwwroot/inc/secret.php

From:
$user_auth_src = 'database'; to $user_auth_src = 'httpd';
From:
$require_local_account = TRUE; to $require_local_account = FALSE;

Result should like this:

racktables_vi_secrets_php
  1. Create new DNS record in Cloudflare panel and point it to the server IP
cloudflare_racktables_dns
  1. Enable Cloudflare Access and create the new policy:
cloudflare_access_policy_config
  1. Open the application URL, authenticate with the OTP pin and here we are - logged in with the correct username and without use of any passwords:
racktables_with_new_user

Q&A:

Question: Can I use the same approach for the other applications?
Answer: Sure! You can use this idea to manage access to all applications that support HTTP_AUTH (BasicAuth) method: Nagios, Icinga, Grafana, Zabbix, and others.

Question: Why you didn’t use the full email address as username in Racktables?
Answer: Racktables doesn’t support the “@” symbol in the permissions logic, so I came with the work-around.