Fortigate VPN mit 2FA SAML Authentifizerung gegen Keycloak

Allgemein

Begrifflichkeiten

  • Service Provider → SP → Fortigate
  • Identity Provider → IdP → Keycloak

Auth-Mechanismen

  • Die gezeigte Fortigate Konfiguration erlaubt mehrere Auth-Backends (Fortigate lokale Benutzer, LDAP, SSO/SAML) parallel für das gleiche VPN. Durch Unterscheidung der Gruppen aus den jeweiligen Backends könnte der gleiche Benutzer über 2FA-SAML andere VPN Rechte erhalten, als über einen LDAP Login.

Fallback-User

  • Durch die Kombinationsmöglichkeiten der unterschiedlichen Auth-Mechanismen gibts keine Einschränkungen bei der Kreativität von Fallback-Usern. Die könnten aus dem LDAP kommen oder gar lokal auf der Fortigate konfiguriert sein.

Fortigate Debug Optionen

diagnose debug reset
diagnose debug console timestamp enable
diagnose debug application fnbamd -1
diagnose debug application sslvpn -1
diagnose debug application samld -1
diagnose debug application httpsd -1
diagnose debug enable

Keycloak

  • Key und Zertifikat müssen im Client neugeneriert werden. Die Felder wurden im nachstehenden Json geleert.
  • Die erzeugte Key/Cert Kombination muss auch auf der Fortigate importiert werden.
client_export.json
{
    "clientId": "FortiVPN-SSL",
    "name": "FortiVPN-SSL - SAML Endpoint",
    "description": "2FA für VPN Logins",
    "adminUrl": "https://<Fortigate-FQDN>:<VPN-Port>/remote/saml/login",
    "baseUrl": "https://<Fortigate-FQDN>:<VPN-Port>/",
    "surrogateAuthRequired": false,
    "enabled": true,
    "alwaysDisplayInConsole": false,
    "clientAuthenticatorType": "client-secret",
    "redirectUris": [
        "https://<Fortigate-FQDN>:<VPN-Port>/*"
    ],
    "webOrigins": [],
    "notBefore": 0,
    "bearerOnly": false,
    "consentRequired": false,
    "standardFlowEnabled": true,
    "implicitFlowEnabled": false,
    "directAccessGrantsEnabled": false,
    "serviceAccountsEnabled": false,
    "publicClient": false,
    "frontchannelLogout": true,
    "protocol": "saml",
    "attributes": {
        "saml.force.post.binding": "true",
        "saml.multivalued.roles": "false",
        "oauth2.device.authorization.grant.enabled": "false",
        "backchannel.logout.revoke.offline.tokens": "false",
        "saml.server.signature.keyinfo.ext": "false",
        "use.refresh.tokens": "true",
        "saml.signing.certificate": "",
        "oidc.ciba.grant.enabled": "false",
        "backchannel.logout.session.required": "false",
        "client_credentials.use_refresh_token": "false",
        "saml.signature.algorithm": "RSA_SHA256",
        "require.pushed.authorization.requests": "false",
        "saml.client.signature": "true",
        "saml.signing.private.key": "",
        "saml.server.signature.keyinfo.xmlSigKeyInfoKeyNameTransformer": "KEY_ID",
        "id.token.as.detached.signature": "false",
        "saml.assertion.signature": "false",
        "saml.encrypt": "false",
        "saml.server.signature": "true",
        "exclude.session.state.from.auth.response": "false",
        "saml.artifact.binding.identifier": "rS7OdT8p+OEnIYCZRDR+FCfTfMo=",
        "saml.artifact.binding": "false",
        "saml_force_name_id_format": "true",
        "tls.client.certificate.bound.access.tokens": "false",
        "saml.authnstatement": "true",
        "display.on.consent.screen": "false",
        "saml_name_id_format": "username",
        "saml.onetimeuse.condition": "false",
        "saml_signature_canonicalization_method": "http://www.w3.org/2001/10/xml-exc-c14n#"
    },
    "authenticationFlowBindingOverrides": {
        "browser": ""
    },
    "fullScopeAllowed": true,
    "nodeReRegistrationTimeout": -1,
    "protocolMappers": [
        {
            "name": "username",
            "protocol": "saml",
            "protocolMapper": "saml-user-property-mapper",
            "consentRequired": false,
            "config": {
                "user.attribute": "username",
                "friendly.name": "username",
                "attribute.name": "username"
            }
        },
        {
            "name": "role list",
            "protocol": "saml",
            "protocolMapper": "saml-role-list-mapper",
            "consentRequired": false,
            "config": {
                "single": "true",
                "attribute.nameformat": "Basic",
                "attribute.name": "Role"
            }
        }
    ],
    "defaultClientScopes": [
        "role_list"
    ],
    "optionalClientScopes": [],
    "access": {
        "view": true,
        "configure": true,
        "manage": true
    }
}

Fortigate

  • Zertifikate
    • IDM-FortiVPN-SSL → Cert+Key aus dem Keycloak Client
    • REMOTE_Cert_1 → Signatur-Zertifikat der Keycloak Realm
config user saml
    edit "idm-sslvpn"
        set cert "IDM-FortiVPN-SSL"
        set entity-id "FortiVPN-SSL"
        set single-sign-on-url "https://<Fortigate-FQDN>:<VPN-Port>/remote/saml/login"
        set single-logout-url "https://<Fortigate-FQDN>:<VPN-Port>/remote/saml/logout"
        set idp-entity-id "https://<Keycloak-FQDN>/auth/realms/<Realmname>"
        set idp-single-sign-on-url "https://<Keycloak-FQDN>/auth/realms/<Realmname>/protocol/saml"
        set idp-single-logout-url "https://<Keycloak-FQDN>/auth/realms/<Realmname>/protocol/saml"
        set idp-cert "REMOTE_Cert_1"
        set user-name "username"
        set group-name "Role"
    next
end
 
config user group
    edit "idm_vpn-internal"
        set member "idm-sslvpn"
        config match
            edit 1
                set server-name "idm-sslvpn"
                set group-name "VPN-Internal"
            next
        end
    next
 
    edit "idm_vpn-corenet"
        set member "idm-sslvpn"
        config match
            edit 1
                set server-name "idm-sslvpn"
                set group-name "VPN-CoreNet"
            next
        end
    next
 
    edit "idm_vpn-forbidden"
        set member "idm-sslvpn"
    next
end
 
 
config vpn ssl settings
    set servercert "Fortinet_SSL"
    set tunnel-ip-pools "SSLVPN_TUNNEL_ADDR1"
    set port 8443
    set source-interface "wan"
    set source-address "all"
    set source-address6 "all"
    set default-portal "tunnel-access"
    config authentication-rule
        edit 1
            set groups "idm_vpn-corenet"
            set portal "SSL-VPN_Core"
        next
        edit 2
            set groups "idm_vpn-internal"
            set portal "SSL-VPN_Internal"
        next
    end
end

FortiClient

  • SSO Login Feature in den Verbindungs-Optionen aktivieren
  • Feature ab Version 6.4.0 enthalten. Getestet wurde bisher nur mit Version 7.0.1 unter Windows.
    • MacOS & Linux FortiClient hat die SSO Login Option in der GUI. Test steht noch aus.