Web Access policy

Who reaches a web console through ISG, and what each of their requests may do. How a request travels is on how Web Access works; the identities and groups these rules use are on identities, groups and locks.

Who reaches an application

Web Access (apps.yaml, set up as in configuring applications) applies the same identities and groups to a web console. The login is the web UI's: password and second factor, or SSO. Each application has an id (APP-2026-000001); an approval, a session, a lock and an audit line belong to that id, not to the name, so two applications of the same name never share them. The pages show the friendly name, then the id. Then, per application:

Groups first: allow_groups

A user in none of the listed groups is refused (APP_ACCESS_DENIED); there is no application open to every signed-in user.

What the application learns about the user

Nothing, a signed assertion, or a shared account's secret — see configuring applications.

Approval, as a time window

With require_approval the user asks for a duration (up to approval_max_grant_seconds, 14400 by default) and someone else decides it in the web UI — nobody approves their own request. A pending request expires after approval_timeout_seconds (300 by default). The window opens at the decision; inside it the application can be opened again, and at its end the application session closes too. approval_single_use spends the approval on the first opening.

Self-service access on a stated reason

With approval_mode: self (the default is four_eyes) nobody decides: the user picks the duration, writes a justification, and the window opens at once. The justification is then mandatory — approval_reason_min_len characters at least (10 by default, at least 1), and if approval_reason_pattern is set, a part of it must match that RE2 pattern (a search, not a full match: write ^…$ for one). The same two keys make a four-eyes request's justification mandatory too. The grant is one COMMAND_APPROVAL_GRANTED audit line with approval_mode: self; the justification's text stays out of the audit and the ticket, which only says the access was self-service. The window, approval_single_use, an administrator's close and the end of the window work as for an approved request; a broker older than this feature does not know the key and asks for a four-eyes approval instead.

What each request may do

Request-level rules

http_rules in policy.yaml judge a request by application, method, path and role. A rule's action is deny (the default), step_up or allow; of the matching rules deny wins over step_up, and step_up over allow, whatever their order in the file, so an early, broad allow cannot override a later deny. A denied request gets 403 (APP_REQUEST_DENIED); the application never sees it, and the session stays. A rule sees the request that opens a WebSocket, not the frames, and not an operation encoded in a request body. ISG's own paths (/_isg/) and the application's logout_paths are never judged.

A fresh second factor for a sensitive path

An action: step_up rule (with its required valid_for, from 1m to 60m) holds a matching request until the user confirms the second factor again: a page load goes to the web UI, which asks for the code the web UI's mfa_mode uses — an authenticator code (or a recovery code), or an e-mailed one — also for a user who signed in with SSO. After it the application session passes the rule's requests for valid_for, never past the session's own end. A request that is not a page load (a form post, an API call, a WebSocket opening) gets 403 and the confirmation address, also in the X-ISG-Step-Up header: confirm in the browser, then repeat the operation. A WebSocket opened after the confirmation is not cut when it expires. A user with no usable factor (no authenticator under mfa_mode: totp, no e-mail address under email) is refused with an explanation, not sent to enrollment. The audit records APP_STEP_UP_REQUIRED, APP_STEP_UP_OK and APP_STEP_UP_FAILED. Under allow mode a step_up rule also lists its requests.

Allow-list mode, with a trial

http_app_modes puts an application into mode allow: only a request an allow rule matches (and no deny rule) gets through, everything else is 403 with rule http_mode:allow. Mode allow_audit is the trial run: the same requests pass, but each writes APP_REQUEST_WOULD_DENY — the list of the application's static files and API calls the allow rules still miss. Start an application in allow_audit, switch to allow once the audit is quiet. isg system check warns about an allow application no allow rule names: every request to it would be 403.

Conditions

A rule's when narrows it to days of the week, a time of day (the end is exclusive, a window may span midnight), a date range (both ends included) and client networks (CIDR, IPv4 and IPv6); the given conditions all have to hold. Days and times are read in the policy's timezone (Europe/Budapest by default). The client address is the connection's own: the gateway sits behind a keepalived address, not a proxy. A window that closes while a WebSocket is open does not cut it.

Upgrade every broker first

An older broker reads an allow or a step_up rule as a deny and ignores when (all stricter), but it does not know http_app_modes, so the allow-list would not apply there. Add an allow-list to policy.yaml only after every broker runs a version that knows it. One exception: v0.547.0 knows allow but rejects step_up as a load error, so on a v0.547.0 broker a step_up rule makes the whole policy.yaml fail and every Web Access request gets 503 — add step_up rules only after every broker runs v0.548.0 or later.

What is recorded

Every request

Every request is one line of the session's transcript: method, path, status, size, time — no body by default. Query parameters by name only, unless the application sets record_query.

Request bodies, opt-in

An application in apps.yaml (not a dynamic one) with record_body: true also puts the body of its POST, PUT, PATCH and DELETE requests on the line — only what the application actually read, at most record_body_max_bytes (default 4096, 256 to 65536) of it, the full size always. A refused request's body and a WebSocket handshake are never read. The body is masked before it is written, and the masking cannot be turned off: in a form or JSON body the value of every field whose name contains password, passwd, pwd, secret, token, api_key, apikey, auth, authorization, credential, private_key, session, cookie, otp or totp (any case; record_body_mask_fields adds names, it cannot remove one) becomes ***, and in every recorded value a Bearer or Basic credential, a JWT and a PEM private key become ***. A multipart body shows only its parts' names, file names and sizes; any other type only its type and size. A body that does not parse is marked, not dropped from the recording. The body lives in the transcript, so it is kept and archived exactly as the transcript is (retention.yaml transcripts), and whoever can read the transcript today can read it. A body can carry personal data, and a WORM archive cannot correct a value the masking missed — enable it only for applications whose changes the audit needs.

How a session ends, and who manages the applications

How it ends

Signing out of the web UI, losing the group, or an administrator closing the session ends the application session on every broker, within about 5 s for the serving broker.

Who manages the applications

With dynamic_apps_domain set, an administrator past the session_admin_group gate adds, changes and deletes applications on the web UI's Manage apps page (/apps/manage); an auditor sees the list but cannot write, and a refused write is audited as SESSION_ADMIN_DENIED. The applications in apps.yaml cannot be changed there. A save names what has no effect: approval fields filled in while approval is off are not saved, and a group the identity source does not have, or one without members, is named; the save stands either way. A change of the groups takes effect on the next request; deleting an application closes its sessions (reason app_deleted). The audit log records APP_CREATED, APP_UPDATED (with the old and new groups, approval and level) and APP_DELETED.