T Techclick ← All lessons
Fortinet · FortiOS · SD-WAN + ZTNA · Interactive lesson

FortiGate SD-WAN + ZTNA — tags, policy type, then prove it

The ticket is two problems on one box. Branch M365 is riding the dirty broadband. Remote users still land on SSL-VPN and can see the whole subnet. The CISO wants Jira only if the laptop is EMS-managed, AV-clean, and domain-joined. SD-WAN picks the path. ZTNA decides who and which device may reach which app.

~20 min read · L2 primary · Quiz at end

⚡ Quick Answer

FortiGate SD-WAN + ZTNA walk-through: EMS posture tags, simple vs full ZTNA policy, access-proxy VIP, Performance SLAs, and when ZTNA replaces VPN. Prove it with ztna logs and diagnose.

After this page you can

Quick answer (say this out loud)

FortiClient EMS evaluates Zero Trust tagging rules and syncs security posture tags plus the client certificate to the FortiGate. The user hits an access-proxy VIP (ZTNA Server), not a VPN pool. A simple ZTNA policy is a firewall policy with Type = ZTNA and set ztna-ems-tag; dstintf stays any and you cannot match on the real server’s destination interface. A full ZTNA policy is config firewall proxy-policy with set proxy access-proxy after Explicit Proxy is visible. Multiple tags default to Any of; use All of when AV and domain-join must both be true. SD-WAN is a different plane: Performance SLA probes members, then an SD-WAN rule steers M365. ZTNA replaces remote-access VPN for published HTTPS and TCP-forward apps on managed FortiClient endpoints. Keep IPsec for site-to-site overlay members. Keep Agentless VPN only for unpublished apps or unmanaged break-glass.

1. Why the two tickets share one box

Monday the branch says Outlook is “on the cheap link and it feels like a café.” Tuesday Security says a contractor on SSL-VPN browsed a file share that was never in scope. Both are FortiOS jobs. They are not the same job.

SD-WAN answers: which member (underlay or overlay) should this session leave on, given live latency, jitter, and loss. ZTNA answers: is this device + user allowed to reach this application through an encrypted access proxy, without a network-wide tunnel.

Hero · two planes on one FortiGate
Teaches: laptop reaches one private app through an access proxy while two WAN underlays leave the branch
Notice: the client talks to one access-proxy VIP, not to every internal subnet. Underlays are a separate steering problem.

Fortinet’s Administration Guide is blunt on the ZTNA half: ZTNA policies let users reach resources through an encrypted access proxy. That reduces the need for remote-access VPN and allows only specific application access. It does not delete IPsec overlays you still need as SD-WAN members.

SD-WAN ticket language

“M365 on lowest-latency underlay, backups on cheapest, failover when the SLA probe dies.” Objects: zone, member, Performance SLA, SD-WAN rule.

ZTNA ticket language

“Jira only if EMS-managed, cert present, tags FortiAD and Low-Risk.” Objects: EMS connector, posture tag, ZTNA Server, ZTNA policy.

2. Mental model: path quality vs identity

Pre-train the hard words before you click anything.

Flow 1 · two planes
Endpoint FortiClient + cert FortiClient EMS posture tags + CA FortiGate WAD + SD-WAN One app real server ZTNA PLANE · who + which app 1. Client cert from EMS CA 2. HTTPS to access-proxy VIP 3. Tag match Any of / All of 4. Map Host/path → real server No VPN pool. No whole subnet. SD-WAN PLANE · which path 1. Zone holds members 2. SLA probe each member 3. First-match SD-WAN rule 4. Manual / BQ / Lowest Cost (SLA) Does not grant app access.

Read left → right, then the two planes. ZTNA never picks wan1 vs wan2. SD-WAN never checks EMS tags.

Journey · identity path
Teaches: Endpoint then EMS tags then access proxy then real server
Notice the order: tags are computed on the endpoint and synced via EMS. The FortiGate does not invent posture.
Say this out loud

EMS owns posture. The FortiGate owns the access-proxy VIP and the policy. SD-WAN owns which WAN the other traffic leaves on. A ZTNA allow is not a VPN.

Tags mean different things in different policies

Official FortiOS: security posture tags are used in ZTNA policies and standard firewall policies, but each type reads different data from the tag. A ZTNA policy uses device identity (client cert / EMS context), not the IP or MAC inside the tag. A regular firewall policy uses the tag as an IP or MAC source/destination object — typical for on-net users. Mixing those two stories is the most common interview fail.

3. Decision: ZTNA, VPN, simple vs full

