Administrator users of Fortianalyzer, Fortimanager, and Fortigate authenticated via RADIUS


RADIUS users workflow

Intro

Removing locally stored passwords from the Fortinet devices is a good step in securing the admin access. While you have to keep at least one local admin-level user for disaster recovery scenarios, the day-to-day changes are best being done by admins authenticated remotely via LDAP/TACACS+/LDAP. In this post I wll show how to do it in FGT/FAZ/FMG against RADIUS server. The RADIUS server will be Windows Server 2019 NPS.

Decide whether to use Wildcard user on FAZ/FMG/FGT or only specific users.

Fortinet created a special setting in the administrator users config - Wildcard user authentication, which in GUI is usually called Match all users on remote server.

When you choose the Wildcard user it means Fortinet device is NOT aware of any usernames at all, all users and their passwords are stored on the remote RADIUS server. And if the RADIUS server authenticates any user successfully, FGT/FAZ/FMG will be happy as well and will assign the access profile set for the Wildcard User, or the one sent by RADIUS.

The advantage of the Wildcard User is that we do not need to manage users on the device - disabling/removing/adding - all is being done on RADIUS server. The disadvantage is that if RADIUS server admin makes a mistake and does not restrict what users can authenticate against this FGT/FMG/FA device, ANY valid user on RADIUS server may potentially log in as admin-level user.

The alternative is to use/create specific admin-level users of type RADIUS, that will still check password and autheticate against RADIUS.

Important
When there are multiple Wildcard Users configured on the same Fortinet device - the first in the table from top to the bottom match wins. If there are both - specific/individual and Wildcard users present - the specific users always match first, and only after that the Wildcard is tried.

Additionally, we have to decide whether to enable profile override - when this option is enabled, the profile sent for a user from the RADIUS server overrides the profile set at the Fortinet device. This way we can assign different access profiles to different users, which is desirable.

RADIUS Configuration - Windows NPS

The intial RADIUS configs done on the NPS are the same for all Fortinet devices: Fortigate, FortiManager, and FortiAnalyzer.

Install Network Policy Role (NPS)

install NPS for RADIUS

Open NPS management console

NPS tools open

Integrate NPS with local Active Directory

Note
if it is a 1st configuration of NPS, make sure to integrate it with Active Directory (if NPS is installed on DC).
NPS console register wtih AD

Create in NPS console RADIUS clients signifying each network device (FGT, FAZ, FMG)

Next, we create RADIUS clients for each Fortinet device that needs to authenticate against this NPS using their IPs and setting shared secret.

Fortigate (10.100.104.13):

nps radius client fgt

FAZ (10.100.104.17):

nps radius client faz

FMG (10.100.104.252):

nps radius client fmg

Create Connection Request Policy for each client

  • Next, is the Connection Policy. I will be matching on RADIUS Client IPs (i.e. the same IPs I used in RADIUS client creation above) as condition:

FGT

nps connection policy fgt
nps connection policy fgt add condition
nps connection policy fgt add condition2
nps connection policy fgt add condition3

After that just click on Next, as Group membership for users on AD we will specify in Network Policy in the next step, not in the Connection Request Policy.

nps connection policy fgt next1
nps connection policy fgt next2

We create the same Connection Request Policies for FMG and FAZ, and they differ only by RADIUS Client IP.

Create Network Policy for each RADIUS client matching on AD Groups membership for end users

In this AD topology, I created 4 AD users adminad1,…​admiad4, then created a new AD Group named AllFGTAdmins and added all 4 users to it. We will next match RADIUS Network Policy on this AD Group, i.e. only members of this AD group will be able to authenticate according to NPS Network Policy. This way we prevent the mistake of allowing ANY valid AD user to authenticate against our Fortinet devices. In later examples of assigning Access Profiles from RADIUS, I will add new Groups and make them more granular.

nps network policy ad users and group

Here I set as condition in the Network Policy matching on the AD group membership and select just AllFGTAdmins group:

nps network policy match group onad
  • Windows 2019 only - there is a bug in this version of Windows that even though it has default Allow rule for incoming RADIUS requests enabled, the Windows Firewall still blocks incoming RADIUS requests from all. The workaround is either to disable Windows Firewall on Server 2019, or create a Custom Inbound Rule for the same ports UDP 1812 (RADIUS) and 1813 (ACCOUNTING). In the screenshot below I created a custom Inbound Rule:

nps custom radius windows firewall rule
  • Message Authenticator problem - starting with FortiOS 7.2.10, 7.4.5 and 7.6.1 Fortinet hardened their RADIUS handling in the Fortigates to mitigate Blast RADIUS vulnerability (CVE-2024-3596). What was optional (Message-Authenticator attribute) in the RADIUS communication, Fortinet made obligatory, but Server 2019 NPS does NOT have it enabled by default and thus any RADIUS authentication attempt will be dropped by the Fortigate.

