Skip to content

v0.11.0

Choose a tag to compare

@github-actions github-actions released this 14 Oct 17:12
· 16 commits to main since this release
9efcafb

Added

  • An Editor who holds a subscription or a management group can write a Personal rule: a rule that only its author sees and runs, from a new Personal tab in the Library. It uses the same form as any rule, on the Resource Graph or Microsoft Graph backend, and its scope picker offers only what the person holds. Run now sends Resource Graph only the overlap of the rule's scope and the subscriptions and management groups the author holds at that moment, and replaces the rule's stored latest results. Those results show only on the rule's own page, with the last run time and the Scope it covered, and count nowhere shared: not in Results, Advisories, Activity, Run History, exports, dashboards, saved views, suppressions or posture. A person who loses some access keeps their rules and runs them over what they still hold; a person demoted to Viewer keeps them read-only; removing a person deletes their Personal rules and results. Each run adds one audit entry that names the rule and the covered Scope. Two new tables hold the rules and their results, and nothing existing changes, so going back to 0.10.1 loses nothing but those two tables' content.

  • Every rule in the Library, built-in or custom, has a Copy to personal action, on its row and on its page. It makes a Personal rule with the shared rule's name, description, category, severity, tags and query, then opens it. The copy starts with no results and no findings, and its scope keeps only the subscriptions and management groups the author holds (empty, meaning all of the author's access, when none of them overlap). The copy's page says which shared rule it came from and links to it, and the link goes away if that rule is deleted. The control is disabled, with the reason, for a Viewer, for an Editor who holds only resource groups, for a Microsoft Graph rule without the Directory, and for a Log Analytics rule. A new nullable column on the Personal rules table holds the link; nothing existing changes.

  • An Editor can send one of their Personal rules to the library as a Library request, from the rule's page with Send to library. The request keeps a copy of the rule as it was sent, so editing the Personal rule afterwards does not change what the reviewer reads. An Admin, or an Editor on Everything, sees a new Requests section in the Library with the number of open requests, and nobody else sees the section or the count. A reviewer opens a request to read its definition, query and scope, previews it, and approves it as a new custom library rule or rejects it with a reason. Preview runs the query once at the reviewer's own access, limited to what they hold, and stores nothing: no finding, scan, Personal rule result or last-run field changes. Approving can change the name, category, severity, scope and starting state first, and everything else comes from what the author sent; the new rule starts disabled unless the reviewer turns it on, has its own id, and a name that clashes with another library rule, ignoring case, is refused and leaves the request open. The author sees the status on the Personal rule, the reason when a request was rejected, and a link to the library rule it became, can withdraw an open request, and can resubmit a rejected one. A reviewer can also use Copy to library on their own Personal rule to add it with no request. Removing a person withdraws their open requests with the removal. Sending, approving, rejecting, withdrawing, previewing and copying each write one audit entry that names the rule and never the query or the rejection reason. A new table holds the requests, a nullable column on the rules table records the request a rule came from, and a nullable column on Personal rules records the library rule it became; nothing existing changes, so going back to 0.10.1 loses nothing but those.

  • An author can send a later edit of a Personal rule to the library as an update request aimed at one existing custom library rule, from the rule's page with Send as update to. It can target the library rule the Personal rule's approved request created, or the custom library rule it was copied from, and can be sent after an earlier request was approved. A copy of a built-in rule can only be sent as a new rule, and the page says so. The reviewer sees the target in the Requests list and on the request, a line diff from the library rule as it is now to the definition that was sent, and a warning when the library rule changed after the request was sent. Approving edits the library rule in place, so it keeps its id and the library has the same number of rules; its open findings, their ages and its suppressions stay as they were. The rule keeps its current enabled state unless the reviewer changes it. A name that clashes with another library rule, ignoring case, is refused and leaves the request open, and approval is refused when the library rule was deleted or the request's backend differs from it. Sending and approving each write one audit entry that names the rules and the changed field names, never the query. Two nullable columns on the requests table record the target and a snapshot of its definition; nothing existing changes, so going back to the previous release loses nothing but those two columns' content.