Flow 2 · what to publish
Remote user needs an app Published HTTPS or TCP-forward? Keep VPN / IPsec full L3 · unpublished · S2S No Need dest-intf or real-server dest? Yes + FortiClient Simple ZTNA firewall policy Type ZTNA No Full ZTNA proxy-policy + Explicit Proxy Yes

Diamond = decision. Official limit: a simple ZTNA policy cannot control access by destination interface or the real server’s destination address.

Decision · Path A vs Path B
Teaches: one decision splits Path A ZTNA per-app from Path B VPN network access
Path A = published app + FortiClient + posture tags. Path B = still a tunnel (Agentless VPN or IPsec overlay).

Simple vs full — official split

FortiOS documents two GUI ways to write the ZTNA rule.

Full ZTNA policy. Enable System → Feature Visibility → Explicit Proxy. Then Policy & Objects → Proxy Policy → Create New, Type = ZTNA. CLI stays config firewall proxy-policy with set proxy access-proxy and set access-proxy "<ZTNA Server>". You can set incoming interface, source, destination (real server object), and the ZTNA Server.

Simple ZTNA policy. Policy & Objects → Firewall Policy → Create New, Type = ZTNA. Pick Incoming Interface, Source, Security posture tags, and the ZTNA Server. CLI uses set dstaddr <access-proxy VIP> and set ztna-ems-tag. set dstintf "any" cannot be modified. This covers most full-policy functions except destination-interface and real-server destination matching.

Multiple tags on a ZTNA policy default to Any of (one tag is enough). Switch to All of when the ticket is “AV and domain-joined.” Official deny evidence is action="deny", policyid=0, msg="Traffic denied because failed to match a policy or proxy-policy", with the live tags in clientdevicetags.

Redirect is a CLI extra, not a default

set ztna-policy-redirect enable on a simple policy can force a second match against full proxy-policies. It is disabled by default. If you enable it and no full policy matches, traffic is implicitly denied even though the simple row looked like an allow.

4. How to choose

QuestionUse ZTNAKeep VPN / overlay
What is being accessed? One HTTPS app or a TCP-forward mapping (RDP/SSH/thick client) published on a ZTNA Server. Arbitrary subnets, unpublished apps, or site-to-site prefixes.
Who is on the endpoint? FortiClient registered to EMS, client cert present, tags you trust. Unmanaged browser, contractor kit, or break-glass. Agentless / web ZTNA is a separate design.
Blast radius if the laptop is stolen Only apps whose tags still match. Posture change can tear the session (WAD). SSL-VPN / Agentless VPN that assigned a tunnel IP can still see whatever the firewall policy allows on that pool.
Where does SD-WAN fit? Does not replace ZTNA. Steers SaaS and other egress. Overlay IPsec members stay in the zone. IPsec hub-spoke overlays remain SD-WAN members even after remote-access VPN shrinks.
NeedSimple ZTNA (firewall policy)Full ZTNA (proxy policy)
GUI path Policy & Objects → Firewall Policy, Type = ZTNA Feature Visibility → Explicit Proxy, then Proxy Policy, Type = ZTNA
CLI config firewall policy · set ztna-ems-tag · dstintf any config firewall proxy-policy · set proxy access-proxy
Match dest-intf / real-server dest No — official limitation Yes — set dstaddr on the real server object
Log policytype policy proxy-policy
When to pick it Most HTTPS access-proxy pilots You must pin dest-intf or a specific real-server address
SD-WAN strategy (official family)Use when
Manual Static member order. No SLA failover by itself.
Best Quality Pick the measured best member (latency / jitter / loss / custom).
Lowest Cost (SLA) Prefer cheaper members that still meet the SLA target. Classic M365 + broadband-if-healthy pattern.
Load balancing / Maximize Bandwidth Spread across healthy members. Wrong default for a single voice/M365 session you want sticky.

5. Runbook: EMS, SD-WAN, ZTNA

Lab numbers are RFC 5737 / RFC 1918 training values: WAN1 port1 203.0.113.10/24 gw 203.0.113.1, WAN2 port2 198.51.100.10/24 gw 198.51.100.1, LAN port3 10.0.1.0/24, ZTNA VIP 203.0.113.50:443, real server 10.88.0.3:9443, tags FortiAD and Low-Risk. Primary source for each block is named under the steps.

Side A — EMS connector and posture tags

