Enable SAML Service Provider on F5 Distributed Cloud Application
SAML is a federation protocol used to authenticate users.
F5 Distributed Cloud does not yet offer such a solution natively, but thanks to F5 portfolio, it is easy to deploy NGINX in F5 XC and enable SAML as Service Provider.
To do so, we need:
- A F5 Distributed Cloud tenant
- A F5 Distributed Cloud vk8s
- A NGINX Plus subscription (license)
- The NGINX Plus SAML module : https://github.com/nginxinc/nginx-saml
- An SAML IDP - in our demo, we will use the Corporate F5 Azure AD
This is the architecture
Create the NGINX Plus docker image
In order to run NGINX Plus in vK8S, NGINX Plus needs to be built as Unprivileged. The NGINX daemon requires it to run as root, but this is not allowed in vK8S.
You can find the GitHub repo with the Dockerfile and steps here : https://github.com/f5devcentral/nginx-unprivileged-f5xc
When the image is created, upload it to a PRIVATE repository. NGINX Plus is not free, so don't push the image into a public repo. In our demo, we will use Azure Container Registry (ACR).
Create a vK8S and link your Container Registry with F5 Distributed Cloud
First of all, create a vK8S in your Namespace. Then create a F5 Distributed Cloud Container Registry (with Azure ACR, it is pretty easy - copy and paste the ACR hostname, username and password)
Now, we are ready to deploy our NGINX Plus in vK8S and configure it as SAML SP.
Create a Workload for N+
Create a new workload and instead of creating all objects manually, paste this JSON into the console. To do so, click on the top left corner to JSON and past the below blob.
You must "modify" this JSON according to your own deployment. You must modify lines:
- 4 - Namespace
- 6 - Owner
- 23 - Container image link
- 25-27 - F5XC Container Registry
You can find the JSON config file here : link to Github
For the rest, we will modify it from the UI.
Click SAVE
Configure SAML settings and NGINX Reverse Proxy
Configure SAML module
There are 2 files to configure SAML, but we will only configure one:
- Edit saml_sp_configuration.conf
- And configure according your SAML IDP, for Azure AD (Corporate Azure AD) I use the below settings
You can find demo configuration file in Github : link to Github
Configure NGINX Reverse Proxy settings
As you can understand, the NGINX is the next hope after the F5 Distributed Cloud LB. It means NGINX will have to proxy the traffic to the backend application. In my demo, my backend application is on public Internet at http://sentence.emea.f5se.com
I will configure the NGINX conf as usual to proxy toward this upstream. It is up to you to adapt the configuration for your apps.
Edit frontend.conf file.
# This is the backend application we are protecting with SAML SSO
upstream my_backend {
zone my_backend 64k;
server sentence.emea.f5se.com;
}
# Custom log format to include the 'NameID' subject in the REMOTE_USER field
log_format saml_sso '$remote_addr - $saml_name_id [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# The frontend server - reverse proxy with SAML SSO authentication
#
server {
# Functional locations implementing SAML SSO support
include conf.d/saml_sp.server_conf;
# Reduce severity level as required
error_log /nginx/var/log/nginx/error.log debug;
listen 8080;
#listen 443 ssl; # Use SSL/TLS in production
#ssl_certificate /etc/nginx/ssl/server.crt;
#ssl_certificate_key /etc/nginx/ssl/server.key;
location / {
# When a user is not authenticated (i.e., the "saml_access_granted"
# variable is not set to "1"), an HTTP 401 Unauthorized error is
# returned, which is handled by the @do_samlsp_flow named location.
error_page 401 = @do_samlsp_flow;
if ($saml_access_granted != "1") {
return 401;
}
# Successfully authenticated users are proxied to the backend,
# with the NameID attribute passed as an HTTP header
proxy_set_header username $saml_name_id;
proxy_set_header Host sentence.emea.f5se.com;
proxy_pass http://my_backend; # The backend site/app
access_log /nginx/var/log/nginx/access.log saml_sso;
}
}
# vim: syntax=nginx
Import your IDP public key to validate SAML assertion signature
Download the IDP public cert (PEM format) and copy it into F5XC workload.
- Edit file saml_idp_verify.pem
- Paste the PEM payload
Configure the Origin Pool
As you probably understand, the Origin Pool forwards traffic to the NGINX so NGINX Plus can prompt the user for the SAML authentication, and when it's done and approved, proxy the traffic to the backend application.
The Origin Pool is a service running in vk8s on port 8080 (name_of_the_workload.namespace). In my demo, I decided to create a virtual site with Paris' REs only. It's up to you to adapt your demo.
Configure F5 Distributed Cloud HTTP LB
Create an HTTP LB with Routes because we need to inject 2 headers to the Origin Pool (the NGINX) and also, DISABLE HOST REWRITE. We don't want to overwrite the host header, as NGINX needs to know the LB FQDN (For SAML redirection when user is authenticated successfully)
Click on Advanced Options and Add these 2 headers
- X-Forwarded-Proto
- X-Forwarded-Port
They are requested by the N+ OIDC module to redirect the user to the LB after the authentication.
Enable Persistency on HTTP LB
SAML is a stateful protocol. You must enable Persistency on LB in order to come back to the same POD during the SAML Handshake.
You are DONE, congrats.
Great article Matt_Dierick . Another good question is if you can send traffic to a not public application without public ip address that is connected with a CE Edge using Nginx on RE as using Nginx on CE with vK8s will solve this but I wonder if there is a way to use the NGINX on the RE and then forward traffic to the CE Edge.
Maybe if an LB is created on the local CE node and NGINX has in the server farm the LB ip address that on the CE but I never tested this if traffic will be forwarded from the RE to the CE using the IPsec tunnel.
- Matt_Dierick
Employee
Nikoolayy1 I'm almost 99,9999% sure we can do it as the N+ in vk8s has access to the F5XC internal DNS to resolve the internal LB exposed on the CE.
Matt_Dierick I can confirm that you are right as just the LB that is going to connect the backend app through the CE tunnel to the NGINX on the RE needs to advertised to the kubernetes on the RE as shown in f5devcentral/xchacedemoguide (github.com) and then the NGINX will use the internal kubernetes DNS with the LB domain name.