Running dia deb app fnbamd -1, dia deb en will show the following error:

rad_udp_recv-Recved 250 bytes. Buf sz 8192
_rad_chk_resp_authenticator-The Message Authenticator validation is mandatory now
_rad_chk_resp_authenticator-No Message Authenticator
nbamd_rad_validate_pkt-Invalid digest
rad_rxtx-Error validating radius rsp

And if we do packet capture on the Fortigate, we will see that Fortigate does include this Message Authenticator RADIUS attribute, but the response from NPS does not, and as a result - Fortigate drops successfully authenticated user connection.

nps attribute wireshark

To fix this, enable the following option in NPS Console:

nps enable message authenticator
Note
If your Server 2019 is not regularly updated, enabling this option will be not enough - you have to have security patches from Microsoft installed as well, see https://support.microsoft.com/en-us/topic/july-9-2024-kb5040430-os-build-17763-6054-0bb10c24-db8c-47eb-8fa9-9ebc06afa4e7

Fortigate configuration

Create a RADIUS user to represent the RADIUS server

config user radius
    edit "RAD1"
        set server "10.100.104.184"
        set secret ENC xl1PiA
        set auth-type ms_chap_v2 // Optional - just make sure the same config on NPS
    next
end

Create a user group to include this RADIUS user

config user group
    edit "RAdminGroup"
        set member "RAD1"
    next
end

Create (here) a wildcard admin account and assign RADIUS-containing user group

config system admin
    edit "RAdmins"
        set remote-auth enable
        set accprofile "super_admin"
        set vdom "root"
        set password FLDm,bnK>JHDF // To use if RADIUS server is down
        set wildcard enable
        set remote-group "RAdminGroup"
    next
end

Wildcard User with dummy accprofile assigned on Fortinet device with override enabled to get actual profile name from the RADIUS

We use Vendor Specifc Attirbute (VSA) of 12356 for the Fortinet as vendor, and the attribute 6 Fortinet-Access-Profile which is a string to list accprofile existing on the Fortinet device (you cannot create accprofile on RADIUS, just send its name). See in the References link to all VSA attributes of Fortinet.

Fortigate

To allow the Access Profile to be overriden, we enable this option on admin user (option exists for regular admin users as well as Wildcard users). Also, as a best practice, we create an empty access profile and assign it to this Wildcard user instead of the "super_admin" I assigned above:

config system accprofile
    edit "noaccess"
    next
end
config system admin
    edit "RAdmins"
        set remote-auth enable
        set accprofile "noaccess"
        set vdom "root"
        set wildcard enable
        set remote-group "RAdminGroup"
        set accprofile-override enable <-- ENABLE OVERRIDE
    next
end

User Group containing the RADIUS object:

config user group
    edit "RAdminGroup"
        set member "RAD1"
    next
end

Now let’s set VSA 6 on NPS to the accprofile name of super_admin:

nps assign super admin access profile from radius

And trying successfully to log in with user adminad4 I get the correct super_admin profile from the RADIUS server sent VSA Attribute 6:

[1216] fnbamd_rad_validate_pkt-RADIUS resp code 2
[912] __rad_rxtx-
[1286] fnbamd_rad_process-Result from radius svr 'RAD1' is 0, req 11553634668545
[545] fnbamd_rad_get_vsas-FORTINET attr, type 6, val super_admin
  • Debug (dia deb fnbamd -1)

Before doing any debug we have to understand what messages RADIUS exchanges, what they mean and such as debug lists numeric codes only.

Most popular RADIUS request/response messages/codes as per RFC:

Code Description

1

Access-Request, sent by RADIUS client to the server to authenticate a user.

2

Access-Accept, response from RADIUS server when authenticaiton is successful.

3

Access-Reject, response from RADIUS server when auth has failed.

4

Accounting-Request, request from client to server to start Accounting.

5

Accounting-Response, response to ACK the accounting request

11

Access-Challenge, sent by server to request additional info - usually MFA.

40

Disconnect-Request, sent by the RADIUS server to the client in order to terminate a user session, more relevant to switches/WiFi and IEEE 802.1X.

41

Disconnect-Response, ACK by the RADIUS client to the server.

43

Change-of-Authorization Request (CoA), sent by RADIUS to the client, and contain information for dynamically changing session authorizations.

44

CoA-Response.

Debug output of successful login with user adminad1 with Wildcard admin user:

FGT-Perimeter # [1757] handle_req-Rcvd auth req 10020305883137 for adminad1 in
  opt=00014001 prot=9 svc=6
[333] __compose_group_list_from_req-Group 'RAdminGroup', type 1 <-- FOUND USER
GROUP WITH RADIUS
[508] create_auth_session-Session created for req id 10020305883137

