Skip to content
PagesWeb UI

EIDGuard docs

On this page

Web UI

A small web companion for day-2 operations: health dashboard, snapshot browsing, restores with WhatIf preview, verification, on-demand backups, certificate rotation, recovery-point export, and settings — secured by Entra ID sign-in with app roles. Tenant onboarding (app registrations, admin consent, certificate issuance) happens here too, in the browser Setup Wizard; see setup-wizard.md.

Architecture#

Everything below is provisioned by marketplace/bicep/ as part of the solution template deployment, into the resource group you own. One Function App serves both the SPA (a {*path} catch-all) and /api/*.

Browser
   │        Function App (PowerShell 7.6, Linux App Service plan,
   │            │            B1 default up to P1v3, Always On)
   │            │  Bearer tokens (msal-browser PKCE); Easy Auth validates JWTs
   │            │  App roles: Viewer / Operator / Admin
   │            ▼
   │       /api/* PowerShell functions (import ExternalIDBackup.psm1)
   │            │  the SPA is served by the same app ({*path} catch-all)
   │            │
   │            │  managed identity:
   │            │    Storage Blob Data Owner + Queue/Table Data Contributor
   │            │      (keyless host storage requires all three)
   │            │    A custom storage role limited to the lifecycle-management
   │            │      policy — the retention setting's only control-plane call
   │            │    Key Vault Certificates Officer (see the note below —
   │            │      manages certificate OBJECTS, cannot export private keys)
   │            │    EIDGuard Automation Operator (one custom role carrying
   │            │      exactly the needed actions, including both
   │            │      hybrid-worker read actions)
   │            │    Website Contributor on its OWN site only, so the Setup
   │            │      Wizard can flip authsettingsV2
   │            ▼
   └──── long-running operations run as Automation runbook jobs:
          Backup-ExternalID · Restore-ExternalID-Job ·
          Compare-ExternalID-Job · Rotate-ExternalID-Cert ·
          Export-ExternalID-Job · Deploy-ExternalID-Networking ·
          Raise-ExternalID-Immutability
          (on the hybrid worker when private networking is deployed)

   Automation account's own identity:
          resource-group-scoped Automation Contributor, which is where its
          jobs/read for the sibling-job guard comes from

Runbooks are bundled and published at deployment time by the deployment script identity, never at runtime.

Key Vault: what the web identity can actually do#

The web identity holds Key Vault Certificates Officer (marketplace/bicep/modules/roles.bicep:177-186) — certificatecas/*, certificates/*, certificatecontacts/write. It cannot export a certificate's private key.

That is a statement about one specific action, so read it from the live role definition rather than from the role name. A Key Vault certificate's private key is retrieved by reading its backing secret, which requires Microsoft.KeyVault/vaults/secrets/getSecret/action. Certificates Officer does not list it, and certificates/* does not reach it, because RBAC action strings do not prefix-match across resource types (the same rule as the hybrid-worker actions).

Do not "simplify" this to Key Vault Certificate User. That role sounds narrower and is not — read from the live role definitions:

Role dataActions Can export the PFX?
Key Vault Certificates Officer (what the deployment grants) certificatecas/*, certificates/*, certificatecontacts/write No
Key Vault Certificate User certificates/read, secrets/getSecret/action, secrets/readMetadata/action, keys/read Yes

The two roles are different rather than nested: Certificates Officer is broader over certificate objects (create, import, update, delete — which browser onboarding needs) and narrower over secret material. Certificates Officer was granted deliberately, and the narrower-sounding alternative is the more dangerous one.

These docs have had this backwards before. An earlier version of this page described Certificates Officer as "Certificate User plus more". It is not, and the mistake points the wrong way — it makes the role that can export private keys look like the safe simplification. If you are about to change this grant, re-read both role definitions rather than their names.

What the code does is narrower still: the only web-tier Key Vault read is Test-BackupCertificateExpiry -PublicOnly (modules/ExternalIDBackup.psm1:224-228), which calls Get-AzKeyVaultCertificate and uses .Expires. No web-tier path fetches a private key.

Why the distinction is load-bearing. The vault holds the backup and restore apps' certificates, and those certificates are those apps' Graph credentials. Anything able to call getSecret on that vault could obtain the restore app's PFX and authenticate to Microsoft Graph as an application holding .ReadWrite on the customer tenant. The role boundary is what prevents it — not the absence of a Graph permission, and not the fact that no code path tries.

Two read grants in the diagram are not decoration, and both are easy to lose by tidying a role definition:

  • Web identity → hybridRunbookWorkerGroups/read + hybridRunbookWorkers/read. The offline-worker probe (Get-HybridWorkerStatus) needs both, and neither Automation Operator built-in includes them. Without them the probe 403s and the guard silently protects nothing — in exactly the private-networking topology it exists for. The custom EIDGuard Automation Operator role names them outright.
  • Automation identity → jobs/read on its own account. The overlapping-run guard (Get-RunbookSiblingJob) reads jobs on the account it is running in. It reaches that through the resource-group-scoped Automation Contributor the identity holds for the networking feature. If that is ever narrowed, the guard fails open — it warns loudly when it does, and tests/RolesTemplate.Tests.ps1 pins the grant.

Design decisions:

  • The API is a PowerShell Function App, and the SPA rides along on it. Azure Static Web Apps managed functions never support PowerShell, so a Function App was always going to serve /api/*; having it serve the SPA too (via the {*path} catch-all) means one origin, one Easy Auth configuration and no CORS.

  • The dedicated Always On plan is what removes cold starts. A scale-to-zero plan costs the first caller several seconds while the PowerShell worker spins up, which on a dashboard is the first thing anyone sees. The B1 plan is the single largest fixed cost in the deployment and buys exactly this.

    The KeepWarm timer still runs, and still earns its place: it fires every 4 minutes and refreshes the health payload into a cache blob, so the Overview serves from one small read instead of chaining ARM and storage calls.

  • No web API code path writes to a tenant. Restores and rotation execute inside Automation runbooks that fetch the restore app's certificate from Key Vault — the same trust boundary as the scheduled backup. The web identity holds no Graph permission of its own.

    Writes that do reach an External ID tenant are made with credentials other than the web tier's identity. In the administrator's browser, on their own delegated token: onboarding and offboarding both work this way (web/app/src/pages/Onboarding.tsx requests Application.ReadWrite.All and AppRoleAssignment.ReadWrite.All, and its offboard() issues DELETE /applications/{id} with the same token), so those writes are made as the admin who is present. And inside an Automation runbook, on the restore app's certificate fetched from Key Vault. Neither writer is the web tier's own identity.

    "No Graph permission" is not by itself the same as "cannot reach the tenant". Anything that can export the restore app's certificate holds that app's Graph credential, so the missing Graph permission would only add a hop. What closes the path is the Key Vault role: it cannot export private keys. Keep both halves of that argument together — see Key Vault: what the web identity can actually do.

  • Blob is the source of truth. The UI lists cloud snapshots and their manifests; reports produced by web-triggered jobs land under backups/<tenant>/<stamp>/reports/.

  • Export / offboarding: Configuration → Export recovery points starts Export-ExternalID-Job, which copies every recovery point to a customer-owned storage account with the Automation managed identity (the customer grants it Storage Blob Data Contributor on the destination; AAD-only, no SAS or account keys) — so deleting a deployment does not destroy the backups. Re-runs are incremental (same path+length blobs are skipped).

  • Webconfig: a sanitized projection of settings.json (no secrets exist in it) is uploaded to the private webconfig container by Publish-BackupWebConfig so the API knows the deployment shape. Deploy scripts refresh it whenever config changes; the rotation runbook patches thumbprints in place.

Deployment and access#

The deployment is created from the marketplace offer; there is no deploy script to run. First-run sign-in setup is the browser Setup Wizard — see setup-wizard.md, which also covers who needs which admin role.

The administrator who completes the Setup Wizard is auto-assigned Admin. Assign everyone else in Entra ID → Enterprise applications → EIDGuard-WebUI (<site>) → Users and groups (deployments set up before the 2026-09 rename carry ExternalID-Backup-WebUI (<site>) — setup runs once, so the name never changes in place); the dashboard's Users page is read-only by design.

Role Can
Viewer Dashboard, snapshots, object browser, jobs, reports
Operator + backup now, compare, restore previews, missing-only restores of users, identity providers, user attributes, custom extensions, API connectors, Conditional Access (new policies created disabled) and branding — including re-creating deleted user accounts, which can then sign in
Admin + Full-mode (overwrite) restores, restores that include Groups, Applications, ServicePrincipals, UserFlows, Policies, TenantPolicies, GroupSettings, DirectoryRoles or AdministrativeUnits (see Restore modes), certificate rotation, settings, onboarding

Settings writes — RPO, retention, verification, alert email and the time zone — are first-class UI features and always available to Admins.

Sign-in uses no secret at all. The Setup Wizard registers the dashboard as an SPA client (web/api/SetupComplete/run.ps1:69) with no password credential, and flips the Function App's Easy Auth to bearer token-validation (:147), so the browser signs in with PKCE and the API validates the resulting token. There is no client secret anywhere in the deployment — the confidential- client flow that needed one belonged to the removed deploy script.

Backup schedule#

Configuration → Protection → Backup schedule is one row: Default RPO, Time zone and Run hour (the Anchor hour for a sub-daily RPO), saved together by one Save schedule button. A line under the row says what the choice means. Only an Admin can save (PUT /api/settings/schedule); everyone else sees the row read-only, with "Requires the Admin role."

Time zone#

The time zone is one deployment setting with two meanings:

  • Every schedule runs in it. The backup schedule, the daily verification and, on a private deployment, the Hybrid Worker's start/stop window are all created in that zone. The run hour is a local hour of it — the picker reads "2:00 AM", with no UTC in brackets — and it stays at that local time through daylight saving: "Backups run at 2:00 AM New York time, all year." That is what a maintenance window usually needs.
  • Every time on the dashboard is shown in it — next runs, job start and end times, recovery points, drift reports and job logs, with the zone's short name (for example EDT) where a bare time could be ambiguous.

Not set (the default) keeps everything as it always was: schedules run in UTC, the run hour reads "02:00 UTC", and each viewer sees their own browser's zone. The line under the row then says where that UTC hour lands for you through the year — "Backups run at 02:00 UTC — 9:00 PM in winter, 10:00 PM in summer in New York" — and that choosing a time zone pins it instead.

Choosing a zone is a schedule change, saved with the rest of the row. It keeps the hour number you picked (2 stays 2, now 2:00 AM local) and moves what runs on the clock: the backup schedule and the verification schedule at the same local hour, and — on a private deployment — the worker window around them. Both job schedules carry the zone in their names in Azure Automation (ExternalID-Backup-24h-02-America-New_York; no zone, no suffix — the names you already have), so a move creates the new schedule beside the old one and removes the old one only once the new one is linked; backups are never left unscheduled. The worker's own start/stop schedules stay in UTC (see below). The time zone is recorded — and times switch to it — only once all three have moved; if one did not, the page says which and Save schedule again finishes it. Saving the schedule without changing the zone never moves the clock. Zones are IANA names, spelled exactly; pick a canonical one (Asia/Kolkata, not the older alias Asia/Calcutta) — a name the server cannot place on a clock is refused with a message saying so. A version upgrade keeps the zone (see plans and limits).

What a local time means on the two days a year the clocks change:

  • One gap is an hour longer, one an hour shorter. A daily backup is 25 hours after the previous one on the night the clocks go back (23 when they go forward); a 6-hour schedule has one 7-hour and one 5-hour gap. A tenant keeps its local slot rather than drifting to a new hour, and the Overview does not call the longer gap late. Only the clocks going back is allowed for: the shorter gap never lets a tenant go past its RPO.
  • The Hybrid Worker (private deployments) stays on UTC, so its windows are about an hour longer. Its start and stop schedules never take the zone: each window is widened to cover both UTC instants a local time can fall on — 2:00 AM New York is 06:00 UTC in summer and 07:00 UTC in winter, so the VM runs from 05:45 to 09:00 UTC every day — and so it is up for every job whatever Azure does on the nights the clocks change. In a zone without daylight saving (Kolkata, for example) the window is the usual length; in one that moves by half an hour (Lord Howe), half an hour longer. The window also covers the times Azure itself reports for the schedules, and if a run Azure will fire is ever outside it, Needs attention says so ("The next backup is due while the Hybrid Worker VM is off") while the dashboard re-aims it. A zone whose Windows time zone keeps different clock changes (the server compares the two) cannot be chosen on a private deployment — the save says why; pick UTC or a nearby zone (private endpoints).
  • A schedule saved just before a change starts at its next run — the same night — unless that night is the one whose run time the clocks skip: then it starts at the following night's, which is a real local time.
  • A local time that does not exist (2:30 AM on the US spring-forward night) runs at the same moment read just before the jump — 3:30 AM.
  • A local time that happens twice (1:30 AM on the night the clocks go back) backs each tenant up once, even if Azure fires it twice.

A deployment that chose a display-only zone before schedules could follow one keeps seeing times in that zone; its schedules stay on UTC (the line under the row says so) until the schedule is saved with a zone, which makes it both.

The Overview's backup calendar still counts UTC days; when another zone is shown, its heading and tooltips say "UTC days".

Recovery points#

A recovery point is one backup of one tenant: a read-only copy of its configuration, taken on the schedule or by Run backup. Open one from Recovery points to browse the captured files and objects, compare it, or restore from it.

Deletion protection (the immutable window)#

Recovery points are written under a version-level immutability policy. While that policy is locked, Azure refuses to delete or overwrite a recovery point for the window's length, counted from its capture — for anyone, a subscription Owner and Vambris included. Each point keeps the window that was in force when it was written: a locked window can be raised later but never lowered, so a point written before a raise keeps at least its shorter window, and a point written before the lock has no locked window at all. A recovery point's page shows the policy:

Shown Meaning
Locked policy · N days Files written while this locked policy was in force cannot be deleted for N days after they were written.
Window ended The point's captured files are older than today's window, so the locked policy no longer protects them. Retention and Azure permissions now decide when they go.
Not locked A policy exists but was never locked, so a deployment did not finish. Azure still refuses deletes today, but anyone with full access to the subscription can shorten or remove the policy. Redeploying the template completes the lock.
Not immutable No policy. Azure permissions alone govern deletion.
Not confirmed The policy could not be read just now, so no protection is claimed. Reload to check again.

The window belongs to each file, not to the recovery point as a whole: a report added later — by a comparison or a restore — is written under the point and keeps its own window, counted from when it was written.

Retention is a separate control: it decides when a recovery point is removed once its window allows it. The window also sets how long an uninstall has to wait; see Before you delete the deployment.

Raising the window#

The window ships at one day, so the permanent choice is never made for you at install. To lengthen it, an Admin opens Configuration → Protection, enters the new number of days in the Deletion protection section (it shows the current window, like Retention above it) and selects Apply. Viewers and Operators see the window read-only, and the API refuses a raise to them. Apply stays disabled while the policy cannot be read, and until the value is a whole number above the current window and within the limits below.

A raise can never be undone — not by you, not by Vambris, not by a subscription Owner. Azure lets a locked policy be extended but never shortened or removed, and only a limited number of times — so pick the window you want to keep rather than stepping up to it. Apply opens a warning that asks for the number of days to be typed again, and nothing is sent until it matches.

The dashboard does not change the policy itself. It starts the Raise-ExternalID-Immutability job, which appears on the Jobs page; the Protection page links to it while it runs and shows the new window when it completes, along with how many times the policy had already been extended. If the job refuses — for any of the reasons below — it checks everything before it touches the policy, so the page says nothing was changed and the job says why. If Azure refuses because the policy has already been extended as many times as it allows, the job says so, and the window stays where it is for good. If the job instead ends any other way (it failed or was stopped after the change was sent), the page does not guess: it re-reads the window from Azure and shows it.

  • The new window must be more than the current one and at most 3650 days (ten years), the longest retention the dashboard can set.
  • At most one raise a day. Counted from the policy's own record of extensions — so a raise within 24 hours of the last one is refused however that one was made, including by a redeploy.
  • Retention must already be at least the new window — the default on Configuration → Protection and every tenant's own window on the Tenants page (0, keep forever, is always fine). The job also checks the storage lifecycle rules Azure actually runs. Otherwise Azure would be asked to delete recovery points it has promised to keep, so the raise is refused and the message names each retention to change first.
  • The raise applies from now on, and Azure may also hold existing recovery points longer.
  • Keeping recovery points longer costs a little more storage (about $0.02/GB a month; a tenant snapshot is typically well under a megabyte).
  • Uninstalling waits longer. Azure will not delete the backups container while it holds a protected recovery point, so removing the deployment must wait until the newest one is older than the window.

The page shows the new window as soon as the job confirms it with Azure. Redeploying or upgrading never lowers it: the deployment keeps whichever is larger, the window Azure enforces or the one the template asks for.

Offboarded tenants#

An offboarded tenant's recovery points stay listed, marked offboarded, until retention removes them. You can browse them, but restoring or comparing needs the tenant onboarded again: offboarding deleted its backup and restore applications, so there is nothing to sign in to the tenant with.

Restoring from a recovery point#

Choose Restore on a recovery point. The wizard has four steps before anything changes: pick the resource types, pick a mode, review a preview, then type RESTORE to confirm. Resource types are restored in dependency order — attributes and identity providers first, then users, groups and applications, then user flows, Conditional Access and role assignments — so references between them can be rewritten to the restored objects' new IDs.

Restore modes#

  • Missing only (the default) recreates objects that no longer exist in the tenant. Objects that still exist keep their properties, but missing links to them are re-added: group members and owners; application owners, federated identity credentials and extension properties; application permissions granted to apps and other app role assignments (every service principal is captured, Microsoft Graph's included); user flow application links; and directory role assignments, Global Administrator included. Tenant-wide settings (the default branding, directory settings) are created only when the tenant has none, and are never overwritten. An Operator can apply it — unless the selection includes a type that can re-grant access (below).
  • Full (disaster recovery) also overwrites existing objects with the recovery point's contents, tenant-wide settings included. An Operator can preview it; applying it needs Admin.

Applying a restore that includes Groups, Applications, ServicePrincipals, UserFlows, Policies, TenantPolicies, GroupSettings, DirectoryRoles or AdministrativeUnits needs Admin in either mode, because each can re-grant access even in Missing only: application permissions (including on Microsoft Graph), directory role assignments and custom role definitions, federated credentials and app owners, group members and owners (a role-assignable group carries directory roles), administrative-unit scoped role members, applications re-linked to an existing user flow (which reopens self-service sign-up into them), cross-tenant partner configurations with their inbound trust, custom permission grant policies (what users may consent to), and tenant-wide directory settings such as consent and group-creation settings. An Operator can still preview them.

What an Operator can apply is a Missing-only restore of the rest: users, identity providers, user attributes, custom authentication extensions, API connectors (created with a placeholder credential), Conditional Access (new policies are created disabled) and branding. That includes re-creating deleted user accounts, which is the core of a restore: a recreated account keeps the enabled state it was backed up with and can sign in — once an administrator resets its random password, or straight away with a social or other identity that needs no password. It gets no assigned group membership, role or app permission from that alone, though a dynamic-membership group's rule can still add it.

The API enforces this, not the page: web/api/ActionRestore/run.ps1 refuses the apply with 403 using the list in Get-PrivilegedRestoreResourceNames (web/api/Modules/WebApi/WebApi.psm1).

Conditional Access policies a restore has to create are created disabled. In Full mode, though, an existing policy takes its backed-up state — so a policy that was enabled in the recovery point is switched back on. Some things cannot be exported from Microsoft Graph at all — user passwords, application and identity-provider secrets, MFA registrations, branding images — so restored objects get placeholders, and the result lists each one under Manual actions required. An applied restore also saves its results and that checklist with the recovery point's reports.

Preview (WhatIf) runs#

Every restore starts with a preview: the same restore job, run against the live tenant with nothing written. A preview lists the existing objects it will keep and anything it skips. It does not list or count the objects it would create or overwrite, or the links it would re-add (the members, owners, credentials, permissions and role assignments above) — in Full mode, any object in the selected resource types that is not listed will be created if it is missing, or overwritten if it exists.

For property-level detail, the review step also shows the newest comparison of this recovery point against the live tenant that covers the selected resource types. If none does, run one from Drift first.

Verification and drift#

A comparison checks a recovery point against the live tenant, or against another recovery point, and reports what was added, modified or deleted. It uses the tenant's read-only backup application, so it never changes anything.

  • Scheduled verification — when enabled under Configuration → Protection, runs daily and compares each tenant's newest recovery point with the live tenant. Differences do not fail the job; they raise the drift alert (see Alerts that ship).
  • On-demand comparisons — Drift → Run comparison, or Compare on a recovery point. These never raise the drift alert; a comparison job that fails still raises the failed-job alert, like any other job.

Each report is kept with its recovery point. A report stores at most the first 500 differences; its counts include every difference, and the page says when the stored rows are only part of them.

Certificate rotation#

Rotate-ExternalID-Cert (Operations → Rotate…) rotates with zero downtime:

  1. issues a new self-signed version of the same Key Vault certificate (the private key never leaves the vault),
  2. adds it to the app registration's keyCredentials (authenticating as the restore app, which holds Application.ReadWrite.All),
  3. verifies an app-only Graph token with the new certificate (retrying up to 10 minutes for key propagation),
  4. only then removes the old credential and disables old vault versions,
  5. updates the webconfig thumbprints.

If verification fails, the job rolls back: original keyCredentials are restored and the previous vault version is re-imported as current, so every consumer keeps using the proven-good certificate. Rotating both does the backup app first and the restore app last (it bootstraps off its own still-valid certificate). Local certificate-store copies on admin workstations become stale by design — Key Vault-based auth picks up new versions automatically.

Private networking from the UI#

POST /api/actions/deploy-networking (Admin). The Networking wizard (Configuration → Private networking) collects the VNet choice — empty for a dedicated VNet created inside the resource group, where the deployment identity already has rights, or an existing VNet resource id after a one-click Network Contributor grant made browser-direct with the signed-in admin's own ARM token — plus subnet names/prefixes and worker VM size, and starts Deploy-ExternalID-Networking (automation/runbook-networking.ps1, registered in marketplace/bicep/modules/runbooks.bicep, allowlisted in Get-WebRunbookNames). The runbook deploys the private endpoints for Key Vault/storage/Automation — optionally the web app too — the hybrid worker, and the data-plane lockdown. Deployment is estate-wide, so it takes the deploy-networking/estate action lock and refuses to start while another such job is running (409).

The worker's power jobs (Start-HybridWorkerVM / Stop-HybridWorkerVM) appear on the Jobs page and in the Overview's recent operations, labelled Worker VM power on / Worker VM power off, so a failed power-on shows up as a failed job. They are listed through Get-WebVisibleRunbookNames (web/api/Modules/WebApi/WebApi.psm1, used by JobList/JobDetail/JobOutput and the health payload) but are not in Get-WebRunbookNames, so Start-WebRunbookJob still refuses to start them. The one web-tier start of Start-HybridWorkerVM is Sync-HybridWorkerWindow's direct Start-AzAutomationRunbook call on a schedule save, which takes no runbook name from the request.

A second, parameterless branch used to sit in front of this one for the legacy self-host deploy, gated on webui.networkDeployEnabled. It was dead on arrival (issue #33) — the flag was written false unconditionally and the -EnableWebNetworkDeploy switch its error message told customers to pass never existed — and it was removed along with the self-host deploy scripts.

Marketplace plan surface#

On solution-template deployments, GET /api/config carries an extra plan object alongside the usual configuration projection:

{ "plan": { "name": "Standard", "tenantLimit": 5, "tenantCount": 2 } }
  • name and tenantLimit come from the verified licence when the deployment holds one — issued by the licensing service from your EIDGuard SaaS subscription at setup and refreshed every six hours — and otherwise from the EIDB_PLAN_NAME / EIDB_TENANT_LIMIT Function App settings stamped into the package, which describe the plan the package was deployed from (Get-ApiPlan: licence first, settings as the fallback). tenantCount is computed from the tenant list in the same response. tenantLimit 0 means unlimited.
  • The plan object is attached to a shallow copy of the cached config — the response never writes it back to the webconfig blob.
  • The marketplace template is what writes the fallback settings, so the key is absent only on a deployment that predates plan stamping. The SPA treats an absent plan on a successfully loaded config as "no plan configured" and hides the plan card; every other state (including an unlimited Enterprise plan) is treated as a capped-capable deployment, and a config refresh that fails then blocks onboarding rather than guessing (blockOnRefreshFailure, web/app/src/lib/plan.ts). Note that all of this is the SPA's display and pre-flight rule only — enforcement is server-side at the onboarding commit.
  • The SPA gates on it in three places that must not drift — the onboard button, the pre-flight guard inside onboard(), and the Configuration Plan card — all through web/app/src/lib/plan.ts.

Enforcement itself is server-side, at the onboarding commit only. See plans-and-limits.md for what the limit counts, what a downgrade does, and how to change plan.

Vambris announcements#

The megaphone icon at the top right, beside the Needs-attention bell, is where announcements from Vambris appear — typically that a new EIDGuard version is available. It is always there: with no announcement, selecting it says the dashboard is up to date and shows the running version and build — but only when the dashboard has recently reached the Vambris licensing service, which is how announcements arrive; otherwise it says it cannot confirm that. When an announcement arrives the icon gets a small dot until you read it; select it to read the title and message, open the release notes or How to update (the steps to redeploy the new version from the Azure Marketplace — EIDGuard does not update itself), or Mark as read (which removes the dot, remembered in this browser, per announcement — the announcement itself stays there to reopen). It is carried inside the signed licence that the existing six-hourly heartbeat to activate.vambris.com already returns, so it adds no new outbound connection and nothing to allow through a firewall, and it is shown only from a licence that verifies as issued to this deployment and has not expired. The title and message are rendered as plain text, never as HTML or clickable links, and are refused if they contain a web address (:// or www.). The announcement's one link is a separate button, and it can point only at vambris.com (or a subdomain of it) or at one of four Microsoft hosts: portal.azure.com, learn.microsoft.com, azuremarketplace.microsoft.com and marketplace.microsoft.com. Treat the wording itself the way you would any vendor message: it names Vambris, but a plain-text sentence can still ask you to do something, and the product checks where the link goes, not what the text says. Marking it as read removes the dot in the browser you did it in; an update announcement also disappears on its own once the update is installed, and is not shown at all to a deployment already running that release or a newer one.