Checkmk
to checkmk.com

1. Introduction

In this article you will learn how to set up a login using Secure Assertion Markup Language (SAML). The implementation in Checkmk runs at the Apache level via mod_auth_mellon, which takes on the role of a Service Provider (SP) in the SAML design.

This guide describes in detail the procedure for using Active Directory Federation Services (AD FS) as the Identity Provider (IDP). In further sections, you will receive instructions on how to configure other IDPs, such as Azure AD and Micro Focus NetIQ Access Manager.

Note: This feature is not supported by SUSE Linux Enterprise Server (SUSE) versions 12 SP3, 12 SP4 and 15 due to missing dependencies (SLES 15 SP1 and later allow the connection).

Caution: The whole topic of transport encryption (TLS/SSL) is only included in the examples here in a simple implementation for demonstration purposes. In production environments with your own CA and diligent certificate handling, there will be corresponding deviations that depend on your own infrastructure.

2. Logging in with Active Directory Federation Services

2.1. Prerequisites

Logging on to Checkmk using Active Directory is basically relatively simple: AD Federation Service (FS) serves as Identity Provider (IDP), the Apache module mod_auth_mellon provides authentication as a Service Provider via Security Assertion Markup Language (SAML). Prerequisites for this tutorial are accordingly:

  • Functioning LDAP-AD integration

  • Working AD FS as IDP

  • Checkmk server with SSL

  • A supported operating system. Curently, SLES15 SP4 is not supported!

The setup is accomplished in three steps:

  1. Configuration of Apache (one result: XML file with metadata).

  2. Configuring AD FS: setting up Relying Party Trust with Mellon metadata.

  3. Enabling the login to Checkmk itself.

2.2. Configuration of Apache

Additional dependencies may still need to be installed, under Debian/Ubuntu for example:

root@linux# apt-get update
root@linux# apt-get install wget libxmlsec1-openssl

Note: In the Checkmk appliance, libxmlsec1-openssl is already installed.

This is, of course, about configuring the site’s own Apache server, so log in there first:

root@linux# omd su mysite

Now create a directory for mod_auth_mellon and switch to it:

OMD[mysite]:~$ mkdir etc/apache/mellon
OMD[mysite]:~$ cd etc/apache/mellon

Now make mellon_create_metadata executable and run it specifying your server as well as your site with the mellon suffix:

OMD[mysite]:~/etc/apache/mellon$ chmod +x ~/bin/mellon_create_metadata
OMD[mysite]:~/etc/apache/mellon$ mellon_create_metadata https://myserver "https://myserver/mysite/mellon"

This module generates three files: Certificate (.cert), key (.key) and static metadata (.xml). The .xml file is not required and can be deleted:

OMD[mysite]:~/etc/apache/mellon$ rm *.xml

Rename the key and certificate files for simplicity:

OMD[mysite]:~/etc/apache/mellon$ mv .key mellon.key
OMD[mysite]:~/etc/apache/mellon$ mv .cert mellon.cert

Now get the required metadata directly from your AD-FS server (here myadfs) and save it as idp-metadata.xml:

OMD[mysite]:~/etc/apache/mellon$ wget --no-check-certificate -O ./idp-metadata.xml https://myadfs/FederationMetadata/2007-06/FederationMetadata.xml

Now you need the public certificate for the AD-FS server, which is stored in the idp-public-key.pem file:

OMD[mysite]:~/etc/apache/mellon$ echo -n | openssl s_client -connect myadfs:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | openssl x509 -pubkey -noout > idp-public-key.pem

Just in case you are wondering about the echo -n: This is used to terminate the following SSL session.

Note: The certificate should, or even must be uploaded to the trust store in case, for example, the IDP service checks the certificate chain. For more information on this topic, see the HTTPS article.

As a last step, replace the authentication configuration file ~/etc/apache/conf.d/auth.conf with the following variant — specifying your Checkmk server (here myserver) and site (here mysite), of course:

~/etc/apache/conf.d/auth.conf
# Set this to the Name of your Checkmk site, e.g.
#Define SITE
Define SITE mysite

# ServerName from listen-ports.conf needs to be overwritten here
# and being set to the URL of the real server. auth_mellon uses this
# to generate the needed URLs in the metadata
ServerName https://myserver

