Ir al contenido

Fortinet FortiGate

This page covers administrative access to a FortiGate over TACACS+. It is the device-side counterpart to TACACS+.

FortiGate is the odd one out in this cookbook, and it is worth saying why before any configuration appears.

PlatformSoftwareWhat was verified
FortiGate-VM64FortiOS v7.6.7 build 3704 (GA)TACACS+ authentication and authorization, admin-profile assignment, group matching, wildcard remote admin, single VDOM (root), NAT mode, standalone

RADIUS administrative login is also supported. The seeded Fortinet FortiGate RADIUS template returns a single mandatory attribute — Fortinet-Group-Name, VSA 1 under vendor ID 12356 — whose value must name a group configured on the firewall, and defaults the reply to Service-Type = Login-User with a session timeout of 28800 s and an idle timeout of 600 s. That path was not part of this test and is not documented further here.

FortiGate needs three objects to cooperate, and each one can be individually correct while the chain as a whole fails. Read this before the configuration, because the error messages will not tell you which link broke.

ObjectWhat it does
user tacacs+The server itself — address, key, source IP, and whether authorization is requested at all
user groupTies the group name Taranac returns to a local group the firewall understands
system adminThe wildcard admin entry that lets unknown-but-authenticated users log in, and decides whether Taranac’s profile choice is honoured

The login flow runs: authenticate against Taranac → request authorization from Taranac → match the returned group against a local group → apply the returned admin profile.

Taranac’s end of that chain is one TACACS+ profile built on the seeded Fortinet FortiGate template. It authorizes the fortigate service — not shell — and the template defines exactly three AV-pairs:

AV-pairSent asRequiredWhat it carries
admin_profadmin_prof = …YesThe admin profile name, which has to exist on that firewall. Template default super_admin
memberofmemberof = …NoThe group name the config match block in step 2 compares against
vdomvdom = …No, repeatableThe VDOM(s) the admin may enter — one AV-pair per VDOM. Empty means the default VDOM

There is nothing else. The template declares no command authorization, which is why the profile form hides its Command Set section for a FortiGate profile, and no enable support — the Enable section is still on the form (it is not gated on the template), but FortiOS has no escalation step for it to reach, so anything set there is inert. Everything the firewall does with the login after that is its own accprofile.

config user tacacs+
edit "TARANAC"
set server "10.0.0.20"
set key <TACACS_SECRET>
set authorization enable
set source-ip "10.0.0.11"
next
end

set key takes the shared secret as plaintext when you type it, and it must equal the secret on this device’s record in Taranac. A later show prints it back as set key ENC <blob> — that is the stored form, not something to paste into another firewall by hand.

set source-ip pins the address the FortiGate uses to reach the server, which is what Taranac matches against the registered device. If it disagrees with the address on the device’s entry, the request is dropped as coming from an unknown client and nothing is written to the Taranac logs. See Network devices.

config user group
edit "TACACS-ADMINS"
set member "TARANAC"
config match
edit 1
set server-name "TARANAC"
set group-name "FGT_access"
next
end
next
end

The match block is the join between the two systems. group-name must equal the value Taranac returns in the memberof attribute of the FortiGate authorization profile — here, FGT_access. They are two independently-edited strings in two different products that must agree exactly, which makes this the most common place for a working setup to break after someone renames something.

set member "TARANAC" makes the TACACS+ server a member of the group.

config system admin
edit "tacacs-wildcard"
set vdom "root"
set remote-auth enable
set accprofile "super_admin"
set remote-group "TACACS-ADMINS"
set wildcard enable
set accprofile-override enable
next
end

wildcard enable is what makes this scale: one admin entry serves every user in the group, instead of a local entry per person. remote-group points at the group from step 2.

config system global
set remoteauthtimeout 30
end

This is the FortiGate’s timer for remote authentication, and it is the one to raise for push MFA. Taranac holds the exchange open while the user approves the push on their phone — up to about 30 seconds. FortiOS defaults to a much shorter value, at which the firewall gives up before anyone can reach into a pocket and the login simply fails.

The effective window is the smaller of this value and Taranac’s own server-side cap, so raise both together.

config system accprofile
edit "prof_admin"
set secfabgrp read-write
...
set cli-config enable
next
end