Next FGT is counting all other remote servers configured (none in this case) until reaches RAD1 RADIUS server 10.100.104.184 using MS-CHAP2 (configured, not default) and authenticates against it:

[590] fnbamd_cfg_get_tac_plus_list-
[425] __fnbamd_cfg_get_tac_plus_list_by_admin-
[606] fnbamd_cfg_get_tac_plus_list-Total tac+ servers to try: 0
[840] fnbamd_cfg_get_ldap_list-
[613] __fnbamd_cfg_get_ldap_list_by_admin-
[856] fnbamd_cfg_get_ldap_list-Total LDAP servers to try: 0
[416] ldap_start-Didn't find ldap servers
[316] radius_start-eap_local=0
[896] fnbamd_cfg_get_radius_list-
[675] __fnbamd_cfg_get_radius_list_by_admin-
[456] fnbamd_rad_get-vfid=0, name='RAD1'
[805] __rad_auth_ctx_insert-Loaded RADIUS server 'RAD1'
[663] __add_admin_rad_svr-Loaded RADIUS server 'RAD1' for admin user 'RAdmins'
[818] __rad_auth_ctx_insert_all_usergroup-
[918] fnbamd_cfg_get_radius_list-Total rad servers to try: 1
[1025] fnbamd_cfg_radius_clear_reachability-Clearing RAD
server reachability RAD1:10.100.104.184
[936] fnbamd_rad_get_auth_server-
[1172] fnbamd_rad_auth_ctx_init-User ha_relay? 0.
[295] fnbamd_radius_get_next_auth_prot-Next auth prot MS-CHAPv2
[1107] __auth_ctx_svr_push-Added addr 10.100.104.184:1812 from rad 'RAD1'
[930] __fnbamd_rad_get_next_addr-Next available address
of rad 'RAD1': 10.100.104.184:1812.

[1125] __auth_ctx_start-Connection starts RAD1:10.100.104.184,
addr 10.100.104.184:1812 proto: UDP

[280] __rad_udp_open-Opened radius socket 10, sa_family 2
[945] __rad_conn_start-Socket 10 is created for rad 'RAD1'.
[807] __rad_add_job_timer-
[439] fnbamd_cfg_get_pop3_list-
[417] __fnbamd_cfg_get_pop3_list_by_group-
[422] __fnbamd_cfg_get_pop3_list_by_group-Group 'RAdminGroup'
[449] fnbamd_cfg_get_pop3_list-Total pop3 servers to try: 0
[434] start_remote_auth-Total 1 server(s) to try
[1900] handle_req-r=4
[828] __rad_rxtx-fd 10, state 1(Auth)
[830] __rad_rxtx-Stop rad conn timer.
[837] __rad_rxtx-
[605] fnbamd_rad_make_access_request-

Composes Access-Request (code 1) message to the RADIUS server, using default (not set to custom) source IP, UDP , to the default port 1812:

[328] __create_access_request-Compose RADIUS request
[588] __create_access_request-Created RADIUS Access-Request. Len: 215.
[1171] fnbamd_socket_update_interface-vfid is 0, intf mode is 0, intf name is ,
server address is 10.100.104.184:1812, source address is null,
protocol number is 17, oif id is 0

[353] __rad_udp_send-oif=0, intf_sel.mode=0, intf_sel.name=
[868] __rad_rxtx-Sent radius req to server 'RAD1': fd=10,
IP=10.100.104.184(10.100.104.184:1812) code=1 id=3 len=215
[877] __rad_rxtx-Start rad conn timer.
[828] __rad_rxtx-fd 10, state 1(Auth)
[830] __rad_rxtx-Stop rad conn timer.
[880] __rad_rxtx-
[431] __rad_udp_recv-Recved 268 bytes. Buf sz 8192

Adds attribute Message Autenticator:

[1125] __rad_chk_resp_authenticator-The Message Authenticator validation is mandatory now
[1148] __rad_chk_resp_authenticator-ret=0

RADIUS server response is success: code 2 (ACCESS-ACCEPT):

[1216] fnbamd_rad_validate_pkt-RADIUS resp code 2

[912] __rad_rxtx-

Next is the FNBAMD daemon final result (see table below for values, 0 = success)

[1286] fnbamd_rad_process-Result from radius svr 'RAD1' is 0, req 10020305883137

[868] fnbamd_radius_parse_mschapv2_attr-Decoding TYPE_MS_MPPE_Recv_Key
[791] __radius_decode_mppe_key-Key len after decode 16
[879] fnbamd_radius_parse_mschapv2_attr-Decoding TYPE_MS_MPPE_Send_Key
[791] __radius_decode_mppe_key-Key len after decode 16
[1485] fnbamd_rad_process-Challenged: 0, FTK_Challenge: 0, CHG_PWD: 0,
Invaid_Digest: 0, State_Len: 0
[627] fnbam_user_auth_group_match-req id: 10020305883137, server: RAD1,
local auth: 0, dn match: 0
[206] find_matched_usr_grps-Passed group matching
[909] update_auth_token_session-config does not require 2fa
[239] fnbamd_comm_send_result-Sending result 0 (nid 0) for req 10020305883137, len=2641
[600] destroy_auth_session-delete session 10020305883137
[1347] fnbamd_rads_destroy-
[516] fnbamd_rad_auth_ctx_free-Freeing 'RAD1' ctx