# Load the module.
<IfModule !mod_auth_mellon.c>

	LoadModule auth_mellon_module /omd/sites/${SITE}/lib/apache/modules/mod_auth_mellon.so

</IfModule>

# Only enable this for debugging purposes
#MellonDiagnosticsFile /opt/omd/sites/${SITE}/tmp/mellon_diagnostics.txt
#MellonDiagnosticsEnable On

<Location /${SITE}>

	# Use SAML auth only in case there is no Checkmk authentication
	# cookie provided by the user and whitelist also some other required URLs
	<If "! %{HTTP_COOKIE} =~ /^(.*;)?auth_${SITE}/ && \
		! %{REQUEST_URI} = '/${SITE}/check_mk/register_agent.py' && \
		! %{REQUEST_URI} = '/${SITE}/check_mk/deploy_agent.py' && \
		! %{REQUEST_URI} = '/${SITE}/check_mk/run_cron.py' && \
		! %{REQUEST_URI} = '/${SITE}/check_mk/webapi.py' && \
		! %{REQUEST_URI} = '/${SITE}/check_mk/automation.py' && \
		! %{REQUEST_URI} -strmatch '/${SITE}/check_mk/api/*' && \
		! %{REQUEST_URI} = '/${SITE}check_mk/ajax_graph_images.py' && \
		! %{QUERY_STRING} =~ /(_secret=|auth_|register_agent)/ && \
		! %{REQUEST_URI} =~ m#^/${SITE}/(omd/|check_mk/((images|themes)/.*\.(png|svg)|login\.py|.*\.(css|js)))# ">

		MellonIdPMetadataFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-metadata.xml
		MellonIdPPublicKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-public-key.pem
		MellonSPCertFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.cert
		MellonSPPrivateKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.key
		MellonEndpointPath "/${SITE}/mellon"
		MellonDefaultLoginPath "/${SITE}/check_mk/"

		Order allow,deny
		Allow from all

		MellonSecureCookie On
		MellonCookieSameSite None

		AuthType Mellon
		AuthName "Checkmk SAML Login"
		MellonEnable auth
		Require valid-user

		# Get Username
		# ADFS sends username as DOMAIN\username pair.
		# Checkmk just wants the username.
		RewriteEngine on
		RequestHeader set X-Remote-User "expr=%{REMOTE_USER}"
		RequestHeader edit X-Remote-User "^.*\\\(.*)$" "$1"

		# When SAML auth fails, show the login page to the user. This should only happen,
		# if e.g. the mellon cookie is lost/rejected or if the IDP is misconfigured.
		# A failed login at the IDP will not return you here at all.

    ErrorDocument 401 '<html> \
      <head> \
        <meta http-equiv="refresh" content="1; URL=/${SITE}/check_mk/login.py"> \
      </head> \
      <body> \
        SAML authentication failed, redirecting to login page. \
        <a href="/${SITE}/check_mk/login.py">Click here</a>. \
      </body> \
    </html>'

	</If>

	# This header is also needed after authentication (outside of the If clause)
	RequestHeader set X-Remote-User "expr=%{REMOTE_USER}"
	RequestHeader edit X-Remote-User "^.*\\\(.*)$" "$1"

</Location>

Then restart Apache:

OMD[mysite]:~/etc/apache/mellon$ omd restart apache

Last but not least, you now download the dynamically created Mellon metadata as an XML file so that you can import it into AD Management right away:

OMD[mysite]:~/etc/apache/mellon$ wget https://myserver/mysite/mellon/metadata -o metadata.xml

3. Configuring Active Directory

To create a Relying Party Trust in AD FS, do the following:

Start the AD FS interface:

saml adfs 01

Click Add Relying Party Trust:

saml adfs 02

Leave the option set to Claims aware and continue with the Start button:

saml adfs 03

Now select Import data on the relying party from a file and specify the XML file you just downloaded:

saml adfs 04

You can safely ignore the AD FS Management warning:

saml adfs 05

Under Specify Display Name now enter Checkmk as name:

saml adfs 06

When assigning permissions, for testing purposes you can first select for Choose Access Control Policy the value Permit everyone; you should later change this to Permit specific group.

saml adfs 07

Confirm the summary under Ready to Add Trust:

saml adfs 08

Finally, confirm the Finish dialog and keep the check mark at Configure claims issuance policy for this application:

saml adfs 09