Source: FortiOS Administration Guide — Establish device identity and trust context with FortiClient EMS and Types of security posture tags.

  1. Connect FortiGate to EMS

    Security Fabric → Fabric Connectors (Endpoint/Identity family) → FortiClient EMS. Point at the EMS FQDN. Authorize the FortiGate on EMS. The FortiGate keeps a continuous connection and syncs FortiClient UID, client-certificate SN, EMS SN, user/domain, and IP/MAC.

  2. Do not confuse the two certificates

    EMS has default_ZTNARootCA (signs FortiClient CSRs). That is not the EMS HTTPS / fabric SSL certificate. Refreshing the ZTNA CA revokes and reissues client certs. On Windows, the client cert in the store must match UID/SN on EMS and the FortiGate.

  3. Build tags on EMS

    On FortiClient EMS: Security Posture Tags → Tags → Create. Example rule: domain-joined + AV running → tag FortiAD. Separate rule: risk class low → tag Low-Risk. A third rule for malware → Malicious-File-Detected used only in a deny story. Tags evaluate on the endpoint; EMS pushes results.

  4. Confirm the FortiGate learned them

    diagnose endpoint fctems test-connectivity then diagnose firewall dynamic list and diagnose endpoint ec-shm list. No tag on the FortiGate means the policy cannot match it, no matter how pretty EMS looks.

Side B — SD-WAN zone, members, SLA, rule

Source: FortiOS Administration Guide — Performance SLA overview and SD-WAN rules / Application steering using SD-WAN rules.

  1. Zone and members

    Network → SD-WAN. Create or use a zone (default virtual-wan-link, or a named underlay). Add members port1 and port2 with their gateways. Overlay IPsec tunnels that should participate are members too — that is how hub-spoke stays on SD-WAN after you shrink SSL-VPN.

  2. Performance SLA

    Performance SLAs tab → Create New. Name Office365. Protocol HTTP or HTTPS to a real target the member can reach (or a FortiGuard SLA-database destination on entitled builds). Participants = the members you care about. SLA target example for this lab: latency 150 ms, jitter 30 ms, packet loss 1%. Participants must be SD-WAN members.

  3. Application-steering rule

    SD-WAN Rules tab → Create New. Identify traffic with ISDB / application (example Microsoft-Office365). Strategy Lowest Cost (SLA) bound to health-check Office365. Prefer the cheaper member that is still in SLA. A later implicit or catch-all rule handles the rest. Rules are first-match.

  4. Firewall policy still required

    SD-WAN does not accept traffic. You still need Policy & Objects → Firewall Policy LAN → SD-WAN zone. Steering without an accept policy is a dark GUI.

https://fw.lab.example/ng/network/sdwan/sla/edit
Training mock · not live

Network → SD-WAN → Performance SLAs → Create New

New Performance SLA

Performance SLAs SD-WAN Rules SD-WAN Zones
Office365
HTTP
www.office.com
port1, port2
150 ms · 30 ms · 1%

Training values. Participants must already be SD-WAN members. Ping to the gateway is not this probe — test with execute ping-options source <member-ip> toward the SLA server.

Cancel OK

Click next: OK → SD-WAN Rules → Create New → Lowest Cost (SLA) → bind Office365. Source: Performance SLA overview.

CLI · SD-WAN zone, members, SLA, rule (FortiOS Administration Guide shape)
config system sdwan
    set status enable
    config zone
        edit "underlay"
        next
    end
    config members
        edit 1
            set interface "port1"
            set zone "underlay"
            set gateway 203.0.113.1
        next
        edit 2
            set interface "port2"
            set zone "underlay"
            set gateway 198.51.100.1
        next
    end
    config health-check
        edit "Office365"
            set server "www.office.com"
            set members 1 2
            config sla
                edit 1
                    set latency-threshold 150
                    set jitter-threshold 30
                    set packetloss-threshold 1
                next
            end
        next
    end
    config service
        edit 1
            set name "M365-lowest-cost"
            set mode sla
            set internet-service enable
            set internet-service-name "Microsoft-Office365"
            set health-check "Office365"
            set sla 1
            set priority-members 2 1
        next
    end
end

Side C — ZTNA Server and policy