FNBAMD authentication daemon response codes in the debug:

Code Description

0

Success

1

Deny

2

Challenged (password renewal or token is needed)

3

unknown

4

Pending

5

Error

6

Framed IP Conflict

7

Token code is required

8

Need another token due to the previous one is out of sync

9

Response Buffer is too small

10

Authentication time out

11

Max Concurrent authentication sessions are reached

12

Token code is already used.

  • Debug of failed authentication

Here I am using the user adminad5 which exists in AD, and password is correct BUT he is not part of the FGTAllAdmins AD group on the RADIUS server. And therefore, will not match the Network Policy of the RADIUS NPS on Server 2019 and thus NPS will reject it.

Intial process is the same as the above example of successful authentication, up to getting aresponse from the RADIUS:

[1757] handle_req-Rcvd auth req 10269421789186 for adminad5 in
opt=00014001 prot=9 svc=6
[333] __compose_group_list_from_req-Group 'RAdminGroup', type 1
[508] create_auth_session-Session created for req id 10269421789186
[590] fnbamd_cfg_get_tac_plus_list-
[425] __fnbamd_cfg_get_tac_plus_list_by_admin-
[606] fnbamd_cfg_get_tac_plus_list-Total tac+ servers to try: 0
[840] fnbamd_cfg_get_ldap_list-
[613] __fnbamd_cfg_get_ldap_list_by_admin-
[856] fnbamd_cfg_get_ldap_list-Total LDAP servers to try: 0
[416] ldap_start-Didn't find ldap servers
[316] radius_start-eap_local=0
[896] fnbamd_cfg_get_radius_list-
[675] __fnbamd_cfg_get_radius_list_by_admin-
[456] fnbamd_rad_get-vfid=0, name='RAD1'
[805] __rad_auth_ctx_insert-Loaded RADIUS server 'RAD1'
[663] __add_admin_rad_svr-Loaded RADIUS server 'RAD1' for admin user 'RAdmins'
[818] __rad_auth_ctx_insert_all_usergroup-
[918] fnbamd_cfg_get_radius_list-Total rad servers to try: 1
[936] fnbamd_rad_get_auth_server-
[1172] fnbamd_rad_auth_ctx_init-User ha_relay? 0.
[295] fnbamd_radius_get_next_auth_prot-Next auth prot MS-CHAPv2
[1107] __auth_ctx_svr_push-Added addr 10.100.104.184:1812 from rad 'RAD1'
[930] __fnbamd_rad_get_next_addr-Next available address of
rad 'RAD1': 10.100.104.184:1812.
[1125] __auth_ctx_start-Connection starts RAD1:10.100.104.184,
addr 10.100.104.184:1812 proto: UDP
[280] __rad_udp_open-Opened radius socket 10, sa_family 2
[945] __rad_conn_start-Socket 10 is created for rad 'RAD1'.
[807] __rad_add_job_timer-
[439] fnbamd_cfg_get_pop3_list-
[417] __fnbamd_cfg_get_pop3_list_by_group-
[422] __fnbamd_cfg_get_pop3_list_by_group-Group 'RAdminGroup'
[449] fnbamd_cfg_get_pop3_list-Total pop3 servers to try: 0
[434] start_remote_auth-Total 1 server(s) to try
[1900] handle_req-r=4
[828] __rad_rxtx-fd 10, state 1(Auth)
[830] __rad_rxtx-Stop rad conn timer.
[837] __rad_rxtx-
[605] fnbamd_rad_make_access_request-
[328] __create_access_request-Compose RADIUS request
[588] __create_access_request-Created RADIUS Access-Request. Len: 215.
[1171] fnbamd_socket_update_interface-vfid is 0, intf mode is 0, intf name is ,
 server address is 10.100.104.184:1812, source address is null,
 protocol number is 17, oif id is 0
[353] __rad_udp_send-oif=0, intf_sel.mode=0, intf_sel.name=
[868] __rad_rxtx-Sent radius req to server 'RAD1': fd=10,
IP=10.100.104.184(10.100.104.184:1812) code=1 id=5 len=215
[877] __rad_rxtx-Start rad conn timer.
[828] __rad_rxtx-fd 10, state 1(Auth)
[830] __rad_rxtx-Stop rad conn timer.
[880] __rad_rxtx-
[431] __rad_udp_recv-Recved 60 bytes. Buf sz 8192
[1125] __rad_chk_resp_authenticator-The Message Authenticator validation is mandatory now
[1148] __rad_chk_resp_authenticator-ret=0