Select the Relying Party Trust you just created and then start the editor with Edit Claim Issuance Policy…​ :

saml adfs 10

Add a new rule in the following dialog via Add Rule…​:

saml adfs 11

In the first step Select Rule Template select Transform to Incoming Claim and confirm:

saml adfs 12

In the second step Configure Rule set the following values:

  • Incoming claim type: Windows account name

  • Outgoing claim type: Name ID

  • Outgoing name ID format: Transient Identifier

saml adfs 13

This also completes the AD-FS configuration. FS can now derive authentication for Checkmk from Windows authentication, which you instruct to authenticate users via HTTP requests in the next step.

4. Configure Checkmk

In Checkmk you now only have to activate under Setup > General > Global Settings > User Interface > Authenticate users by incoming HTTP requests at Current settings the Activate HTTP header authentication option.

saml adfs cmk

5. Other IDPs

The following sections only describe the configuration of Mellon/Apache for different IDPs already running. The connection in Checkmk itself is limited in each case to the last step from the detailed AD-FS instructions.

5.1. Azure AD

When Azure AD acts as an IDP, there are some differences in the configuration procedure, for example, the user name can be set directly without being rewritten.

Prerequisites for the following sample configuration:

  • Set UserPrincipalName in LDAP connection as identifier (more information at LDAPwiki.com).

  • Custom Enterprise App in Azure AD with UserPrincipalName as 'name' attribute — more details in the Microsoft documentation).

Here is a sample configuration:

~/etc/apache/conf.d/auth.conf
#Set this to the Name of your Checkmk site, e.g.
# Define SITE mysite
Define SITE mysite

# ServerName from listen-ports.conf needs to be overwritten here
# and being set to the URL of the real server.
# auth_mellon uses this to generate the needed URLs in the metadata.
ServerName https://myserver

# Load the module.
<IfModule !mod_auth_mellon.c>

	LoadModule auth_mellon_module /omd/sites/${SITE}/lib/apache/modules/mod_auth_mellon.so

</IfModule>

# Only enable this for debugging purposes
# MellonDiagnosticsFile /opt/omd/sites/${SITE}/tmp/mellon_diagnostics.log
# MellonDiagnosticsEnable On

<Location /${SITE}>

	# Use SAML auth only in case there is no Checkmk authentication
	# cookie provided by the user and whitelist also some other required URLs.
   <If "! %{HTTP_COOKIE} =~ /^auth_${SITE}/ && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/register_agent.py' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/webapi.py' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/run_cron.py' && \
	! %{REQUEST_URI} = '/${SITE}/check_mk/automation.py' && \
        ! %{REQUEST_URI} -strmatch '/${SITE}/check_mk/api/*' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/deploy_agent.py' && \
		! %{REQUEST_URI} = '/${SITE}check_mk/ajax_graph_images.py' && \
        ! %{QUERY_STRING} =~ /(_secret=|auth_|register_agent)/ && \
		! %{REQUEST_URI} =~ m#^/${SITE}/(omd/|check_mk/((images|themes)/.*\.(png|svg)|login\.py|.*\.(css|js)))# ">

        RequestHeader unset X-Remote-User
        MellonIdPMetadataFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-metadata.xml
        # Azure-AD-specific: Not needed because in metadata:
        #MellonIdPPublicKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-public-key.pem
        MellonSPCertFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.cert
        MellonSPPrivateKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.key
        MellonEndpointPath "/${SITE}/mellon"
        MellonDefaultLoginPath "/${SITE}/check_mk/"

		Order allow,deny
		Allow from all

		MellonSecureCookie On
		MellonCookieSameSite None

		AuthType Mellon
		MellonEnable auth
		require valid-user

        # Azure-AD-specific:
        # Get Username
        # If your assertion offers the username for Checkmk in an attribute you can set it directly as the remote user (REMOTE_USER):
        MellonUser "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
        RequestHeader set X-Remote-User "%{MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name}e" env=MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name

        # When SAML auth fails, show the login page to the user. This should only happen, if e.g. the mellon cookie is lost/rejected or if the IDP is misconfigured.
        # A failed login at the IDP will not return you here at all.
        ErrorDocument 401 '<html> \
          <head> \
            <meta http-equiv="refresh" content="1; URL=/${SITE}/check_mk/login.py"> \
          </head> \
          <body> \
            SAML authentication failed, redirecting to login page. \
            <a href="/${SITE}/check_mk/login.py">Click here</a>. \
          </body> \
        </html>'

	</If>

	# Azure-AD-specific:
	# This header is also needed after authentication (outside of the If clause)
	RequestHeader set X-Remote-User "%{MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name}e" env=MELLON_http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name