Source: FortiOS Administration Guide — Basic ZTNA configuration and Full versus simple ZTNA policies.

  1. ZTNA Server (access-proxy VIP)

    Policy & Objects → ZTNA → ZTNA Server → Create New. Interface = WAN that clients hit. External IP 203.0.113.50 (or 0.0.0.0 to use the interface primary/secondary). Port must not collide with management HTTPS on that interface. Default certificate = the server cert clients see on the VIP.

  2. Service / server mapping

    Service = HTTPS. Virtual Host = Specify jira.lab.example (or Any Host if every name that resolves to the VIP should map). Path match as needed (substring / wildcard / regex). Real server IP 10.88.0.3 port 9443. Extra real servers from CLI enable load-balancing in the GUI.

  3. Simple ZTNA policy for the pilot

    Policy & Objects → Firewall Policy → Create New. Type = ZTNA. Incoming interface = the WAN. Source = all (or a user group once auth schemes exist). Security posture tags = FortiAD and Low-Risk, matching method All of. ZTNA Server = the object from step 1. Action ACCEPT. Do not skip the tags — a Type=ZTNA row with no ztna-ems-tag is a posture-free allow for anyone who completed the ZTNA handshake.

  4. Use full policy only if you need dest-intf

    Enable Explicit Proxy, then Proxy Policy Type ZTNA, Destination = real-server address object Webserver1, ZTNA Server set. Skip this for the first HTTPS pilot.

https://fw.lab.example/ng/firewall/policy/edit
Training mock · not live

Policy & Objects → Firewall Policy → Create New

New Firewall Policy

ZTNA-jira-all-of
ZTNA
port1 (WAN)
ZTNA-webserver
FortiAD, Low-Risk
All of
any — not editable on a simple ZTNA policy
Action · ACCEPT · NAT enable

Official simple-policy CLI sets dstintf "any" and dstaddr to the access-proxy VIP. Multiple tags default to Any of unless you choose All of.

Cancel OK

Click next: OK → resolve jira.lab.example to 203.0.113.50 on the pilot laptop → open HTTPS → read subtype=ztna. Source: Basic ZTNA configuration.

CLI · access-proxy VIP + simple ZTNA policy (official field names)
config firewall vip
    edit "ZTNA-webserver"
        set type access-proxy
        set extip 203.0.113.50
        set extintf "port1"
        set server-type https
        set extport 443
        set ssl-certificate "lab-vip-cert"
    next
end
config firewall access-proxy
    edit "ZTNA-webserver"
        set vip "ZTNA-webserver"
        set client-cert enable
        config api-gateway
            edit 1
                set service https
                set url-map "/"
                config realservers
                    edit 1
                        set ip 10.88.0.3
                        set port 9443
                    next
                end
            next
        end
    next
end
config firewall policy
    edit 17
        set name "ZTNA-jira-all-of"
        set srcintf "port1"
        set dstintf "any"
        set action accept
        set srcaddr "all"
        set dstaddr "ZTNA-webserver"
        set ztna-ems-tag "FortiAD" "Low-Risk"
        set schedule "always"
        set nat enable
    next
end
Authentication is not “just add a group”

You can put a user group under Source on both simple and full ZTNA. The authentication scheme and rules must already send that traffic to the ZTNA application gateway. Regular firewall authd is a different engine. config firewall auth-portal / set proxy-auth enable is the WAD path and is off by default.

6. Runtime path and proof

After go-live, a good session looks like this. A bad session fails at a named step — do not restart EMS first.

Flow 3 · one HTTPS session
1. Client cert + tags 2. VIP :443 access-proxy 3. Tag check Any of / All of 4. url-map Host / path 5. Real server 10.88.0.3:9443 If posture flips mid-session, WAD can tear it down. That is by design. Proof: subtype=ztna · clientcert=yes · emsconnection=online · policyname=ZTNA-jira-all-of

Read left → right. Fail at 2 = VIP/DNS/cert. Fail at 3 = tags. Fail at 4 = virtual host. Fail at 5 = real server / health.

Ops · proof cockpit
Teaches: verification is a desk with health checks and logs, not a guess
Green on the SLA chart is not proof of ZTNA. You still need a ztna subtype log for the app session.
CLI · prove EMS, tags, ZTNA session, SD-WAN SLA
diagnose endpoint fctems test-connectivity
diagnose test application fcnacd 2
diagnose endpoint ec-shm list
diagnose wad dev query-by uid
diagnose wad dev query-by ipv4 10.0.1.50
diagnose firewall dynamic list

execute log filter category traffic
execute log filter field subtype ztna
execute log display

diagnose sys sdwan member
diagnose sys sdwan health-check
diagnose sys sdwan service
execute ping-options source 203.0.113.10
execute ping www.office.com
Green means these fields, not a feeling

ZTNA allow: type=traffic subtype=ztna action=accept policytype=policy (simple) or proxy-policy (full), vip and accessproxy set, clientcert=yes, emsconnection=online, clientdevicetags includes every tag you required for All of. SD-WAN: diagnose sys sdwan health-check shows the member in-SLA, not just “gateway ping works.”