What differs is the RADIUS server response - here it is 3 (ACCESS-REJECT), also FNBAMD daemon final result is 1 (DENY):

[1216] fnbamd_rad_validate_pkt-RADIUS resp code 3
[624] fnbamd_rad_extract_chap_error-CHAP err: E=649 R=0 V=3
[1028] __rad_error-Ret 1, st = 1.
[295] fnbamd_radius_get_next_auth_prot-Next auth prot ??
[1077] __rad_error-
[306] __rad_udp_close-closed.
[964] __rad_conn_stop-Stop rad conn timer.
[1286] fnbamd_rad_process-Result from radius svr 'RAD1' is 1, req 10269421789186

FortiAnalyzer

  • Create RADIUS user to set parameters for communication with the RADIUS server:

config system admin radius
    edit "RAD-184"
        set server "10.100.104.184"
        set secret ENC NTEwNjAxNDMzN
        set auth-type mschap2
    next
end
  • Create a Wildcard admin-level user, set profile to built-in profile w/o actual permissions, set ADOM to "all", to be later overridden by the RADIUS server response (as a best practice option you could create a new ADOM w/o any devices in it and use this ADOM as default log-in ADOM):

config system admin user
    edit "RAwildcard"
        set profileid "No_Permission_User"<-- BUILT-IN PROFILE
        set adom-access all
        set user_type radius
        set radius_server "RAD-184"
            config meta-data
                edit "Contact Email"
                next
                edit "Contact Phone"
                next
            end
        set wildcard enable
        set ext-auth-accprofile-override enable
        set ext-auth-adom-override enable
    next
end

FortiManager

The config in FMG is pretty much identical to the FAZ, so I will only show this example.

  • Create RADIUS server

config system admin radius
    edit "RAD1"
        set server "10.100.104.184"
        set secret ENC MTUxMTg4NTA
        set auth-type mschap2
    next
end

Or in GUI System Settings → Remote Authentication:

nps fmg1
  • Create Wildcard user

nps fmg2
config system admin user

    edit "RAWildcard"
        set profileid "No_Permission_User"
        set adom-access all
            set policy-package "all_policy_packages"
            set policy-block "all_policy_blocks"
        set user_type radius
        set radius_server "RAD1"
            config meta-data
                edit "Contact Email"
                next
                edit "Contact Phone"
                next
            end
        set wildcard enable
        set ext-auth-accprofile-override enable
        set ext-auth-adom-override enable
    next
end

And the same drill - create NPS Policy on RADIUS server to send FMG at least VSA Attribute 6 - name of the access profile, and possibly VSA Attribute 3 - ADOM name.

  • Debug on FMG dia deb app auth 8

connecting to server 0: 10.100.104.184 ip=10.100.104.184 port=1812/udp
send request: type=mschap2 id=35
  got reply: code=accept(2) id=35
  Message-Authenticator: len=16
  Ftnt-Profile: Super_User
  Ftnt-Adom: root
  0-7: len=4
  0-6: len=4
  0-25: len=44
  311-17: len=34
  311-16: len=34
  311-26: pS=EB01A13608E95CC4F996F80FD2CE58D3665C1DAB
  311-10: pARGO
success
 success

Additional logs on authentication failure can be found in System Settings → Event Logs, but they are not very detailed.

Here is example of successful and failed logins:

nps fmg3

Wildcard user with accprofile override enabled and 2 user groups on NPS, one to assign super_admin profile, 2nd - readonly profile

As the decision what accprofile to assign to a user based on user’s group membership in AD is done totally on the NPS side, all configs are being done on NPS side. The Fortinet device side uses the regular Wildcard user with accprofile override enabled.

Fortigate

NPS configs. Here I create 2 Network Policies - FGT-readonly and FGT-superadmin. The 1st will assign any user in the AD Group FGTreadonly the accprofile (via VSA Attribute) "readonly" located on the Fortigate already. Users in the AD group FGTsuperadmin, after authentication will get profile "super_admin". To the FGTreadonly group I added only adminad5 user, and to the FGTsuperadmin AD Group adminad4, adminad3 etc.

  • NPS, FGT-readonly policy:

nps readonly1
nps readonly2
  • NPS, FGT-superadmin policy:

nps superadmin1
nps superadmin2

FortiManager

For this and the next example I will only show Fortianalyzer configs as in both cases the configuration is the same for both FAZ & FMG.

Fortianalyzer

The NPS side is the same as for FGT - create 2 new Network Policies with Conditions of RADIUS Client IP (FAZ) and user group membership, sending for each policy different accprofile name via VSA Attribute 6 - "readonly" and "Super_User" (there is no "super_admin" profile in FAZ unless you create a custom one with that name).

  • readonly Network Policy of NPS for FAZ:

nps faz readonly network policy
nps faz readonly network policy2
  • super_user Network Policy of NPS:

nps faz superuser1

Fortianalyzer with overriding not only accprofile but ADOM of the user as well

Fortinet have additional helpful VSA Attribute - 3 Fortinet-Vdom-Name which when sent from RADIUS can be used by Fortigate/FAZ/FMG/etc to override the default VDOM/ADOM the user can access.

NPS: For this I created a new AD Group "FAZ-syslogadom" that contains only adminad8 user. I create then new Network Policy to match FAZ IP and this AD Group. And finally, I set not only VSA Attribute 6 - accprofile, but also VSA Attribute 3 - ADOM name to "Syslog" to be sent by RADIUS server.

Note
As I want to assign this user write/read full rights BUT to the specific ADOM he has been assigned to, I have to create a new accprofile where "ADOM" settings is "Read only", so this user cannot change to a different ADOM after log in. If I were to assign it the built-in "Super_User" profile, this would allow the user to change to another ADOM freely.

Here is the accprofile I created:

nps faz accprofile to single adom

And on CLI:

config system admin profile
    edit "ADOMSuper_User"
        set system-setting read-write
        set adom-switch read
        set device-manager read-write
        set device-op read-write
        set device-wan-link-load-balance read-write
        set device-ap read-write
        set device-fortiswitch read-write
        set device-fortiextender read-write
        set adom-lock read-write
        set device-policy-package-lock read-write
        set extension-access read-write
        set log-viewer read-write
        set fabric-viewer read-write
        set report-viewer read-write
        set event-management read-write
        set update-incidents read-write
        set triage-events read-write
        set run-report read-write
        set execute-playbook read-write
        set script-access read-write
        set fgt-gui-proxy disable
        set ips-lock none
    next
end
nps faz specific adom only

FAZ Debug (dia deb app auth -1)

Case 1: Debug of successful authentication with the user adminad7 getting "readonly" profile with access to all ADOMs:

FAZ-AWS # diagnose debug application auth -1

FAZ-AWS # dia deb enab

FAZ-AWS #
s9: auth request: user=adminad7 from=GUI(10.100.104.13)
s9: wildcard admin: RAwildcard
s9:   start radius: RAD-184
s9:RAD-184: connect to server 0: 10.100.104.184 ip=10.100.104.184 port=1812
s9:RAD-184: send request: type=mschap2 id=6
s9:RAD-184:   got reply: code=accept(2) id=6
s9:RAD-184:   0-80: jZ9:RAD-184:   ftnt-profile: readonly
s9:RAD-184:   0-7: len=4
s9:RAD-184:   0-6: len=4
s9:RAD-184:   0-25: len=44
s9:RAD-184:   311-17: len=34
s9:RAD-184:   311-16: len=34
s9:RAD-184:   311-26: 7S=55F620A3763E7D99149FFBCC96AEDF195E6C862E
s9:RAD-184:   311-10: 7ARGO
s9:RAD-184: success
s9: profile from server: readonly
s9: wildcard admin matched: RAwildcard
s9: profile-override: readonly
s9: no adom from server, use adoms in admin setting
s9: auth result: success
  • Case 2: Here I mis-spelled access profile name "super_user" instead of "Super_User" and got an error that such profile does not exist on FAZ and user log in was rejected:

s11: auth request: user=adminad4 from=GUI(10.100.104.13)
s11: wildcard admin: RAwildcard
s11:   start radius: RAD-184
s11:RAD-184: connect to server 0: 10.100.104.184 ip=10.100.104.184 port=1812
s11:RAD-184: send request: type=mschap2 id=8
s11:RAD-184:   got reply: code=accept(2) id=8
s11:RAD-184:   0-80: len=16
s11:RAD-184:   ftnt-profile: super_user
s11:RAD-184:   0-7: len=4
s11:RAD-184:   0-6: len=4
s11:RAD-184:   0-25: len=44
s11:RAD-184:   311-17: len=34
s11:RAD-184:   311-16: len=34
s11:RAD-184:   311-26: 689AEA94593EF06B7659C41254F31B68A85D628
s11:RAD-184:   311-10: O
s11:RAD-184: success
s11: profile from server: super_user (invalid)
s11: wildcard admin matched: RAwildcard
s11: no valid profile from server
s11: auth result: denied
  • Case 3: Debug of successful log in of adminad8 getting accprofile ADOMSuper_User and being forced to the ADOM "Syslog":

