diff --git a/menu/menu.yaml b/menu/menu.yaml index f3b79aba770..cf2aedff716 100644 --- a/menu/menu.yaml +++ b/menu/menu.yaml @@ -1505,6 +1505,8 @@ Articles: - Title: Authentication Url: servicepulse/security/configuration/authentication + - Title: Role-Based Access Control + Url: servicepulse/security/configuration/authorization - Title: Forward Headers for Reverse Proxy Url: servicepulse/security/configuration/forward-headers - Title: TLS @@ -1600,6 +1602,8 @@ Articles: - Title: Authentication Url: servicecontrol/security/configuration/authentication + - Title: Role-Based Access Control + Url: servicecontrol/security/configuration/authorization - Title: Forward Headers for Reverse Proxy Url: servicecontrol/security/configuration/forward-headers - Title: TLS diff --git a/servicecontrol/audit-instances/configuration.md b/servicecontrol/audit-instances/configuration.md index 9d13fbd2efc..c0e555bed9e 100644 --- a/servicecontrol/audit-instances/configuration.md +++ b/servicecontrol/audit-instances/configuration.md @@ -289,6 +289,70 @@ Controls whether HTTPS is required when retrieving metadata from the authority. > [!WARNING] > Setting this to `false` is not recommended for production environments. +### ServiceControl.Audit/Authentication.RoleBasedAuthorizationEnabled + +_Added in version 6.18.0_ + +Enables [role-based access control](/servicecontrol/security/configuration/authorization.md) on the Audit instance. When `false`, every authenticated user is granted every permission. Has no effect unless `Authentication.Enabled` is `true`. + +| Context | Name | +| --- | --- | +| **Environment variable** | `SERVICECONTROL_AUDIT_AUTHENTICATION_ROLEBASEDAUTHORIZATIONENABLED` | +| **App config key** | `ServiceControl.Audit/Authentication.RoleBasedAuthorizationEnabled` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| bool | `false` | + +### ServiceControl.Audit/Authentication.RolesClaim + +_Added in version 6.18.0_ + +The token claim from which user roles are read. Supports a flat claim name or a dotted path into a nested JSON object claim. See [reading roles from the token](/servicecontrol/security/configuration/authorization.md#reading-roles-from-the-token). + +| Context | Name | +| --- | --- | +| **Environment variable** | `SERVICECONTROL_AUDIT_AUTHENTICATION_ROLESCLAIM` | +| **App config key** | `ServiceControl.Audit/Authentication.RolesClaim` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| string | `roles` | + +### ServiceControl.Audit/Authentication.SubjectIdClaim + +_Added in version 6.18.0_ + +The token claim used as the stable user identifier in the [authorization audit log](/servicecontrol/security/configuration/authorization.md#authorization-audit-log). Requests are rejected if this claim is missing from the token. + +| Context | Name | +| --- | --- | +| **Environment variable** | `SERVICECONTROL_AUDIT_AUTHENTICATION_SUBJECTIDCLAIM` | +| **App config key** | `ServiceControl.Audit/Authentication.SubjectIdClaim` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| string | `sub` | + +### ServiceControl.Audit/Authentication.SubjectNameClaim + +_Added in version 6.18.0_ + +The token claim used as the human-readable display name in the [authorization audit log](/servicecontrol/security/configuration/authorization.md#authorization-audit-log). Requests are rejected if this claim is missing from the token. + +| Context | Name | +| --- | --- | +| **Environment variable** | `SERVICECONTROL_AUDIT_AUTHENTICATION_SUBJECTNAMECLAIM` | +| **App config key** | `ServiceControl.Audit/Authentication.SubjectNameClaim` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| string | `preferred_username` | + ## [TLS](/servicecontrol/security/configuration/tls.md) These settings configure HTTPS. Refer to the [hosting and security guide](/servicecontrol/security/hosting-guide.md) or [TLS configuration examples](/servicecontrol/security/configuration/tls.md#configuration-examples) for additional information. diff --git a/servicecontrol/monitoring-instances/configuration.md b/servicecontrol/monitoring-instances/configuration.md index f45abe6cc19..84b69802931 100644 --- a/servicecontrol/monitoring-instances/configuration.md +++ b/servicecontrol/monitoring-instances/configuration.md @@ -228,6 +228,70 @@ Controls whether HTTPS is required when retrieving metadata from the authority. > [!WARNING] > Setting this to `false` is not recommended for production environments. +### Monitoring/Authentication.RoleBasedAuthorizationEnabled + +_Added in version 6.18.0_ + +Enables [role-based access control](/servicecontrol/security/configuration/authorization.md) on the Monitoring instance. When `false`, every authenticated user is granted every permission. Has no effect unless `Authentication.Enabled` is `true`. + +| Context | Name | +| --- | --- | +| **Environment variable** | `MONITORING_AUTHENTICATION_ROLEBASEDAUTHORIZATIONENABLED` | +| **App config key** | `Monitoring/Authentication.RoleBasedAuthorizationEnabled` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| bool | `false` | + +### Monitoring/Authentication.RolesClaim + +_Added in version 6.18.0_ + +The token claim from which user roles are read. Supports a flat claim name or a dotted path into a nested JSON object claim. See [reading roles from the token](/servicecontrol/security/configuration/authorization.md#reading-roles-from-the-token). + +| Context | Name | +| --- | --- | +| **Environment variable** | `MONITORING_AUTHENTICATION_ROLESCLAIM` | +| **App config key** | `Monitoring/Authentication.RolesClaim` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| string | `roles` | + +### Monitoring/Authentication.SubjectIdClaim + +_Added in version 6.18.0_ + +The token claim used as the stable user identifier in the [authorization audit log](/servicecontrol/security/configuration/authorization.md#authorization-audit-log). Requests are rejected if this claim is missing from the token. + +| Context | Name | +| --- | --- | +| **Environment variable** | `MONITORING_AUTHENTICATION_SUBJECTIDCLAIM` | +| **App config key** | `Monitoring/Authentication.SubjectIdClaim` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| string | `sub` | + +### Monitoring/Authentication.SubjectNameClaim + +_Added in version 6.18.0_ + +The token claim used as the human-readable display name in the [authorization audit log](/servicecontrol/security/configuration/authorization.md#authorization-audit-log). Requests are rejected if this claim is missing from the token. + +| Context | Name | +| --- | --- | +| **Environment variable** | `MONITORING_AUTHENTICATION_SUBJECTNAMECLAIM` | +| **App config key** | `Monitoring/Authentication.SubjectNameClaim` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| string | `preferred_username` | + ## [TLS](/servicecontrol/security/configuration/tls.md) These settings configure HTTPS. Refer to the [hosting and security guide](/servicecontrol/security/hosting-guide.md) or [TLS configuration examples](/servicecontrol/security/configuration/tls.md#configuration-examples) for additional information. diff --git a/servicecontrol/security/configuration/authentication.md b/servicecontrol/security/configuration/authentication.md index e7cd36abce6..88da868abdb 100644 --- a/servicecontrol/security/configuration/authentication.md +++ b/servicecontrol/security/configuration/authentication.md @@ -5,6 +5,7 @@ reviewed: 2026-05-27 component: ServiceControl related: - servicecontrol/security/hosting-guide +- servicecontrol/security/configuration/authorization - servicepulse/security/configuration/authentication --- @@ -13,6 +14,8 @@ ServiceControl instances can be configured to require [JWT](https://en.wikipedia > [!NOTE] > Authentication is disabled by default. To enable it, follow the configuration instructions for each instance type below. +Authentication verifies the identity of the caller. To additionally restrict what authenticated users are allowed to do, see [role-based access control](authorization.md). + ## Configuration ServiceControl instances can be configured via environment variables or App.config. Each instance type uses a different prefix. See the [Hosting Guide](../hosting-guide.md) for example usage of these configuration settings in conjunction with [Forward Header](forward-headers.md) and [TLS](tls.md) configuration settings in a scenario based format. diff --git a/servicecontrol/security/configuration/authorization.md b/servicecontrol/security/configuration/authorization.md new file mode 100644 index 00000000000..dd85d87cfa7 --- /dev/null +++ b/servicecontrol/security/configuration/authorization.md @@ -0,0 +1,90 @@ +--- +title: ServiceControl Role-Based Access Control +summary: Restrict what authenticated users can do in ServiceControl and ServicePulse using roles +reviewed: 2026-07-01 +component: ServiceControl +related: +- servicecontrol/security/configuration/authentication +- servicepulse/security/configuration/authorization +--- + +Once [authentication](authentication.md) is enabled, ServiceControl can additionally enforce _authorization_: restricting what each authenticated user is allowed to do based on the roles assigned to them in the identity provider. This is known as role-based access control (RBAC). + +Authentication answers _who is calling_; authorization answers _what they are allowed to do_. Authorization requires authentication to be enabled first. + +> [!NOTE] +> Role-based authorization is disabled by default. When it is disabled — but authentication is enabled — every authenticated user is granted full access. Enable authorization to restrict actions per user. + +## How it works + +When authorization is enabled, ServiceControl reads the user's roles from their access token and, for each request, allows or denies the action based on those roles. [ServicePulse](/servicepulse/security/configuration/authorization.md) adapts its interface to match, hiding or disabling the actions a user is not permitted to perform. + +## Built-in roles + +Access is granted through three built-in roles. Assign one or more of these role names to users in the identity provider: + +| Role | Access | +|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `reader` | Read-only access to everything. | +| `admin` | Everything `reader` can do, plus managing the configuration and administration areas (licensing, notifications, retry redirects, throughput, and connections). | +| `writer` | Full access, including message actions such as retry, edit, archive, and restore. | + +The roles are cumulative: `writer` is the highest level and can do everything `admin` and `reader` can, and `admin` can do everything `reader` can. Role names are matched case-insensitively, and a user with none of these roles has no access to the affected areas. + +> [!NOTE] +> Only `reader`, `admin`, and `writer` grant access. Custom role names are not supported, so provider-side roles must be named to match. + +## How to enable role-based access control + +1. Upgrade to ServiceControl 6.18.0 or later and ServicePulse 2.9.0 or later. +2. Enable [authentication](authentication.md) if it is not already enabled. Authorization has no effect without it. +3. In the identity provider, create roles named `reader`, `admin`, and `writer`, and assign them to users. Ensure the roles are included in the access token — see [reading roles from the token](#reading-roles-from-the-token) for where different providers place them. +4. On **every** ServiceControl instance (Primary, Audit, and Monitoring), set the following configuration keys: + + + +5. Restart all ServiceControl instances. + +Each instance authorizes its own requests, so all instances must have authorization enabled. For the app config keys and environment variables of every instance type, see [Primary](/servicecontrol/servicecontrol-instances/configuration.md#authentication), [Audit](/servicecontrol/audit-instances/configuration.md#authentication), and [Monitoring](/servicecontrol/monitoring-instances/configuration.md#authentication) configuration. + +> [!WARNING] +> Enable authorization consistently across all instances. If one instance is left with `RoleBasedAuthorizationEnabled` set to `false` while the others have it enabled, that instance grants every authenticated user full access to its endpoints, and ServicePulse will show those actions as available. Apply the same setting to Primary, Audit, and Monitoring. + +## Reading roles from the token + +Identity providers place roles in different claims and shapes. Use the [`Authentication.RolesClaim`](/servicecontrol/servicecontrol-instances/configuration.md#authentication-servicecontrolauthentication-rolesclaim) setting to tell ServiceControl where to find them. Both a flat claim name (for example `roles`) and a dotted path into a nested JSON object claim (for example `realm_access.roles`) are supported. + +| Identity provider | Typical `RolesClaim` value | Notes | +|-----------------------------------------------|----------------------------|-----------------------------------------------------------------------------------| +| Keycloak (realm roles) | `realm_access.roles` | Roles are nested inside the `realm_access` object; a dotted path reaches them. | +| Keycloak (with a realm-role mapper) / generic | `roles` | A flat top-level array of role strings. | +| Microsoft Entra ID (app roles) | `roles` | Configure app roles named `reader`, `admin`, or `writer` and assign them to users. | +| AWS Cognito (groups) | `cognito:groups` | Name the Cognito groups `reader`, `admin`, or `writer`. | + +The value at the configured path may be a single string or an array of strings; both are accepted. + +## Authorization audit log + +Every authorization decision — both allowed and denied — is written to a dedicated audit log so access can be reviewed and retained for compliance. Entries are emitted under the log category `ServiceControl.Audit` and formatted as [Elastic Common Schema (ECS)](https://www.elastic.co/guide/en/ecs/current/index.html) JSON, so they can be ingested into Elastic/Kibana or most SIEM (Security Information and Event Management) systems without custom mapping. Allowed decisions are logged at `Information` level and denied decisions at `Warning` level. + +### Where the audit log is written + +ServiceControl routes the `ServiceControl.Audit` category to a dedicated destination automatically; no additional logging configuration is required. Each entry is a single ECS JSON object on its own line, kept separate from the operational log so the two streams do not mix. + +- **Running as a Windows service** (not in a container): entries are written to an `audit.json` file in the instance's log directory, alongside the console. The file rotates daily and when it exceeds 30 MB, retaining up to 14 archived files. +- **Running in a container**: entries are written to standard output only, for the container's log driver or log aggregator to collect; no `audit.json` file is produced. + +The audit trail is captured from `Information` upward independently of the operational log level, so reducing operational verbosity never drops audit entries, and audit entries never appear in the operational log. + +### Audit identity claims + +The audit log identifies the caller using two token claims, configurable per instance: + +- [`Authentication.SubjectIdClaim`](/servicecontrol/servicecontrol-instances/configuration.md#authentication-servicecontrolauthentication-subjectidclaim) — a stable identifier for the user (default `sub`). +- [`Authentication.SubjectNameClaim`](/servicecontrol/servicecontrol-instances/configuration.md#authentication-servicecontrolauthentication-subjectnameclaim) — a human-readable display name (default `preferred_username`). + +If either claim is missing from the token, the request is rejected. A missing claim usually means the identity provider is not configured to emit it; correct the provider or point these settings at claims the token does contain. + +## Disabling authorization + +To keep authentication (require a valid token) but grant every authenticated user full access, leave `Authentication.RoleBasedAuthorizationEnabled` set to `false` (the default). In this mode roles are not consulted. diff --git a/servicecontrol/security/index.md b/servicecontrol/security/index.md index 3ee7955fbd3..cf1d650b8aa 100644 --- a/servicecontrol/security/index.md +++ b/servicecontrol/security/index.md @@ -87,6 +87,12 @@ Open ServicePulse in a browser. You should be redirected to your identity provid If authentication fails, check the ServiceControl logs for token validation errors. See [authentication configuration](configuration/authentication.md#troubleshooting) for common error messages and solutions. +## Restricting what users can do + +From ServiceControl version 6.18.0 it is possible to use Roles to restrict what users are able to do within the Platform. + +Authentication verifies who a user is. To additionally restrict what each authenticated user is allowed to do — for example, granting some users read-only access while others can retry or edit messages — enable [role-based access control](configuration/authorization.md). Authorization is optional and disabled by default; when it is off, every authenticated user has full access. + ## Advanced deployment patterns For deployments that use a reverse proxy for TLS termination, or require end-to-end encryption between a proxy and ServiceControl, see the [hosting guide](hosting-guide.md). @@ -94,6 +100,7 @@ For deployments that use a reverse proxy for TLS termination, or require end-to- ## Reference - [Authentication configuration](configuration/authentication.md) +- [Role-based access control](configuration/authorization.md) - [TLS configuration](configuration/tls.md) - [CORS configuration](configuration/cors.md) - [Hosting guide](hosting-guide.md) diff --git a/servicecontrol/servicecontrol-instances/configuration.md b/servicecontrol/servicecontrol-instances/configuration.md index 91e6ca748f0..3e2b6b0458b 100644 --- a/servicecontrol/servicecontrol-instances/configuration.md +++ b/servicecontrol/servicecontrol-instances/configuration.md @@ -377,6 +377,70 @@ The API scopes for ServicePulse to request when authenticating. This is a JSON a | --- | --- | | string (JSON array) | None | +### ServiceControl/Authentication.RoleBasedAuthorizationEnabled + +_Added in version 6.18.0_ + +Enables [role-based access control](/servicecontrol/security/configuration/authorization.md). When `false`, every authenticated user is granted every permission. Has no effect unless `Authentication.Enabled` is `true`. + +| Context | Name | +| --- | --- | +| **Environment variable** | `SERVICECONTROL_AUTHENTICATION_ROLEBASEDAUTHORIZATIONENABLED` | +| **App config key** | `ServiceControl/Authentication.RoleBasedAuthorizationEnabled` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| bool | `false` | + +### ServiceControl/Authentication.RolesClaim + +_Added in version 6.18.0_ + +The token claim from which user roles are read. Supports a flat claim name (for example `roles`) or a dotted path into a nested JSON object claim (for example `realm_access.roles`). See [reading roles from the token](/servicecontrol/security/configuration/authorization.md#reading-roles-from-the-token). + +| Context | Name | +| --- | --- | +| **Environment variable** | `SERVICECONTROL_AUTHENTICATION_ROLESCLAIM` | +| **App config key** | `ServiceControl/Authentication.RolesClaim` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| string | `roles` | + +### ServiceControl/Authentication.SubjectIdClaim + +_Added in version 6.18.0_ + +The token claim used as the stable user identifier in the [authorization audit log](/servicecontrol/security/configuration/authorization.md#authorization-audit-log). Requests are rejected if this claim is missing from the token. + +| Context | Name | +| --- | --- | +| **Environment variable** | `SERVICECONTROL_AUTHENTICATION_SUBJECTIDCLAIM` | +| **App config key** | `ServiceControl/Authentication.SubjectIdClaim` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| string | `sub` | + +### ServiceControl/Authentication.SubjectNameClaim + +_Added in version 6.18.0_ + +The token claim used as the human-readable display name in the [authorization audit log](/servicecontrol/security/configuration/authorization.md#authorization-audit-log). Requests are rejected if this claim is missing from the token. + +| Context | Name | +| --- | --- | +| **Environment variable** | `SERVICECONTROL_AUTHENTICATION_SUBJECTNAMECLAIM` | +| **App config key** | `ServiceControl/Authentication.SubjectNameClaim` | +| **SCMU field** | N/A | + +| Type | Default value | +| --- | --- | +| string | `preferred_username` | + ## [TLS](/servicecontrol/security/configuration/tls.md) These settings configure HTTPS. Refer to the [hosting and security guide](/servicecontrol/security/hosting-guide.md) or [TLS configuration examples](/servicecontrol/security/configuration/tls.md#configuration-examples) for additional information. diff --git a/servicepulse/security/configuration/authentication.md b/servicepulse/security/configuration/authentication.md index 04e6c40f8f1..620520143f1 100644 --- a/servicepulse/security/configuration/authentication.md +++ b/servicepulse/security/configuration/authentication.md @@ -5,6 +5,7 @@ reviewed: 2026-01-14 component: ServicePulse related: - servicepulse/security/hosting-guide +- servicepulse/security/configuration/authorization - servicecontrol/security/configuration/authentication - servicecontrol/security/entra-id-authentication --- diff --git a/servicepulse/security/configuration/authorization.md b/servicepulse/security/configuration/authorization.md new file mode 100644 index 00000000000..e8c74b5f96e --- /dev/null +++ b/servicepulse/security/configuration/authorization.md @@ -0,0 +1,37 @@ +--- +title: ServicePulse Role-Based Access Control +summary: How ServicePulse adapts its interface to the permissions granted to the signed-in user +reviewed: 2026-07-01 +component: ServicePulse +related: +- servicepulse/security/configuration/authentication +- servicecontrol/security/configuration/authorization +--- + +When [role-based access control](/servicecontrol/security/configuration/authorization.md) is enabled in ServiceControl, ServicePulse tailors its interface to the permissions of the signed-in user. Tabs, pages, and action buttons that the user is not permitted to use are hidden or disabled, so users see only the actions they can actually perform. + +> [!IMPORTANT] +> Authorization is configured entirely in ServiceControl. ServicePulse has no authorization configuration of its own; it reads the permitted actions from ServiceControl. See the [ServiceControl authorization guide](/servicecontrol/security/configuration/authorization.md). + +## How it works + +When a user signs in, ServicePulse adapts its interface to the user's [role](/servicecontrol/security/configuration/authorization.md#built-in-roles): + +- Navigation tabs and pages the user cannot access are hidden. +- Action buttons (for example _Retry_, _Edit_, _Delete_, _Restore_) the user cannot use are shown as disabled, with a tooltip explaining why, rather than failing after a click. + +ServiceControl enforces access on every request regardless of what ServicePulse displays, so hiding and disabling elements is a usability aid, not a security boundary. A user cannot bypass a restriction by calling the API directly. + +## Reviewing your permissions + +ServicePulse includes a **Your permissions** page under **Configuration** that lists each area of the product and shows, for the signed-in user, which capabilities are allowed and which are not. Use it to confirm that a user's roles map to the expected access, or to diagnose why an action is unavailable. + +## Troubleshooting + +### An action is unexpectedly disabled + +The signed-in user's roles do not grant the required permission. Check the **Your permissions** page to see which capabilities are allowed, and verify the user's role assignments in the identity provider match the [built-in role names](/servicecontrol/security/configuration/authorization.md#built-in-roles). + +### All actions are visible even though authorization is enabled + +ServicePulse could not determine the user's permissions and is showing everything rather than blocking access. Confirm that ServiceControl is reachable and that `Authentication.RoleBasedAuthorizationEnabled` is `true` on each instance. ServiceControl still rejects any action the user is not permitted to perform. diff --git a/servicepulse/security/index.md b/servicepulse/security/index.md index 9dbe1f19397..b2edfe48e47 100644 --- a/servicepulse/security/index.md +++ b/servicepulse/security/index.md @@ -13,6 +13,8 @@ ServicePulse authentication is configured in ServiceControl, not in ServicePulse To set up authentication, follow the [ServiceControl security guide](/servicecontrol/security). +When [role-based access control](configuration/authorization.md) is enabled in ServiceControl, ServicePulse hides or disables the tabs, pages, and buttons that the signed-in user is not permitted to use. + ## Enable HTTPS on ServicePulse ServicePulse should be served over HTTPS to protect user sessions and tokens in transit. Configure a TLS certificate so ServicePulse serves HTTPS directly. @@ -25,6 +27,8 @@ For deployments that use a reverse proxy for TLS termination, or require end-to- ## Reference +- [Authentication configuration](configuration/authentication.md) +- [Role-based access control](configuration/authorization.md) - [TLS configuration](configuration/tls.md) - [Forward headers for reverse proxy](configuration/forward-headers.md) - [Hosting guide](hosting-guide.md)