Run the service behind IIS or a proxy
If there's an IIS, a load balancer, or another proxy in front of the service, by default the service sees only the proxy's address. For origin rules, the sign-in policy, and the HTTPS requirement to work correctly, the service has to trust the proxy explicitly.
Solution overview
The proxy reports the caller's address in X-Forwarded-For, the scheme in X-Forwarded-Proto, and
the host the caller addressed in X-Forwarded-Host. The service believes these headers only if they
come from an address under Gateway:Security:TrustedProxies. Without this entry, it would see every caller with the proxy's
address—if the proxy is in the corporate network, everyone would count as “inside”.
Implementation
- Have the service listen only on
127.0.0.1(or on an address only the proxy reaches), for example withKestrel:Endpoints:Http:Url=http://127.0.0.1:8434. Register the proxy as trusted:
"Security": { "TrustedProxies": [ "127.0.0.1", "::1" ] }- Have the proxy set
X-Forwarded-For,X-Forwarded-Proto: https, andX-Forwarded-Host. IfX-Forwarded-Foris missing, every request counts as coming from the proxy itself—with IIS on the same computer, that means127.0.0.1: inside, protected, exempt from every network rule. So after setup, check in the audit that the real origins appear there. The service builds the absolute addresses in its responses from scheme and host: the service document and next pages of the OData interface,Locationafter a create, and the one-time links of the administration API. WithoutX-Forwarded-Host, they point to127.0.0.1and can't be reached from outside. Of each header, the service takes the last entry, the one the nearest proxy appended, and of the host only a host name or address with a port. With IIS: the installation package with
GW_MODE=iistakes care of steps 1 and 2 and writes a templateiis\web.configto the program folder. It redirectshttptohttps, forwards every request tohttp://127.0.0.1:<GW_PORT>, setsX-Forwarded-Proto: httpsandX-Forwarded-Host, and allows addresses of up to 8,192 characters. Use it to create an IIS website with your certificate. The template needs the IIS modules URL Rewrite and Application Request Routing. In IIS Manager, under URL Rewrite > View Server Variables, allow the variablesHTTP_X_FORWARDED_PROTOandHTTP_X_FORWARDED_HOST; without this permission, IIS rejects the rule that sets the headers and responds with500.
The template's rules under URL Rewrite (German-language IIS Manager).
The two allowed server variables.
Result: the audit names the caller's address, not the proxy's; a request over https at the proxy
counts as a protected connection, and the addresses in responses name the proxy with https.
Notes
- Windows sign-in only without shared connections. Windows sign-in applies to the connection on which it happened. A proxy that routes requests from different users over one connection to the service would give the second user the rights of the first. IIS with Application Request Routing forwards requests over shared connections. That's why
setup-host --mode iissetsAuthModetoPersonalKey, without Windows sign-in; people sign in with their personal key. IfWindowsis inAuthModeanyway and a trusted proxy is entered, the service logs a warning at startup. - Reading the origin: the service reads
X-Forwarded-Forfrom the nearest hop; the first address that isn't itself a trusted proxy applies. An entry the client adds at the front itself is thus not counted. An unreadable value makes the origin unknown; an unknown origin doesn't lift any block. Serverheader: the service itself doesn't name its server software. Behind IIS, IIS addsServer: Microsoft-IIS/10.0. On IIS 10 and later,removeServerHeader="true"on the template'srequestFilteringelement removes it:<requestFiltering removeServerHeader="true">. Earlier IIS versions don't know the attribute and answer with error 500.19, so the template doesn't set it.- Long addresses: without the template, IIS and http.sys allow only 2 KB of query string; clients can send long conditions in the body anyway, see HTTP: long queries.