s15: auth request: user=adminad8 from=GUI(10.100.104.13)
s15: wildcard admin: RAwildcard
s15:   start radius: RAD-184
s15:RAD-184: connect to server 0: 10.100.104.184 ip=10.100.104.184 port=1812
s15:RAD-184: send request: type=mschap2 id=12
s15:RAD-184:   got reply: code=accept(2) id=12
s15:RAD-184:   0-80: len=16
s15:RAD-184:   ftnt-adom: Syslog
s15:RAD-184:   ftnt-profile: ADOMSuper_User
s15:RAD-184:   0-7: len=4
s15:RAD-184:   0-6: len=4
s15:RAD-184:   0-25: len=44
s15:RAD-184:   311-17: len=34
s15:RAD-184:   311-16: len=34
s15:RAD-184:   311-26: 12AC271969CF7E420358CD1B621D7022BAA5352
s15:RAD-184:   311-10: O
s15:RAD-184: success
s15: profile from server: ADOMSuper_User
s15: wildcard admin matched: RAwildcard
s15: profile-override: ADOMSuper_User
s15: adom-override: Syslog
s15: auth result: success

Specific (not wildcard) user with access profile assigned on Fortinet device

When creating individual users on Fortinet device it is logical to assign them the needed access profile as well.

I create a new Network Policy on Server 2019 here to all ALL Domain Users to be able to authenticate to simplify the case (the Group matching on NPS would work as well).

nps specific admin account no wildcard

And I disabled the NPS policy matching on AllFGTAdmins group in AD (moving it down would still leave it active and match on it).

Next, I remove the Wildcard admin account on Fortigate to prevent the case of ANY Domain User connecting as admin (the new user would NOT use this Wildcard anyway, but for security sake). The alternative would be to create NPS Policy for a specific AD Group of which this user is member of:

config sys admin
del RAdmins

And create a new admin user adminad5 to be authenticated against NPS:

config system admin
    edit "adminad5"
        set remote-auth enable
        set accprofile "super_admin"
        set vdom "root"
        set remote-group "RAdminGroup"
        set password ENC SH2cnkEXtY
    next
end

Verifying on CLI:

FGT-Perimeter # diagnose test authserver radius RAD1 mschap2 adminad5 secr3t

authenticate 'adminad5' against 'mschap2' succeeded, server=primary
assigned_rad_session_id=9771184754689 session_timeout=0 secs idle_timeout=0 secs!

Specific (not wildcard) user with access profile assigned by FGT AND Group Matching on Fortigate side

RADIUS has no notion of Groups on Fortinet device, but we do have an option to use VSA Fortinet-specific Attribute Fortinet-Group-Name code 1 as a String - we just set in Network Policy of NPS for matching conditions to send some custom string (doesn’t have to match the user’s Group in AD) which Fortigate will match to the string we configure in Fortigate as well. If the string in FGT matches the string the RADIUS sends when a user successfully autheticated, Fortigate will allow it as well. When using this feature with VPN Groups on Fortigate, it makes sense to match the existing groups exactly.

Config on the NPS side steps:

nps send group name as vsa attribute

Configure "group" matching on the Fortigate, remember - it is just string against string matching, also it is case-sensitive:

config user group

    edit "RAdminGroup"
        set member "RAD1"
        config match
            edit 1
                set server-name "RAD1"
                set group-name "FGTADMINS"
            next
        end
    next
end

Debug (excerpts only, as much of it is the same as above):

User adminad5 matches RADIUS User Group on the FGT:

[1757] handle_req-Rcvd auth req 10265108312068 for adminad5 in
[333] __compose_group_list_from_req-Group 'RAdminGroup', type 1
[456] fnbamd_rad_get-vfid=0, name='RAD1'
[805] __rad_auth_ctx_insert-Loaded RADIUS server 'RAD1'
[663] __add_admin_rad_svr-Loaded RADIUS server 'RAD1' for admin user 'adminad5'

RADIUS response (success):

[1125] __rad_chk_resp_authenticator-The Message Authenticator validation is mandatory now
[1148] __rad_chk_resp_authenticator-ret=0
[1216] fnbamd_rad_validate_pkt-RADIUS resp code 2

AFTER successfully authenticating the user adminad5 by RADIUS, next step is to match on the string sent as VSA Attribute - these actions are independent, RADIUS may send SUCCESS but then FGT will fail user if the VSA Attribute doesn’t match:

[1286] fnbamd_rad_process-Result from radius svr 'RAD1' is 0, req 10265108312068
[502] fnbamd_rad_get_vsas-FORTINET attr, type 1, val FGTADMINS
[868] fnbamd_radius_parse_mschapv2_attr-Decoding TYPE_MS_MPPE_Recv_Key
[791] __radius_decode_mppe_key-Key len after decode 16
[879] fnbamd_radius_parse_mschapv2_attr-Decoding TYPE_MS_MPPE_Send_Key
[791] __radius_decode_mppe_key-Key len after decode 16
[1485] fnbamd_rad_process-Challenged: 0, FTK_Challenge: 0, CHG_PWD: 0, Invaid_Digest: 0, State_Len: 0
[627] fnbam_user_auth_group_match-req id: 10265108312068, server: RAD1, local auth: 0, dn match: 0
[581] __group_match-Check if RAD1 is a group member
[587] __group_match-Group 'RAdminGroup' passed group matching
[590] __group_match-Add matched group 'RAdminGroup'(3)
  • Example of failed login on group-name string mismatch. Below is debug of when I intentionally put group-name on FGT in lower case, while it is upper case on RADIUS:

    edit "RAdminGroup"
        set member "RAD1"
        config match
            edit 1
                set server-name "RAD1"
                set group-name "fgtadmins"
            next
        end
    next