show system accprofile does not necessarily list every profile that exists — super_admin was in active use on the tested firewall and does not appear in this output. Do not conclude from a missing entry that a profile is undefined; the name Taranac returns only has to be valid on the firewall, not visible here.

FortiGate’s fnbamd daemon handles remote authentication, and its debug output is by far the most informative diagnostic on this platform — it shows exactly what Taranac returned and how the firewall interpreted it.

diagnose debug enable
diagnose debug application fnbamd -1

It self-disables after 30 minutes. Now log in from another session. A successful login produces this (elided to the lines that matter):

[1784] handle_req-Rcvd auth req … for taranac in opt=00014001 prot=9 svc=6
[336] __compose_group_list_from_req-Group 'TACACS-ADMINS', type 1
[414] __add_admin_tac_plus_svr-Loaded TAC+ server 'TARANAC' for admin user 'tacacs-wildcard'
[94] fnbamd_tac_plus_get_next_authen_type-Next authen type pap
[389] __tac_plus_tcps_open-… addr 10.0.0.20, src_ip 10.0.0.11 …
[300] fnbamd_tac_plus_make_authen_request-Building authen start packet: authen_type=2(pap)
[509] fnbamd_tac_plus_validate_authen_reply-TAC+ authen type=2, result=1(pass)
[117] __tac_plus_next_state-State: 'Authen' -> 'Author'
[435] fnbamd_tac_plus_make_author_request-Building author req packet: authen_type=2(pap)
[595] __parse_author_reply_args-arg cnt 3
[363] __add_group-Authorization group 'FGT_access'
[375] __set_admin_prof-Authorization admin profile 'super_admin'
[206] find_matched_usr_grps-Passed group matching
[280] fnbamd_comm_send_result-Sending result 0 …

Read it as a checklist — each line confirms one link in the chain:

LineWhat it proves
Loaded TAC+ server … for admin user 'tacacs-wildcard'The wildcard admin entry was selected
src_ip 10.0.0.11The source address Taranac will match against the device record
authen … result=1(pass)The password was accepted
State: 'Authen' -> 'Author'set authorization enable is in effect — absent if it is not
Authorization group 'FGT_access'Taranac’s memberof value arrived
Authorization admin profile 'super_admin'Taranac’s admin_prof value arrived
Passed group matchingThe config match block agreed with the returned group
Sending result 0Success (1 is failure)
diagnose test authserver tacacs+ TARANAC ad_user1 <password>

The first argument is the server name as configured, not its address. Passing an IP returns '10.0.0.20' is not a valid tac_plus server name, which reads like a configuration fault and is not one.

On success the command ends with the assigned profile. On failure:

authenticate user 'ad_user1' on server 'TARANAC' failed
Admin profile: <none>

This is the platform behaviour most likely to surprise you, and it is only visible in the debug output:

Building authen start packet: authen_type=2(pap)
→ TAC+ authen type=2, result=2(fail)
Next authen type mschap
Building authen start packet: authen_type=5(mschap)
→ TAC+ authen type=5, result=2(fail)
Next authen type chap
Building authen start packet: authen_type=3(chap)
→ TAC+ authen type=3, result=2(fail)
Next authen type ??

When PAP is rejected, FortiGate does not give up — it retries the same credentials as MS-CHAP, then as CHAP, each on its own fresh TCP connection, before declaring failure.

A successful login never starts the cascade — PAP passes on the first exchange and the chain stops there. So the cascade in your logs is always a failure signature, which makes it useful: three rejections with ascending authentication types is a wrong password, not a broken server.

FortiGate has no per-command authorization, but it does send per-command accounting — in a shape no other platform in this cookbook uses.

The record arrives under service=fortigate, and the standard cmd attribute holds only a category word: Config, Show, Diagnose or Execute. The command itself sits in a separate reason AV-pair, alongside an event naming what kind of record it is:

event=cmd_acct stop_time=… reason="diagnose sys ha status" cmd=Diagnose
event=sys_acct stop_time=… reason="Edit firewall.address 2.2.2.2" cmd=Config