Changed

  • Every finding now records where it sits: at a resource, at a subscription, at a management group, in the Directory, at a Log Analytics workspace, or nowhere RuleBeat could place it. Microsoft Graph findings sit in the Directory and Log Analytics findings sit at their workspace, where both used to borrow the first subscription the credential listed. A Directory finding has no subscription, so the Scans page, the dashboard filters, the CSV export, the Run History snapshot and its export and webhook notifications read "Directory" where a subscription would be named, and "Directory" is one choice in the subscription filter, which also groups. A Logs finding takes the subscription and resource group of the workspace, looked up in Resource Graph by the workspace's customer id; when the workspace is not configured or cannot be found, the finding has no subscription until a scan can find it. On the first start after this upgrade every stored finding and every Run History record is placed from its own columns and its rule, and each Logs finding is placed at its workspace once it resolves. No fingerprint, age, history, row or suppression changes, and a suppression on a Graph finding still suppresses it. Going back to 0.10.1 loses nothing, since it ignores the new columns, and the next start or scan of this release corrects whatever it wrote meanwhile.

  • A notification channel limited to certain subscriptions no longer receives Directory findings, such as expiring app secrets and certificates, because they sit under no subscription. They had been delivered to a channel limited to the first subscription listed. A channel with no subscription limit still receives them.

  • RuleBeat now stores each person's access as a Role held at a Scope, and works out one access value for every request. Nobody can do more or less than before. On the first start after this upgrade every existing Viewer and Editor, pending invites included, is given one row that holds their current Role on Everything, with the source "manual", and the Access page shows "Everything, manual" for them and "Everything" for an Admin. Admins hold no rows. No user, local account or password changes, and a person narrowed to no Scope later is not granted Everything again on a restart. Inviting a person, changing a Role and removing a person keep those rows in step. Going back to 0.10.1 loses nothing, since it ignores the new table and column and keeps reading each person's Role as before; a person added there is picked up by the next start of this release.

  • Managing people moved from the Users card in Settings to a new Access page, reached from "Access" beside "Audit log" in the sidebar. Admins invite people, change a Role and set, reset or remove a local password there, as before, and /settings/users now opens /access. Every Role sees the entry: a Viewer or Editor sees their own access there, read-only.

  • Every read of findings, and of what is derived from them, now carries the access of the person who asked, and every request that queries Azure builds its connection from it. Scheduled scans and startup work run with their own system access.

  • A query someone writes now reaches Azure only inside the access they hold, on the Query page and in the rule editor's Resource Graph, Microsoft Graph and Log Analytics previews. Resource Graph is sent only the subscriptions and management groups they hold at a Role that can run queries: leaving the scope empty uses all of them, and a scope that names nothing they hold is refused. Microsoft Graph needs the Directory, and Log Analytics needs a Scope covering the resource group of the workspace. A person whose access is only resource groups cannot write queries, because Resource Graph cannot limit a query to one, and the Query page says a subscription is needed. The query text and its rows are never changed. An Admin and anyone on Everything are not affected, and scheduled scans send the same requests as before. Run now sends a smaller request for someone whose access is smaller than Everything.

  • An Admin can give a Viewer or Editor Manual access: a hand-picked list of Scopes, each with its own Role. A Scope is Everything, the Directory, a management group, a subscription or a resource group in one. Choose them on the Access page when adding someone, with Edit beside a person, or when demoting an Admin, where Everything is preselected. Adding a Viewer or Editor now needs at least one Scope. Everyone who is already here keeps Everything until an Admin changes their access. The Results, Advisories and Activity tabs then show a person only the findings inside their Scopes: every list, count, filter option, column option, export and finding detail. A subscription Scope covers the resource groups in it, findings at the subscription itself and the Log Analytics workspaces in it. A resource group Scope covers its own resources and workspaces. The Directory Scope covers Directory findings only. Findings that RuleBeat could not place are seen under Everything only. A person who holds no Scope sees a message that they have been given no access and to ask an Admin, in place of "No findings yet". Each Scope is stored under the Azure tenant RuleBeat is connected to, so a subscription, resource group or the Directory cannot be given before Azure is connected. Adding someone, changing their access, promoting and demoting each write one audit entry that names the fields changed and none of their values. Viewers and Editors see the Access page too: it lists their own Scopes, the Role at each and where the access came from, and holds nothing about anyone else.

  • An Admin can give a Viewer or Editor a management group as a Scope. That person sees the findings in every subscription under the group, at any depth, and the findings placed at the group or at a group beneath it, but not the Directory's, not findings RuleBeat could not place, and not those at a group above or beside it. RuleBeat keeps its own copy of the management group tree and reads it again every hour, so a subscription moved under a group is covered after the next read, and one moved out stops being covered, with no change to anyone's access. The Access page has a new Management groups card for Admins that shows the tree, when it was last read and a Refresh button. When a read fails, the tree is kept as it was, and the page says the refresh failed, when, and that the tree shown is the last one that loaded. The Scope picker offers each management group in the tree, and says why it lists none when the tree has not been read, the last read failed or Azure is not connected. A management group the tree does not hold is refused, and one a person already holds that has left the tree stays in their list so it can be removed. Refreshing from the page writes one audit entry that names no group or subscription. The Reader credential needs read access to the management group hierarchy for the tree to load.

  • An Admin can give a Viewer or Editor Mirrored access: one Role and a Linked account, which is an Azure object id and may be a different account from the one they sign in with. RuleBeat reads that account's Azure role assignments with its own Reader credential and turns them into Scopes. Active assignments and PIM-eligible ones count, whether held directly or through a group, and an assignment on a single resource gives its resource group. A role at the tenant root management group gives that group, and a mirror never gives Everything or the Directory. Deny assignments are ignored, and the Azure role never decides the Role. On the Access page, choose Mirrored access in Edit beside a person: saving shows the Scopes the account would give, and the Manual Scopes they hold that would be replaced, before Confirm. "Use their sign-in account" fills the object id for a person who signed in with Entra when sign-in uses the same tenant as the Azure connection, and the page says when another person is already linked to the account. Each mirrored person has a Refresh button, the time of the last successful refresh, each Scope with the Azure role that gave it ("through a group" where Azure says so), and, when the last refresh failed, a message that says so and that the Scopes shown are the last ones that loaded. A failed refresh keeps the Scopes and records a stable reason, never Azure's own text, and a refresh that finds no assignments leaves the person with no Scope and a message saying why. Editing a mirrored person's Scopes by hand turns them into Manual access with the same Scopes, and changing their Role keeps the mirror on. Confirming, refreshing, switching to manual and changing a Role each write one audit entry that names fields, never an object id, tenant id or Scope. The Reader credential needs no new permission. Nobody is mirrored by the upgrade: every existing person keeps the access they have, and the new columns start empty.

  • Mirrored access now refreshes by itself: about once an hour, after the management group tree is read, and in the background each time the person signs in, which never waits for it. Nobody has to press Refresh. A refresh that fails keeps the person's last Scopes, records a stable reason, and shows on the Access page the same way a failed manual Refresh does. Automatic refreshes write no audit entry.

  • Dashboards, the six dashboard widgets and saved views now count only what the person can see. Every number, list and filter option on a dashboard is built from the findings inside the Scopes a Viewer or Editor holds, and the Rules tab count on the Scans page follows. A saved view or dashboard filtered to a subscription or resource group outside a person's access still opens: the filter reads "Outside your access", it can be cleared, and an empty result says access is the reason instead of "No findings match your filters". A widget filtered only to such values says so instead of showing 100%, "No violations found" or "All rules passing". Trend history is kept for the install and for each subscription, never for a resource group, so a Viewer or Editor below Everything sees the trend of one subscription they hold whole (the one the filter names, or the only one they hold), and otherwise a message that trend history is kept per subscription. They are never given a number from the install-wide history. A person with no Scope sees the no-access message in place of a dashboard. Admins and people on Everything see the same numbers as before.

  • A person given less than Everything is now shown only what their Scopes cover on the Suppressions page, in the Rules tab and in the Azure pickers. Suppressions list only those on findings inside their Scopes, and the Rules tab's "resources affected" counts only the findings inside them. A rule's name, description and query are the same for everyone, but its scope no longer names a subscription or management group they do not hold: each shows as "Outside your access", once per entry, in the Library, the rule page and the Scans page. The subscription, management group and scope pickers list only what they hold, and a person who holds a resource group is shown its subscription. An Editor suppresses or removes a suppression only on a finding inside a Scope where they are an Editor, and is told "Not found" otherwise. Rules, schedules, categories and clearing findings change what the whole install shares, so an Editor on a Scope short of Everything sees New rule, edit, enable, disable, duplicate, delete, clear findings and every schedule control switched off with the reason, where they used to fail with a 403 when clicked, and the new rule page answers not found for them. An Editor on Everything may now also add, rename and delete categories, which only an Admin could before, and an Editor on a Scope short of Everything may not. An Admin sees no change, and neither does a Viewer, who still has no write control.

  • Run now works for an Editor whose access is smaller than Everything, and Run History says what each run covered. A run checks each shared rule only where the rule's own scope and the Editor's access overlap: a rule that covers the whole tenant is sent to the Editor's subscriptions, management groups and the subscriptions that hold their resource groups, a rule on a management group above a subscription they hold is sent to that subscription, and a rule that shares nothing with their access is not run, so it is not counted and does not make the run partial. A Microsoft Graph rule runs only for someone who holds the Directory, and a Log Analytics rule only when their access covers the resource group of the workspace. Queries are not changed, only where they are sent. A resource group cannot limit a Resource Graph request, so findings outside the resource groups an Editor holds are dropped before they are stored, counted or marked fixed. A run marks findings fixed only inside what it covered: another team's findings stay open until an Admin's run or a scheduled run checks them, and a rule that failed or was capped marks nothing fixed anywhere. Run History records the Scope of every run and shows it beside the run, with "Outside your access" for any part of it the reader's own access does not reach. A Viewer or Editor below Everything sees a run's totals, new findings and severity counts counted again from the findings inside their access, and only the subscriptions they hold under "scanned"; a run with no stored findings to count from says its counts are unavailable. A past run's snapshot and its export, and a compare and its export, list only the findings inside their access. Two runs that covered different Scopes cannot be compared, since what one did not cover would read as fixed, and the picker offers only runs that covered the same Scope as the first one picked. Runs from before this upgrade, scheduled runs and an Admin's runs covered Everything. Running a schedule from Schedules still needs Everything.

  • Every connection to Azure made for a person short of Everything is now limited to what they hold, whatever the route that made it. Resource Graph is sent only the part of a request inside their subscriptions, management groups and the subscriptions holding their resource groups, and a request outside all of them is refused before it is sent. Microsoft Graph needs the Directory and Log Analytics needs a Scope covering the workspace. Scheduled scans, startup work, Admins and people on Everything are not affected.

  • A run limited to an Editor's access no longer writes a rule's last run status, which is the rule's across the whole install. A failure in such a run shows in that run's Run History entry.

  • Inviting a Viewer or Editor now asks for Mirrored or Manual access, with neither chosen. Mirrored takes the Linked account's object id and shows the Scopes it would give before the invite is sent. An invite that names both, or neither, is refused.

  • A mirrored person's own access on the Access page shows when their access was last refreshed, and says so when the last refresh failed.

  • Microsoft Graph is switched off on the Query page and in the new rule picker for a person whose access does not include the Directory, with the reason beside it, where the query used to fail when run.

  • The Access list shows each Scope and its Role under a person with Manual access, the way it already did for Mirrored access.

  • The diff on an update request now follows the reviewer's edits to the name, category, severity and scope, so it ends on exactly what approving will write to the library rule.

  • Removing a person writes the names of the access fields the removal takes away (Role, source, Scopes, Linked account) into its audit entry, never their values.

  • Deleting a Personal rule withdraws its open Library request in the same transaction, so a failure part way can no longer leave a withdrawn request for a rule that still exists, or an open one for a rule that is gone.

  • Copy to library refuses a Personal rule that is already in the library, with the same reason the page gives, even after the Personal rule was renamed. The button was already off; a second request no longer adds a second rule.

Fixed

  • A saved view or dashboard filtered to one subscription counted Microsoft Graph and Log Analytics findings under it, because they carried the first subscription the credential listed. Filtered to a subscription, the Scans page, its exports, and the dashboard (including New vs Fixed and the Activity occurrences widget) no longer count them, and the subscription scorecard and the per-subscription trend no longer include them. They still count in the tenant-wide totals.