7. Traps and pilot checklist

SymptomLikely causeFirst proof
HTTPS to the VIP fails before a policy name appears VIP IP/port collides with management HTTPS, or client does not trust the Default certificate Browse the VIP from the laptop. Check empty-cert-action / client-cert on the access-proxy VIP.
action=deny policyid=0 failed to match a policy Tags are Any/All wrong, or the endpoint lacks Low-Risk, or you enabled ztna-policy-redirect with no full match Read clientdevicetags on that log. Compare to the policy’s All of / Any of list.
Type=ZTNA policy works for every EMS laptop, including contractors No ztna-ems-tag on the simple policy — handshake-only allow CLI show firewall policy for that id. Add tags or it is not zero trust.
On-net firewall policy with a tag never hits You used a ZTNA-style identity story. Firewall policies consume the tag’s IP or MAC Confirm address type on the dynamic object. FortiGate learns IP/MAC for directly connected FortiClient (and fabric-shared EMS tags).
Member “dead” but you can ping the gateway SLA probe target is blocked from the member source, or threshold too tight so the member flaps execute ping-options source <member-ip> then ping the SLA server. Tune failtime / thresholds — do not disable the SLA.
M365 still on the expensive link SD-WAN rule below a broader first-match, or strategy is Manual, or no ISDB match diagnose sys sdwan service hit-count. Move the Microsoft-Office365 rule up.
CISO asks “did we turn VPN off?” You published two apps and left the SSL-VPN pool on LAN Shrink Agentless VPN to unpublished / break-glass only. IPsec overlays stay as SD-WAN members.

Pilot checklist

Do not “migrate everything Friday”

Official language is reduce the need for remote-access VPN, not “delete the portal before every app is mapped.” Publish the HTTPS and TCP-forward set, prove tags, then shrink the tunnel. Site-to-site IPsec that is an SD-WAN member is not in that shrink list.

Knowledge check

Six judgment questions. Each maps to a promise bullet. Check answers shows the reason and the section to re-read.

Q1

You must allow ZTNA only when the session egresses a specific DMZ interface toward real server 10.88.0.3. The simple ZTNA firewall policy greys out destination interface. What is the official next move?

Correct: c. Official limit: a simple ZTNA policy cannot control destination interface or the real server’s destination address, and dstintf stays any. Full ZTNA is Policy & Objects → Proxy Policy after Feature Visibility → Explicit Proxy. Re-read Decision and How to choose.
Q2

Jira must require domain-join and low risk. You add tags FortiAD and Low-Risk to one ZTNA policy and leave the matching method at the GUI default. A laptop has only FortiAD. What happens?

Correct: b. FortiOS defaults multiple security posture tags to Any of. All of is the AND the ticket asked for. Official deny logs show clientdevicetags missing the required tag. Re-read Mental model and Side C in Runbook.
Q3

An on-net finance PC should reach an internal file server using an EMS tag as the source of a regular firewall policy (no access proxy). Which statement is true?

Correct: a. Official: FortiOS uses posture tags in ZTNA policies and standard firewall policies, but each type uses different information from the tag. ZTNA is identity/cert; firewall policy is IP or MAC, typically on-net. Re-read the callout in Mental model.
Q4

A contractor’s FortiClient is EMS-registered. Your simple ZTNA policy sets Type = ZTNA and the ZTNA Server, but you never attach ztna-ems-tag. Security impact?

Correct: d. Tags are how you enforce role-based posture. Type = ZTNA without ztna-ems-tag is an access-proxy allow, not zero trust. Re-read Side C and the traps table in Traps.
Q5

diagnose sys sdwan health-check shows 100% probe loss on port1. You can ping the port1 gateway from the FortiGate. First action?

Correct: b. Performance SLA participants are probed toward a server, not toward the interface gateway. execute ping-options source <member-ip> then ping the SLA target. Re-read Side B and Traps.
Q6

CISO: “Turn off SSL-VPN this weekend; we have ZTNA now.” Best architectural answer?

Correct: a. Official wording is that ZTNA reduces the need for remote-access VPN by allowing specific application access — not that it deletes unpublished apps or site-to-site overlays. Re-read How to choose and the last trap.

Sources

Related: FortiGate SD-WAN SLA + rules · FortiGate policy lookup + NAT · FortiGate IPsec / SSL-VPN · FortiGate ZTNA tags and private apps · FortiGate interview · Troubleshooting command center