Configuring RADIUS Admin Auth on FortiGate SD-WAN: RBAC and Three User Profiles (Part 2 of 2)
Part 2 of a two-part series. Part 1 covered why RADIUS is the right AAA choice for most FortiGate SD-WAN deployments, the available RADIUS servers, and when TACACS+ is still defensible. This post is the implementation — what you actually type into the box, the three admin profiles that map to common roles, and the verification commands you’ll wish you’d had open during the first failed login.
The reference design uses Microsoft NPS as the RADIUS server (against on-prem AD) with Fortinet VSAs carrying the access-profile name. The same shape works against FortiAuthenticator, FreeRADIUS, or any RADIUS server that can return VSAs — only the server-side config changes.
Reference architecture
| Component | Detail |
|---|---|
| FortiGate | Branch SD-WAN edge, FortiOS 7.6.x, management lives in VRF 20 |
| RADIUS server primary | NPS-01, 10.20.50.10, in the data centre |
| RADIUS server secondary | NPS-02, 10.20.50.11, same DC, different rack |
| AD groups | FGT-NetEngineers, FGT-NOC, FGT-Auditors |
| FortiGate admin profiles | engineer-admin, noc-operator, auditor-readonly |
| Shared secret | Stored encrypted on FortiGate, vaulted on the NPS side |
| Source IP for RADIUS | The mgmt VRF interface; NPS sees branch loopbacks |
| MFA | Azure MFA NPS extension, push to Microsoft Authenticator |
The three personas:
| Persona | AD group | FortiGate profile | What they need to do | What they must not do |
|---|---|---|---|---|
| Senior network engineer | FGT-NetEngineers | engineer-admin | Full read/write across system, network, security, VPN, SD-WAN, monitoring. Reboot. | Nothing — this is the privileged role. |
| NOC operator | FGT-NOC | noc-operator | Read everything. Enable/disable existing policies. Bounce IPsec tunnels and interfaces. Take packet captures. Restart routing daemon. | Edit security profiles, change system config, manage admins, modify SD-WAN rules. |
| Compliance auditor | FGT-Auditors | auditor-readonly | Read config, view logs, list certificates, view policies and address objects. | Make any change. View VPN pre-shared keys or other secrets in cleartext. |
Step 1 — Define the admin profiles (RBAC)
Profiles are the FortiOS authorization model. Each profile is a matrix of features × none|read|read-write|custom. Profiles are evaluated locally — RADIUS only tells the FortiGate which profile to apply.
Profile A — engineer-admin
A near-superuser, but not super_admin. Keeping engineers out of super_admin means the audit trail shows a named profile, not the all-powerful built-in, and prevents accidental edits to admin accounts and HA settings without a deliberate elevation step.
config system accprofile
edit "engineer-admin"
set scope vdom
set comments "Senior network engineer — full operational control, no admin/HA mgmt"
set secfabgrp read-write
set ftviewgrp read-write
set authgrp read-write
set sysgrp read-write
set netgrp read-write
set loggrp read-write
set fwgrp read-write
set vpngrp read-write
set utmgrp read-write
set wanoptgrp read-write
set wifi read-write
set system-diagnostics enable
set system-execute-ssh enable
set system-execute-telnet enable
# Explicitly NOT super_admin — admin/HA mgmt is excluded:
set admintimeout-override enable
set admintimeout 30
next
end
Profile B — noc-operator
Read across the box, plus a tightly scoped set of write operations. The trick on FortiOS is that read-write is per feature group, but you can drop into custom on fwgrp (firewall) and loggrp (log & report) to grant policy-level enable/disable without policy creation/deletion.
config system accprofile
edit "noc-operator"
set scope vdom
set comments "NOC operator — read everywhere, bounce tunnels/interfaces, toggle policies"
set secfabgrp read
set ftviewgrp read
set authgrp read
set sysgrp read
set netgrp custom
set loggrp custom
set fwgrp custom
set vpngrp custom
set utmgrp read
set wanoptgrp read
set wifi read
set system-diagnostics enable
set system-execute-ssh disable
set system-execute-telnet disable
config netgrp-permission
set cfg read
set packet-capture read-write
set route-cfg read
end
config fwgrp-permission
set policy custom
set address read
set service read
set schedule read
set others read
end
config loggrp-permission
set config read
set data-access read-write
set report-access read
set threat-weight read
end
config vpngrp-permission
set ipsec custom
set ssl read
end
next
end
The custom settings on fwgrp.policy, vpngrp.ipsec, and netgrp.packet-capture give the NOC the granular powers they need (toggle a policy, bounce an IPsec phase-2, run a sniffer) without giving them the ability to create or delete policies, change security profiles, or alter system config.
Profile C — auditor-readonly
Pure read across everything that produces evidence — config, logs, policies, certificates — and explicit no on anything that could be a privacy or secrets-disclosure risk.
config system accprofile
edit "auditor-readonly"
set scope vdom
set comments "Compliance auditor — read-only, no secret disclosure"
set secfabgrp read
set ftviewgrp read
set authgrp read
set sysgrp read
set netgrp read
set loggrp read
set fwgrp read
set vpngrp read
set utmgrp read
set wanoptgrp read
set wifi read
set system-diagnostics disable
set system-execute-ssh disable
set system-execute-telnet disable
next
end
system-diagnostics disable is the important one — without it an auditor with read on sysgrp could still run diagnose hardware deviceinfo, diagnose debug crashlog, etc. With diagnostics disabled, the profile is truly observational. The vpngrp = read line means the auditor can see that an IPsec tunnel exists and which proposals it carries, but FortiOS will mask the pre-shared key and certificate private keys in the rendered config.
Step 2 — Configure the RADIUS server entry
config user radius
edit "NPS-PRIMARY"
set server "10.20.50.10"
set secret ENC <vaulted-secret>
set auth-type ms_chap_v2
set radius-port 1812
set source-ip "172.20.10.1"
set interface-select-method specify
set interface "mgmt"
set timeout 5
set rsso disable
set h3c-compatibility disable
next
edit "NPS-SECONDARY"
set server "10.20.50.11"
set secret ENC <vaulted-secret>
set auth-type ms_chap_v2
set radius-port 1812
set source-ip "172.20.10.1"
set interface-select-method specify
set interface "mgmt"
set timeout 5
next
end
Notes that aren’t obvious from the CLI:
auth-type ms_chap_v2is required to talk to NPS by default. NPS will reject PAP unless you’ve explicitly allowed it, which you should not.source-ipandinterface-select-method specifypin the RADIUS conversation to the management VRF. This matters when the FortiGate has multiple VRFs or multiple uplinks; without it FortiOS picks the egress IP based on the routing table, which can land in the wrong VRF and make NPS see source addresses you don’t expect.- MFA timeout — if you’re using Azure MFA push, increase
timeoutto 30+ seconds. The default 5 will fail before the user has tapped Approve on their phone. - The secondary server is configured as a separate
user radiusentry rather than two servers under one entry. This gives you per-server statistics (diag test authserver radius NPS-PRIMARY <user> <pass>) and makes it easier to put each in different user groups for failover testing.
Step 3 — Map RADIUS groups to FortiGate profiles via VSA
This is where Part 1’s “RADIUS authorization is in the Access-Accept” comes home to roost. There are two patterns; pick one and don’t mix them on the same box.
Pattern A — VSA-based (preferred)
The RADIUS server returns the Fortinet-Access-Profile VSA (vendor ID 12356, attribute 6) containing the literal admin-profile name. FortiOS reads that VSA and assigns the matching profile.
On FortiGate:
config user group
edit "fgt-radius-admins"
set member "NPS-PRIMARY" "NPS-SECONDARY"
next
end
config system admin
edit "remote-admin"
set remote-auth enable
set accprofile "no_access" ; default-deny if no VSA returned
set vdom "root"
set wildcard enable
set remote-group "fgt-radius-admins"
next
end
On NPS, three Network Policies, one per AD group, each returning a different VSA value:
| Network Policy | AD group condition | VSA returned |
|---|---|---|
| FGT-NetEngineers | Member of FGT-NetEngineers | Fortinet-Access-Profile = engineer-admin |
| FGT-NOC | Member of FGT-NOC | Fortinet-Access-Profile = noc-operator |
| FGT-Auditors | Member of FGT-Auditors | Fortinet-Access-Profile = auditor-readonly |
Adding the VSA in NPS:
- Network Policies → properties → Settings → RADIUS Attributes → Vendor Specific → Add → Custom.
- Vendor code:
12356(Fortinet). - Attribute number:
6. - Format: String. Value:
engineer-admin(or whichever profile).
Why this is the better pattern: one wildcard admin entry, one user-group entry, all the policy lives on the RADIUS server. Adding a fourth role doesn’t require any FortiGate change — just a new admin profile and a new NPS network policy.
Pattern B — One wildcard admin per group
Skip the VSA. Instead, create one user group per role and one wildcard admin per group, hard-coding the access profile in the FortiGate config.
config user group
edit "fgt-engineers"
set member "NPS-PRIMARY" "NPS-SECONDARY"
config match
edit 1
set server-name "NPS-PRIMARY"
set group-name "FGT-NetEngineers"
next
end
next
edit "fgt-noc"
set member "NPS-PRIMARY" "NPS-SECONDARY"
config match
edit 1
set server-name "NPS-PRIMARY"
set group-name "FGT-NOC"
next
end
next
edit "fgt-auditors"
set member "NPS-PRIMARY" "NPS-SECONDARY"
config match
edit 1
set server-name "NPS-PRIMARY"
set group-name "FGT-Auditors"
next
end
next
end
config system admin
edit "remote-engineer"
set remote-auth enable
set accprofile "engineer-admin"
set vdom "root"
set wildcard enable
set remote-group "fgt-engineers"
next
edit "remote-noc"
set remote-auth enable
set accprofile "noc-operator"
set vdom "root"
set wildcard enable
set remote-group "fgt-noc"
next
edit "remote-auditor"
set remote-auth enable
set accprofile "auditor-readonly"
set vdom "root"
set wildcard enable
set remote-group "fgt-auditors"
next
end
The config match block uses NPS to send the AD group name as a RADIUS attribute (Class attribute is the typical carrier, or Filter-Id). This works but ties role membership to FortiGate config — every new role needs a FortiGate change.
For an SD-WAN fleet of more than a handful of boxes, Pattern A wins because it externalises the role definition entirely. Add a new profile once on a golden config, push via FortiManager, and from that day forward role assignment is purely an AD-group + NPS-policy change.
Step 4 — Local break-glass admin
Before you cut over, make absolutely sure you have a working local account that is not dependent on RADIUS:
config system admin
edit "breakglass"
set accprofile "super_admin"
set vdom "root"
set password ENC <long-vaulted-password>
set trusthost1 10.20.10.0 255.255.255.0 ; jump-host subnet only
set two-factor email
set email-to "[email protected]"
next
end
The trusthost lock keeps this account unusable from anywhere outside the jump-host subnet. The password lives in a password vault, rotated quarterly, and the audit trail picks up any login as a breakglass event. If RADIUS dies for any reason — NPS down, certificate expired, MFA outage — this account is how you get back in. Skipping it is how people get locked out of their own gear.
Step 5 — Order RADIUS in the admin login chain
config system global
set admin-https-redirect enable
set admin-port 443
set admintimeout 30
end
config system admin-radius ; (where supported in your FortiOS version)
set status enable
end
FortiOS evaluates admins in this order:
- Local admin with matching username → use it.
- Wildcard admin → forward credentials to RADIUS.
This means a local breakglass user always works regardless of RADIUS state, and any other username falls through to the RADIUS chain. Don’t create a local user with the same name as a RADIUS user — local always wins, which can mask credential changes upstream.
Step 6 — Verify
The order to verify in:
# 1. Can the FortiGate reach NPS at all?
execute ping-options source 172.20.10.1
execute ping 10.20.50.10
# 2. Does the shared secret work and does NPS accept the auth-type?
diagnose test authserver radius NPS-PRIMARY ms_chap_v2 alice 'TestPassword123!'
# Expected output snippet on success:
# authenticate 'alice' against 'ms_chap_v2' succeeded, server=10.20.50.10
# group_list=FGT-NetEngineers
# Fortinet-Access-Profile=engineer-admin
# 3. Group resolution working?
diagnose debug enable
diagnose debug application fnbamd 7
# attempt a login from the GUI / SSH, watch the debug
diagnose debug disable
# 4. Profile is being applied as expected?
get system admin list
# Look for the remote session and which accprofile it's running under
# 5. Live admin session check
get system status
diagnose sys session list | grep <admin-source-ip>
The fnbamd debug is the single most useful command when this isn’t working. It shows the exact RADIUS conversation — the request the FortiGate sends, the attributes NPS returns, and the decision FortiOS makes about which profile to apply. Almost every failure manifests as one of:
wrong shared secret→ fix theset secretline.auth-type mismatch→ flip betweenms_chap_v2,pap, orchapto match what NPS allows.no Fortinet-Access-Profile attribute returned→ NPS Network Policy isn’t returning the VSA, or the AD group condition didn’t match.unknown group→ the wildcard admin’sremote-groupdoesn’t match the user-group name.
Gotchas
These are the ones that have eaten my afternoon at one point or another.
1. auth-type mismatch. NPS by default rejects PAP. If your secondary server happened to be FreeRADIUS configured for PAP, you can end up with primary auth working and secondary silently failing. Pick one auth-type and force it on every server.
2. Source IP and management VRF. If RADIUS lives in a different VRF from the FortiGate’s default route, you must set source-ip and set interface-select-method specify. Otherwise the request leaves out of wan1 (VRF 0), NPS sees a public IP it doesn’t recognise, and the request is dropped with no useful log on either side.
3. MFA timeout. Default 5 seconds is too short for push MFA. Bump to 30+ and test with the user actually approving and rejecting.
4. Two wildcards, ambiguous match. If you use Pattern B and a user is in two AD groups (say, FGT-NOC and FGT-Auditors), the wildcard admin selected is the first match in FortiOS evaluation order. Document which group wins, or use Pattern A and let the RADIUS server pick exactly one VSA value.
5. RADIUS over IPsec — return path. If RADIUS rides an IPsec tunnel back to the hub, ensure the tunnel selectors include the FortiGate source-IP and the RADIUS server destination-IP. A tunnel that comes up but doesn’t include the AAA flow makes failures look like RADIUS issues when they’re actually crypto issues.
6. NPS connection request policies. NPS evaluates Connection Request Policies before Network Policies. A misconfigured CRP will reject the conversation before any group lookup happens. If diagnose test authserver returns Access-Reject and NPS Event Log shows Reason Code: 8 (The specified user account is disabled) when the account is fine, suspect a CRP mismatch.
7. VSA values are case-sensitive. Engineer-Admin from NPS will not match engineer-admin on FortiGate. Match them exactly, lowercase by convention.
8. accprofile no_access as default-deny. When using Pattern A, the wildcard admin’s local accprofile should be no_access (or a custom equivalent). If RADIUS returns no VSA, the user logs in with the wildcard’s profile — making it super_admin is a recipe for an accidental privilege grant.
9. RADIUS accounting and FortiAnalyzer. RADIUS accounting from the FortiGate goes to the RADIUS server, not FortiAnalyzer. If your audit trail comes from FortiAnalyzer’s event log, you don’t need accounting on. If it comes from the RADIUS server’s logs (e.g. SIEM ingest from NPS), enable set acct-server for each RADIUS server entry.
10. Profile drift across the fleet. The whole point of central AAA is that role definitions are centralised. If five engineers have manually tweaked the engineer-admin profile across twenty branch FortiGates, you’ve lost that property. Define profiles once in a FortiManager template, treat them as version-controlled config, and stop hand-editing.
11. Renaming an AD group breaks everything silently. NPS condition matches the group SID or the literal name depending on configuration. Renaming FGT-NOC to Network-Operations-Center may pass a CRP using SID-match but fail a User Groups match using name. Always re-test after any AD-side rename.
12. set wildcard enable is required. Without it, the FortiGate looks for an exact local user match and falls back to local-deny. The wildcard flag is what tells FortiOS to forward unknown usernames to the configured remote group.
Verification commands worth memorising
# Test RADIUS from the FortiGate
diagnose test authserver radius NPS-PRIMARY ms_chap_v2 <user> '<pass>'
diagnose test authserver radius NPS-SECONDARY ms_chap_v2 <user> '<pass>'
# Live debug of the next auth attempt
diagnose debug reset
diagnose debug console timestamp enable
diagnose debug application fnbamd 7
diagnose debug enable
# ... user logs in ...
diagnose debug disable
# What admin profile is each session using right now?
get system admin list
diagnose sys session list | grep "policy_id"
# Show all profiles and what they grant
show system accprofile
show system accprofile engineer-admin
# Confirm the wildcard mapping
show system admin remote-admin
# RADIUS server-side stats
diagnose test authserver radius-direct NPS-PRIMARY 1812
Closing
Centralised admin AAA on FortiGate SD-WAN comes down to three things done in this order: define the profiles that capture each role’s actual job; configure the RADIUS conversation with the right source IP, auth-type, and timeout; and choose VSA-based mapping so role definitions live on the RADIUS side instead of being baked into FortiOS config. Once those three are in place, scaling from one branch to fifty is just FortiManager pushes and AD group adds.
The break-glass account is non-negotiable and the local-account-always-wins evaluation order is the property that lets you keep one. Set it up, document the password vault entry, and you’ll never be the person who locked themselves out of their own SD-WAN edge during a Friday-afternoon RADIUS outage.
If you came in from Part 1, that’s the full picture — protocol choice, server choice, FortiOS config, role design, and verification, end to end. The next thing worth writing about is wiring the same RADIUS chain into SSL VPN with Azure MFA, and how the user-group definitions there interact with the admin-side ones; that’ll be a separate post.