</Location>

5.2. NetIQ Access Manager

When NetIQ Access Manager acts as an IDP, there are some differences in the configuration procedure, for example, the user name can be set directly without being rewritten.

Here is an example configuration:

~/etc/apache/conf.d/auth.conf

# Set this to the Name of your Checkmk site, e.g.# Define SITE mysite
# Define SITE mysite
Define SITE mysite

# ServerName from listen-ports.conf needs to be overwritten here
# and being set to the URL of the real server. auth_mellon uses this to generate the needed URLs in the metadata.

ServerName https://myserver.mydomain.tld

# Load the module.
<IfModule !mod_auth_mellon.c>

	LoadModule auth_mellon_module /omd/sites/mysite/lib/apache/modules/mod_auth_mellon.so

</IfModule>

# Only enable this for debugging purposes
#MellonDiagnosticsFile /opt/omd/sites/${SITE}/tmp/mellon_diagnostics.log
#MellonDiagnosticsEnable On

<Location /${SITE}>

	# Use SAML auth only in case there is no Checkmk authentication
	# Cookie provided by the user and whitelist also some other required URLs.

    <If "! %{HTTP_COOKIE} =~ /^auth_${SITE}/ && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/register_agent.py' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/run_cron.py' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/deploy_agent.py' && \
        ! %{REQUEST_URI} = '/${SITE}/check_mk/webapi.py' && \
        ! %{REQUEST_URI} -strmatch '/${SITE}/check_mk/api/*' && \
		! %{REQUEST_URI} = '/${SITE}check_mk/ajax_graph_images.py' && \
        ! %{QUERY_STRING} =~ /(_secret=|auth_|register_agent)/ && \
		! %{REQUEST_URI} =~ m#^/${SITE}/(omd/|check_mk/((images|themes)/.*\.(png|svg)|login\.py|.*\.(css|js)))# ">

        MellonIdPMetadataFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-metadata.xml
        # NetIQ-specific: Not needed because in metadata:
        #MellonIdPPublicKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/idp-public-key.pem
        MellonSPCertFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.cert
        MellonSPPrivateKeyFile /opt/omd/sites/${SITE}/etc/apache/mellon/mellon.key
        MellonEndpointPath "/${SITE}/mellon"
        MellonDefaultLoginPath "/${SITE}/check_mk/"

		Order allow,deny
		Allow from all

		MellonSecureCookie On
		MellonCookieSameSite None

		AuthType Mellon
		MellonEnable auth
		require valid-user


        # NetIQ-specific:
        # Even though it is set as 'optional' in https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf
        # a NetIQ Access Manager requires it to be set.
        # Specified in oasis link above - line 396
        MellonOrganizationName "<countrycode>" "<your organisation name>"
        # Specified in oasis link above - line 443 / 452
        MellonOrganizationURL  "<countrycode>" "<your organisation url>"
        # Specified in oasis link above - line 454
        MellonOrganizationDisplayName "<countrycode>" "<your organisation display name>"

        # NetIQ-specific:
        # If your assertion offers the username for Checkmk in an attribute you can set it directly as the remote user (REMOTE_USER)
        MellonUser "myusername"

        # NetIQ-specific:
        # If the assertion does contain the username (and was set to MellonUser) then you can set the header directly.
        RequestHeader set X-Remote-User "expr=%{REMOTE_USER}"

    # When SAML auth fails, show the login page to the user. This should only happen,
    # if e.g. the mellon cookie is lost/rejected or if the IDP is misconfigured.
    # A failed login at the IDP will not return you here at all.
        ErrorDocument 401 '<html> \
          <head> \
            <meta http-equiv="refresh" content="1; URL=/${SITE}/check_mk/login.py"> \
          </head> \
          <body> \
            SAML authentication failed, redirecting to login page. \
            <a href="/${SITE}/check_mk/login.py">Click here</a>. \
          </body> \
        </html>'

# This header is also needed after authentication (outside of the If clause)
RequestHeader set X-Remote-User "expr=%{REMOTE_USER}"

</Location>
On this page