Technical Tip: System admin’s trusthost setting takes precedence over system API user’s trusthost
Description
This article describes how system admin’s trusthost setting impacts on API access despite that system api-user’s trusthost setting is applied.
Scope
FortiGate.
Solution
If the system admin’s trusthosts list does not contain API client’s IP address the FortiGate denies connection to API.
See the example configuration below:
config system admin
edit "admin"
set trusthost1 192.168.217.2 255.255.255.255
set accprofile "super_admin"
set vdom "root"
set password ***
next
end
config system api-user
edit "apitest"
set api-key ***
set accprofile "api-profile-test"
set vdom "root"
# config trusthost
edit 1
set ipv4-trusthost 192.168.217.1 255.255.255.255
next
end
next
end
The following outputs can be observed in the debug flow:
id=20085 trace_id=3 func=print_pkt_detail line=5517 msg="vd-root:0 received a packet(proto=6, 192.168.217.1:52392->192.168.217.146:443) from port1. flag [S], seq 890923820, ack 0, win 64240"
id=20085 trace_id=3 func=init_ip_session_common line=5682 msg="allocate a new session-00000ead"
id=20085 trace_id=3 func=vf_ip_route_input_common line=2591 msg="find a route: flag=84000000 gw-192.168.217.146 via root"
id=20085 trace_id=3 func=fw_local_in_handler line=410 msg="iprope_in_check() check failed on policy 0, drop"
This is expected behavior.
Since the trusthosts of 'system admin' are applied in kernel local-in policy it takes precedence over system API user.
The trusthosts of api-user are applied only for API access and in this specific scenario to access api-user the API client’s IP address should be matched by both - the trusthost list of 'system admin' and 'system api-user'. For example:
config system admin
edit "admin"
set trusthost1 192.168.217.2 255.255.255.255
set trusthost2 192.168.217.1 255.255.255.255
set accprofile "super_admin"
set vdom "root"
set password ***
next
end
config system api-user
edit "apitest"
set api-key ***
set accprofile "api-profile-test"
set vdom "root"
config trusthost
edit 1
set ipv4-trusthost 192.168.217.1 255.255.255.255
next
end
next
end
Debug flow outputs:
id=20085 trace_id=4 func=print_pkt_detail line=5517 msg="vd-root:0 received a packet(proto=6, 192.168.217.1:50064->192.168.217.146:443) from port1. flag [S], seq 2103817493, ack 0, win 64240"
id=20085 trace_id=4 func=init_ip_session_common line=5682 msg="allocate a new session-00001621"
id=20085 trace_id=4 func=vf_ip_route_input_common line=2591 msg="find a route: flag=84000000 gw-192.168.217.146 via root"
id=20085 trace_id=5 func=print_pkt_detail line=5517 msg="vd-root:0 received a packet(proto=6, 192.168.217.146:443->192.168.217.1:50064) from local. flag [S.], seq 4070971775, ack 2103817494, win 42340"
id=20085 trace_id=5 func=resolve_ip_tuple_fast line=5597 msg="Find an existing session, id-00001621, reply direction"
id=20085 trace_id=6 func=print_pkt_detail line=5517 msg="vd-root:0 received a packet(proto=6, 192.168.217.1:50064->192.168.217.146:443) from port1. flag [.], seq 2103817494, ack 4070971776, win 2053"
'httpsd' debug outputs:
[httpsd 218 - 1591003878 info] ap_invoke_handler[593] -- new request (handler='api_cmdb_v2-handler', uri='/api/v2/cmdb/firewall/address/', method='GET')
[httpsd 218 - 1591003878 info] ap_invoke_handler[597] -- User-Agent: PostmanRuntime/7.25.0
[httpsd 218 - 1591003878 info] ap_invoke_handler[600] -- Source: 192.168.217.1:50064 Destination: 192.168.217.146:443
[httpsd 218 - 1591003878 info] api_cmdb_v2_handler[2158] -- received api_cmdb_v2_request from '192.168.217.1'
[httpsd 218 - 1591003878 warning] api_access_check_for_api_key[962] -- API Key request authorized for apitest from 192.168.217.1.
[httpsd 218 - 1591003878 info] handle_cli_req_v2_vdom[2060] -- new CMDB API request (vdom='root',user='apitest')
[httpsd 218 - 1591003878 info] api_cmdb_request_init_by_path[1432] -- new CMDB query (path='firewall',name='address')
[httpsd 218 - 1591003878 info] api_cmdb_select_etag[2231] -- ETag check for firewall.address
[httpsd 218 - 1591003878 info] api_return_cmdb_revision[789] -- ETag check for firewall.address
[httpsd 218 - 1591003878 info] api_add_etag[874] -- no If-None-Match header
[httpsd 218 - 1591003878 info] api_cmdb_v2_object_select[909] -- 0 entries filtered out
[httpsd 218 - 1591003878 info] api_return_cmdb_revision[789] -- ETag check for firewall.address
[httpsd 218 - 1591003878 info] ap_invoke_handler[616] -- request completed (handler='api_cmdb_v2-handler' result==0)
If trusthost needs to be applied to system api-user but the same trusthost IP can not be allowed to administratively access the FortiGate GUI (i.e. allowing external vendor to make API calls to FortiGate), create a system admin account that has no read/write access and apply the trusthost to it:
config system accprofile
edit "noaccess"
set comments ''
set secfabgrp none
set ftviewgrp none
set authgrp none
set sysgrp none
set netgrp none
set loggrp none
set fwgrp none
set vpngrp none
set utmgrp none
set wanoptgrp none
set wifi none
set admintimeout-override disable
set system-diagnostics disable
set system-execute-ssh disable
set system-execute-telnet disable
next
end
config system admin
edit "noaccess"
set trusthost1 1.1.1.1 255.255.255.255
set accprofile "noaccess"
set vdom "root"
set password ***
next
end
config system api-user
edit "apitest"
set apikey ***
set accprofile "api-profile-test"
set vdom "root"
config trusthost
edit 1
set ipv4-trusthost 1.1.1.1 255.255.255.255
next
end
next
end
This configuration allows a user to make API calls to FortiGate from 1.1.1.1 but ensures that no user from 1.1.1.1 will be able to login to the FortiGate GUI with valid access.
Starting FortiOS 7.4.1, the system api-user's trusthost settings do not require the equivalent trusthost IP to be applied to a system admin's trusthost settings.