Read literally, every FortiGate command in the accounting log would read Diagnose or Config — which is exactly what it did until 1.2.1. Taranac now recognises a FortiGate record from service=fortigate in the AV-pairs alone, with no database lookup, and uses the reason value as the command — in the log views and in the syslog export alike. A record that carries no reason (a login_acct event, for one) keeps its category word rather than being blanked.

Worth noticing in that second line: FortiGate reports configuration changes through the same channel, so the accounting log on this platform contains change detail — Edit firewall.address 2.2.2.2 — that most platforms never send at all.

Taranac’s NAC vendor dictionary carries a fortinet entry — Fortinet FortiGate / FortiSwitch, vendor ID 12356 — so the platform can also be used as an 802.1X authenticator against Taranac’s RADIUS side. None of it was exercised in the test above; the table below is what the dictionary declares, not what has been verified here.

WhatHow Taranac encodes it
VLANTunnel-Type / Tunnel-Medium-Type / Tunnel-Private-Group-ID
Named ACLFilter-Id
Session timeoutSession-Timeout + Termination-Action = RADIUS-Request
VLAN changeA real CoA-Request carrying the tunnel triplet
Re-authenticationA Disconnect. The entry declares no native CoA reauth, so the endpoint reconnects instead of re-authenticating in place
Port bounce · port disableUnsupported — nothing is sent
Downloadable ACL · URL redirectNot declared. URL redirect is declared by Cisco IOS / IOS-XE alone

Neither of those last two rows is a gap peculiar to FortiGate. vlan_change is a real CoA-Request on all sixteen vendors in the dictionary — the one near-universal native action — while native coa_request re-authentication is declared by three entries only: Cisco IOS / IOS-XE, Cisco NX-OS and Juniper. FortiGate is not among them, so Re-authenticate in a NAC policy resolves to a Disconnect here and the endpoint has to come back on its own.

Which entry a request is answered with is resolved in this order: the dictionary entry pinned on the device record, then auto-detection from a vendor attribute in the request (for this entry, Fortinet-Group-Name), then the device’s free-text Vendor field, then the generic RFC entry. Pinning it on the device is the only one of those that is deterministic.

  • RADIUS administrative login. The seeded template is described above; the path itself was not exercised.
  • Multi-VDOM. Everything here was verified on a single VDOM (root). The repeatable vdom AV-pair has not been tested against a multi-VDOM firewall.
  • 802.1X. The fortinet dictionary entry has not been exercised against a FortiGate or a FortiSwitch — the table above is a declaration, not a result.
  • The device-side accounting switch. The accounting records above came from a production firewall; which FortiOS setting turns them on was not part of the rebuild on the VM.
SymptomLikely cause
Everyone logs in as super_admin regardless of policyaccprofile-override disabled, so the admin entry’s local accprofile wins. Or authorization disabled on the server, so no profile is ever requested.
Login works, no Author phase in the debugset authorization enable missing on the user tacacs+ entry.
Login rejected, nothing in the Taranac logssource-ip does not match the address registered for this device.
Passed group matching never appearsThe group-name in the config match block does not equal Taranac’s memberof value — or the template still spells the attribute member_of (pre-1.2.2).
Push MFA always failsremoteauthtimeout too low — raise it to 30 and match the server-side cap.
MFA prompt never appearsExpected: PAP has no second step. Use concatenated password+OTP, or push.
is not a valid tac_plus server namediagnose test authserver takes the server’s configured name, not its IP.
Three failed auths per bad passwordExpected — the PAP → MS-CHAP → CHAP cascade.
Unknown action 0 on every commandYou are inside a config context. end first, or use show <path> from the root prompt.
Authentication succeeds and no admin_prof ever arrives, on Taranac 1.1.1 or earlierThe profile is built on a non-shell vendor template, and the deployed daemon config reduced it to a shell / privilege-15 block. Fixed in 1.1.2.
Accounting shows Config / Show / Diagnose / Execute where the command should bePre-1.2.1 behaviour — or a TACACS+ configuration that has not been generated and deployed again since the upgrade.
You cannot find where to set an enable secret for FortiGateThere is nowhere: FortiOS has no separate escalation step, the profile arrives with the login, and the template declares no enable support. Taranac’s $enab<N>$ escalation handling (1.2.5) covers Cisco IOS / IOS-XE, Cisco Business, H3C Comware 7 and Eltex ESR — never this platform.