end

Pay attention to the RADIUS response code - 2 (success), but in the 2nd step of matching the string, FGT fails the user:

[1216] fnbamd_rad_validate_pkt-RADIUS resp code 2
[912] __rad_rxtx-
[1286] fnbamd_rad_process-Result from radius svr 'RAD1' is 0, req 10265108312067
[502] fnbamd_rad_get_vsas-FORTINET attr, type 1, val FGTADMINS
[868] fnbamd_radius_parse_mschapv2_attr-Decoding TYPE_MS_MPPE_Recv_Key
[791] __radius_decode_mppe_key-Key len after decode 16
[879] fnbamd_radius_parse_mschapv2_attr-Decoding TYPE_MS_MPPE_Send_Key
[791] __radius_decode_mppe_key-Key len after decode 16
[1485] fnbamd_rad_process-Challenged: 0, FTK_Challenge: 0, CHG_PWD:
0, Invaid_Digest: 0, State_Len: 0
[627] fnbam_user_auth_group_match-req id: 10265108312067, server: RAD1,
local auth: 0, dn match: 0
[581] __group_match-Check if RAD1 is a group member
[209] find_matched_usr_grps-Failed group matching

Fortianalyzer

FAZ also has the option of matching on Group Name sent from RADIUS. It is useful when using wildcard users and authenticating against the same NPS server - we cannot in such case allow any Domain Users as matching condition in NPS Policy, as this would allow any AD users that do not exist on FAZ but do exist in AD to authenticate.

Task: create RADIUS-authenticated user adminad9 on FAZ, when it connects assign it profile ADOMSuper_User and limit his access to the FGT-only ADOM.

So for this, I create user adminad9 on both FAZ and AD. I create a new AD Group FGT-only-adom which will have as a member just user adminad9. And then create NPS Policy matching user on AD Group FGT-only-adom and sending with the response also Fortinet VSA Attribute 1 Group-Name to be additional match on the FAZ side.

  • User adminad9 on the FAZ:

Using the same RADIUS server:

config system admin radius
    edit "RAD-184"
        set server "10.100.104.184"
        set secret ENC MTY2NTg3Nj
        set auth-type mschap2
    next
end

The user with the matching condition of string "FGT-only":

FAZ-AWS # show sys admin user adminad9
config system admin user
    edit "adminad9"
        set profileid "ADOMSuper_User"
        set adom-access specify
            set adom "FGT-only" (1)
        set dev-group "FGT-Perimeter-firewalls" (2)
        set user_type radius
        set radius_server "RAD-184"
            config meta-data
                edit "Contact Email"
                next
                edit "Contact Phone"
                next
            end
        set ext-auth-group-match "FGT-only"  (3)
        set use-global-theme disable
        set user-theme autumn  (4)
    next
end
  1. Limit to this ADOM only

  2. (Opt) Inside the ADOM, limit access to this device group only

  3. Match on this string sent as VSA Attribute "Group-Name", fail if no match

  4. (Opt) Set the GUI Theme for this user

    • NPS Policy:

nps faz specific user nps policy
nps faz specific user nps policy2

After log in, the user cannot change ADOM, and has Autumn as the theme:

nps faz specific adom only user
  • Debug

s16: auth request: user=adminad9 from=GUI(10.100.104.13)
s16: found admin: adminad9
s16:   start radius: RAD-184
s16:RAD-184: connect to server 0: 10.100.104.184 ip=10.100.104.184 port=1812
s16:RAD-184: send request: type=mschap2 id=13
s16:RAD-184:   got reply: code=accept(2) id=13
s16:RAD-184:   0-80: len=16
s16:RAD-184:   ftnt-group: FGT-only <-- GROUP-NAME SENT FROM RADIUS
s16:RAD-184:   0-7: len=4
s16:RAD-184:   0-6: len=4
s16:RAD-184:   0-25: len=44
s16:RAD-184:   311-17: len=34
s16:RAD-184:   311-16: len=34
s16:RAD-184:   311-26: GS=9ACFB7F404F0530F90AE097C95C0A69B119B250D
s16:RAD-184:   311-10: GARGO
s16:RAD-184: success
s16: auth result: success