ZTNA agentless web-based application access
A ZTNA web portal is available to provide end-user access to applications without FortiClient or client certificate checks. The ZTNA portal handles authentication and authorization of traffic destined for the protected resources. It is implemented entirely in WAD.
When end-users connect to the ZTNA web portal, they are directed to a login page:
Once logged in, end-users can access bookmarks defined by the administrator:
For web applications, the client must resolve the FQDN to the ZTNA portal VIP. In addition, when accessing the web application, end users are presented with the certificate configured on the ZTNA portal VIP instead of the certificate on the end web server. Hence, the certificate requires the correct Subject Alternate Name(s) to avoid browser certificate errors.
CLI syntax
Configure an access-proxy type of VIP. Disable client-cert so that it is not checked when an agentless client connects.
config firewall vip
edit <name>
set type access-proxy
set server-type https
set extip <ip address>
set extintf <interface>
set client-cert disable
set extport <port>
set ssl-certificate <certificate>
next
end
Configure an access-proxy virtual host. End-users will connect to this destination to access the ZTNA web portal. Disable client-cert for this virtual host.
config firewall access-proxy-virtual-host
edit "ztna-web-portal-fqdn"
set host < web portal host name or ip >
set client-cert disable
next
end
Configure an authentication scheme. Then configure an authentication rule with ztna-portal.
config authentication rule
edit <rule>
set protocol ztna-portal
set active-auth-method < auth scheme >
next
end
Configure the ZTNA web portal:
config ztna web-portal
edit <name>
set vip <vip name>
set host <virtual host name>
set auth-portal {enable | disable}
set vip6 <virtual IPv6 name>
set auth-rule <rule>
next
end
|
Command |
Description |
|---|---|
|
vip <vip name> |
The access-proxy VIP associated with this portal. |
|
host <virtual host name> |
The access-proxy virtual host object and FQDN defined for accessing this portal. This virtual host object should not conflict with other virtual host objects used in TCP forwarding and HTTP web services or with the SAML SP host. |
|
auth-portal {enable | disable} |
Enable/disable the authentication portal. |
|
vip6 <virtual IPv6 name> |
The access-proxy VIP6 associated with the ZTNA server and applications that this portal is allowing. |
Create the web portal bookmarks:
config ztna web-portal-bookmark
edit <name>
set users <users>
set groups <groups>
config bookmarks
edit <name>
set apptype {ftp | rdp | sftp | smb | ssh | telnet | vnc | web}
set url <string>
set host <name or IP>
set description <description>
set port <remote port>
set sso {enable | disable}
next
end
next
end
|
Command |
Description |
|---|---|
|
users <users> |
The user(s) allowed to access the web-portal. |
|
groups <groups> |
The group(s) allowed to access the web-portal. |
|
apptype {ftp | rdp | sftp | smb | ssh | telnet | vnc | web} |
Supported types of bookmarks: ftp, rdp, sftp, smb, ssh, telnet, vnc, web. |
|
url <url> |
For different types of applications, the URL used to define the destination. |
|
host <name or ip> |
For different types of applications, the host name or IP used to define the destination. |
|
port <remote port> |
Where applicable, define the port for the service. |
|
sso {enable | disable} |
Enable/disable the SSO user login and credentials to connect to the application, where applicable. |
|
|
Not all options are listed. Some options are available only for certain types of applications. |
Configure your proxy-policy to map to your web-portal.
config firewall proxy-policy
edit <id>
set proxy ztna-proxy
set active-auth-method <authentication rule>
set ztna-proxy <web-portal>
…
next
end
Example
This example demonstrates connecting to a ZTNA web portal to gain access to protected resources. Authentication is performed with LDAP.
Prerequisites:
-
The Client can resolve:
-
The hostname web-portal.ztnademo.com to the VIP address 10.0.3.20
-
The server s1.ztnademo.com to the VIP address 10.0.3.20
-
The server s2.ztnademo.com to the VIP address 10.0.3.20
-
-
The FortiGate resolves:
-
s1.ztnademo.com to the real server IP of 10.88.0.7
-
s2.ztnademo.com to the real server IP of 10.88.0.3
-
-
The FortiGate has an LDAP connection and user group already created.
To configure from the CLI:
-
Configure a firewall VIP with external IP 10.0.3.20:
config firewall vip edit "ZTNA-web-proxy" set type access-proxy set server-type https set extip 10.0.3.20 set extintf "port3" set client-cert disable set extport 443 set ssl-certificate "ztna-wildcard" next end -
Configure an access-proxy virtual host:
The configuration here defines the virtual host used to access the ZTNA web portal, as well as the server certificate for the portal. It overrides the settings in the VIP. Ensure that
client-certis disabled.config firewall access-proxy-virtual-host edit "ztna-web-portal-fqdn" set host "web-portal.ztnademo.com" set client-cert disable next end -
Configure the authentication scheme and rule:
config authentication scheme edit "ztna-web-portal-ldap" set method basic set user-database "LDAP-fortiad" next end config authentication rule edit "ztna-web-portal-rule" set protocol ztna-portal set ip-based disable set active-auth-method "ztna-web-portal-ldap" set web-auth-cookie enable next end -
Configure the ZTNA web-portal:
Map the portal to the VIP, virtual host, and authentication rule that were previously created.
config ztna web-portal edit "ztna-web-portal-ldap" set vip "ZTNA-web-proxy" set host "ztna-web-portal-fqdn" set auth-rule "ztna-web-portal-rule" next end -
Create web-portal bookmarks that will point to your internal resources:
The
groupssetting defines the user group allowed access to the portal.config ztna web-portal-bookmark edit "bookmark" set groups "LDAP-Remote-Allowed-Group" config bookmarks edit "Webserver" set url "https://s2.ztnademo.com:9043" next edit "Server-S1-Web" set sso enable set url "https://s1.ztnademo.com" next edit "Server-S1-SSh" set apptype ssh set sso enabled set host "10.88.0.7" set logon-user "admin" set logon-password <password> next edit "FortiGate-Internal-SSH" set apptype ssh set host "10.88.0.254" next edit "RDP" set apptype rdp set host "10.88.0.1" set port 3389 next end next end -
Create a full ZTNA policy (
proxy-policy) to allow access to the new VIP:config firewall proxy-policy edit 0 set name "ZTNA-web-portal" set proxy ztna-proxy set ztna-proxy "ztna-web-portal-ldap" set srcintf "any" set srcaddr "all" set dstaddr "all" set action accept set schedule "always" set logtraffic all next end
Verification:
-
On the Client 10.0.3.2, access the portal on https://web-portal.ztnademo.com.
-
When prompted, enter the LDAP user credentials.
-
Once logged into the ZTNA Portal, choose the application bookmark to connect to.
-
Click Webserver to access s2.ztnademo.com. A new tab opens up to the web page.
-
Check the certificate to confirm it is signed by the CA certificate used in the VIP configurations.
-
On the FortiGate, go to Log & Report > ZTNA Traffic to view the latest traffic log. Alternatively, use these commands to view the logs from CLI:
# execute log filter field subtype ztna # execute log display 32 logs found. 10 logs returned. 1: date=2024-12-03 time=13:04:33 eventtime=1733259873399494172 tz="-0800" logid="0005000024" type="traffic" subtype="ztna" level="notice" vd="root" srcip=10.0.3.2 srcport=1629 srcintf="port3" srcintfrole="wan" dstcountry="Reserved" srccountry="Reserved" dstip=10.0.3.20 dstport=443 dstintf="port2" dstintfrole="dmz" sessionid=6761 srcuuid="b458a65a-f759-51ea-d7df-ef2e750026d1" service="HTTPS" proxyapptype="ztna-proxy" proto=6 action="accept" policyid=2 policytype="proxy-policy" poluuid="b93f2588-b125-51ef-47b1-85fc99ba0ab1" policyname="ZTNA-web-portal" trandisp="dnat" tranip=10.88.0.3 tranport=9043 appcat="unscanned" duration=421 gatewayid=1 vip="ZTNA-web-proxy" clientdevicemanageable="unknown" clientcert="no" wanin=303011 rcvdbyte=303011 wanout=5460 lanin=3202 sentbyte=3202 lanout=306669
-
On the ZTNA Portal, connect to RDP. When prompted enter the credentials.
-
Once successfully connected, users can press F8 for additional controls.
-
Review the logs:
# execute log filter field subtype ztna # execute log display 35 logs found. 10 logs returned. 1: date=2024-12-03 time=16:24:50 eventtime=1733271890886450548 tz="-0800" logid="0005000024" type="traffic" subtype="ztna" level="notice" vd="root" srcip=10.0.3.2 srcport=2540 srcintf="port3" srcintfrole="wan" dstcountry="Reserved" srccountry="Reserved" dstip=10.0.3.20 dstport=443 dstintf="port2" dstintfrole="dmz" sessionid=8146 srcuuid="b458a65a-f759-51ea-d7df-ef2e750026d1" service="HTTPS" proxyapptype="ztna-proxy" proto=6 action="accept" policyid=2 policytype="proxy-policy" poluuid="b93f2588-b125-51ef-47b1-85fc99ba0ab1" policyname="ZTNA-web-portal" trandisp="dnat" tranip=10.88.0.1 tranport=3389 appcat="unscanned" duration=0 gatewayid=1 vip="ZTNA-web-proxy" clientdevicemanageable="unknown" clientcert="no" wanin=0 rcvdbyte=0 wanout=0 lanin=3242 sentbyte=3242 lanout=1726
Additional troubleshooting and debugs:
If an issue occurs, you can troubleshoot by running these commands:
# diagnose wad debug enable category all # diagnose wad debug enable level verbose # diagnose debug enable
A working connection will output the debugs indicating the web-portal matched the proper gateway. Then accessing the bookmark will output debugs for matching the bookmark.
GET /XX/YY/ZZ/webservice?bmgroup=bookmark&bmname=Webserver&cookie=9DC408DF3F32C8805385A1204DED7F81 HTTP/1.1 Host: s2.ztnademo.com upgrade-insecure-requests: 1 user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 sec-fetch-site: same-site sec-fetch-mode: navigate sec-fetch-user: ?1 sec-fetch-dest: document sec-ch-ua: "Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" referer: https://web-portal.ztnademo.com/ accept-encoding: gzip, deflate, br, zstd accept-language: en-US,en;q=0.9 cookie: ZTPORTAL-EP-w8ICkTaqA8_EMoSCNDe_gyTAXEUw=430AAAAAAIAAAAAAAAAKF1h1WrrQAbAnodk0tYbtu1vnZZ-qlaOhL_y-UZIXxPCwqIplM3ujQ==DAAAAFB0iNTviC6zS6nUx9VNZ3yWCbkG priority: u=0, i [V][p:3472][s:6905][r:815] wad_http_marker_uri :1533 path=/XX/YY/ZZ/webservice len=20 [V][p:3472][s:6905][r:815] wad_http_parse_host :1911 host_len=15 [I][p:3472][s:6905][r:815] wad_http_parse_host :1948 host=[15]s2.ztnademo.com [I][p:3472][s:6905][r:815] wad_http_str_canonicalize :2468 enc=0 path=/XX/YY/ZZ/webservice len=20 changes=0 [I][p:3472][s:6905][r:815] wad_http_str_canonicalize :2470 end=5 path=bmgroup=bookmark&bmname=Webserver&cookie=9DC408DF3F32C8805385A1204DED7F81 len= 73 changes=0 [V][p:3472][s:6905][r:815] wad_http_normalize_uri :2643 host_len=15 path_len=20 query_len=73 [I][p:3472][s:6905][r:815] wad_http_req_detect_special :14025 captive_portal detected: false, preflight=(null) [I][p:3472][s:6905][r:815] wad_vs_proxy_match_gwy :4534 16059:ZTNA-web-proxy: matching gwy with vhost(_def_virtual_host_) [V][p:3472][s:6905][r:815] wad_vs_proxy_match_vhost :4653 16059:ZTNA-web-proxy: matching vhost by: s2.ztnademo.com [V][p:3472][s:6905][r:815] wad_vs_proxy_match_vhost :4656 16059:ZTNA-web-proxy: no host matched. [V][p:3472][s:6905][r:815] wad_vs_web_portal_cookie_lookup :8784 decode cookie_str=9DC408DF3F32C8805385A1204DED7F81 as cookie_val=1870837449, vd_id=0, vs_ id=16059, gwy_id=1 [I][p:3472][s:6905][r:815] wad_vs_proxy_match_gwy :4578 16059:ZTNA-web-proxy: Matched gwy(1) type(ztna-portal) via cookie in query 0x7fdeabcd2448 . … [I][p:3472][s:6905][r:815] wad_ztna_portal_match_user :79 matched cached grp:LDAP-Remote-Allowed-Group … [V][p:3472][s:6905][r:815] wad_http_req_exec_act :13264 response is ready! [V][p:3472][s:6905][r:815] wad_http_msg_start_setup_proc :2280 msg(0x7fdeaa161048) proc-setup started from: req_resp_ready. [V][p:3472][s:6905][r:815] wad_http_def_proc_msg_plan :2242 msg(0x7fdeaa161048) setting up processor(req_resp_ready) [V][p:3472][s:6905][r:815] wad_http_msg_start_setup_proc :2280 msg(0x7fdeaa4f4cf0) proc-setup started from: resp_forward. [V][p:3472][s:6905][r:815] wad_http_def_proc_msg_plan :2242 msg(0x7fdeaa4f4cf0) setting up processor(resp_forward) [I][p:3472][s:6905][r:815] wad_dump_fwd_http_resp :3040 hreq=0x7fdeaa161048 Forward response from Internal: HTTP/1.1 303 See Other X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Strict-Transport-Security: max-age=31536000 Content-Security-Policy: frame-ancestors 'self'; object-src 'self'; script-src 'self' https: 'unsafe-eval' 'unsafe-inline' blob:; Connection: close Content-Type: text/html Cache-Control: no-cache Location: https://s2.ztnademo.com:443 Content-Length: 133 Set-Cookie: ZTNAWebPortal=9DC408DC3F32C8805385A1204DED7F81; Max-Age=3600; Path=/; HTTPOnly; Secure Set-Cookie: ZTNAWEB=bmgroup=bookmark&bmname=Webserver; Path=/; HTTPOnly; Secure