diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc index 7312f19fce..65fa4a475f 100644 --- a/modules/ROOT/nav.adoc +++ b/modules/ROOT/nav.adoc @@ -173,6 +173,7 @@ *** xref:manage:security/authentication.adoc[Authentication] *** xref:manage:security/authorization/index.adoc[Authorization] **** xref:manage:security/authorization/rbac.adoc[Role-Based Access Control (RBAC)] +**** xref:manage:security/authorization/gbac.adoc[Group-Based Access Control (GBAC)] **** xref:manage:security/authorization/acl.adoc[Access Control Lists (ACLs)] *** xref:manage:security/fips-compliance.adoc[FIPS Compliance] *** xref:manage:security/encryption.adoc[] diff --git a/modules/get-started/pages/release-notes/redpanda.adoc b/modules/get-started/pages/release-notes/redpanda.adoc index ce23599874..7c965a46ac 100644 --- a/modules/get-started/pages/release-notes/redpanda.adoc +++ b/modules/get-started/pages/release-notes/redpanda.adoc @@ -7,6 +7,17 @@ This topic includes new content added in version {page-component-version}. For a * xref:redpanda-cloud:get-started:whats-new-cloud.adoc[] * xref:redpanda-cloud:get-started:cloud-overview.adoc#redpanda-cloud-vs-self-managed-feature-compatibility[Redpanda Cloud vs Self-Managed feature compatibility] +== Group-based access control (GBAC) + +Redpanda {page-component-version} introduces xref:manage:security/authorization/gbac.adoc[group-based access control (GBAC)], which extends OIDC authentication to support group-based permissions. In addition to assigning roles or ACLs to individual users, you can assign them to OIDC groups. Users inherit permissions from all groups reported by their identity provider (IdP) in the OIDC token claims. + +GBAC supports two authorization patterns: + +* Assign a group as a member of an RBAC role so that all users in the group inherit the role's ACLs. +* Create ACLs directly with a `Group:` principal. + +Group membership is managed entirely by your IdP. Redpanda reads group information from the OIDC token at authentication time and works across the Kafka API, Schema Registry, and HTTP Proxy. + == FIPS 140-3 validation and FIPS Docker image Redpanda's cryptographic module has been upgraded from FIPS 140-2 to https://csrc.nist.gov/pubs/fips/140-3/final[FIPS 140-3^] validation. Additionally, Redpanda now provides a FIPS-specific Docker image (`docker.redpanda.com/redpandadata/redpanda:-fips`) for `amd64` and `arm64` architectures, with the required OpenSSL FIPS module pre-configured. @@ -34,3 +45,10 @@ xref:develop:produce-data/leader-pinning.adoc[Leader Pinning] now supports the ` Redpanda now supports throughput quotas based on authenticated user principals. Unlike client-based quotas (which rely on self-declared `client-id` values), user-based quotas enforce limits using verified identities from SASL, mTLS, or OIDC authentication. You can set quotas for individual users, default users, or fine-grained user/client combinations. See xref:manage:cluster-maintenance/about-throughput-quotas.adoc[] for conceptual details, and xref:manage:cluster-maintenance/manage-throughput.adoc#set-user-based-quotas[Set user-based quotas] to get started. + +== New configuration properties + +**Authentication:** + +* xref:reference:properties/cluster-properties.adoc#nested_group_behavior[`nested_group_behavior`]: Control how Redpanda handles nested groups extracted from authentication tokens +* xref:reference:properties/cluster-properties.adoc#oidc_group_claim_path[`oidc_group_claim_path`]: JSON path to extract groups from the JWT payload diff --git a/modules/manage/pages/audit-logging/audit-log-samples.adoc b/modules/manage/pages/audit-logging/audit-log-samples.adoc index 7ba297e6b8..6681c21047 100644 --- a/modules/manage/pages/audit-logging/audit-log-samples.adoc +++ b/modules/manage/pages/audit-logging/audit-log-samples.adoc @@ -3,6 +3,9 @@ :page-categories: Management, Security // tag::single-source[] +ifdef::env-cloud[:gbac-doc: security:authorization/gbac.adoc] +ifndef::env-cloud[:gbac-doc: manage:security/authorization/gbac.adoc] + ifndef::env-cloud[] [NOTE] ==== @@ -80,6 +83,59 @@ This scenario shows the message resulting from an admin using rpk with successfu ---- ==== +.Authentication successful (OIDC with group claims) +[%collapsible] +==== +This scenario shows a successful OIDC authentication event that includes the user's IdP group memberships in the `user.groups` field. Group memberships are extracted from the OIDC token and included in all authentication events for OIDC users. +[,json] +---- +{ + "category_uid": 3, + "class_uid": 3002, + "metadata": { + "product": { + "name": "Redpanda", + "uid": "0", + "vendor_name": "Redpanda Data, Inc.", + "version": "v26.1.1" + }, + "version": "1.0.0" + }, + "severity_id": 1, + "time": 1700533469078, + "type_uid": 300201, + "activity_id": 1, + "auth_protocol": "SASL-OAUTHBEARER", + "auth_protocol_id": 99, + "dst_endpoint": { + "ip": "127.0.0.1", + "port": 9092, + "svc_name": "kafka rpc protocol" + }, + "is_cleartext": false, + "is_mfa": false, + "service": { + "name": "kafka rpc protocol" + }, + "src_endpoint": { + "ip": "10.0.1.50", + "name": "kafka-client", + "port": 48210 + }, + "status_id": 1, + // IdP group memberships extracted from the OIDC token + "user": { + "name": "alice@example.com", + "type_id": 1, + "groups": [ + {"type": "idp_group", "name": "engineering"}, + {"type": "idp_group", "name": "analytics"} + ] + } +} +---- +==== + .Authentication failed [%collapsible] ==== @@ -237,6 +293,93 @@ This example illustrates an ACL update that also requires a superuser authentica ---- ==== +.Authorization matched on a group ACL +[%collapsible] +==== +This example shows an API Activity (6003) where the authorization decision matched an ALLOW ACL on a `Group:` principal. The `actor.user.groups` field includes the matched group with type `idp_group`, and the `authorization_metadata` shows the group ACL that granted access. See xref:{gbac-doc}[Group-Based Access Control]. + +[,json] +---- +{ + "category_uid": 6, + "class_uid": 6003, + "metadata": { + "product": { + "name": "Redpanda", + "uid": "0", + "vendor_name": "Redpanda Data, Inc.", + "version": "v26.1.0" + }, + "version": "1.0.0" + }, + "severity_id": 1, + "time": 1774544504327, + "type_uid": 600303, + "activity_id": 3, + "actor": { + "authorizations": [ + { + "decision": "authorized", + "policy": { + "desc": "acl: {principal type {group} name {/sales} host {{any_host}} op all perm allow}, resource: type {topic} name {sales-topic} pattern {literal}", + "name": "aclAuthorization" + } + } + ], + // The matched group appears in the user's groups field + "user": { + "name": "alice", + "type_id": 1, + "groups": [ + { + "type": "idp_group", + "name": "/sales" + } + ] + } + }, + "api": { + "operation": "produce", + "service": { + "name": "kafka rpc protocol" + } + }, + "dst_endpoint": { + "ip": "127.0.1.1", + "port": 9092, + "svc_name": "kafka rpc protocol" + }, + "resources": [ + { + "name": "sales-topic", + "type": "topic" + } + ], + "src_endpoint": { + "ip": "127.0.0.1", + "name": "rdkafka", + "port": 42728 + }, + "status_id": 1, + "unmapped": { + "authorization_metadata": { + "acl_authorization": { + "host": "{{any_host}}", + "op": "all", + "permission_type": "allow", + "principal": "type {group} name {/sales}" + }, + "resource": { + "name": "sales-topic", + "pattern": "literal", + "type": "topic" + } + } + } +} +---- +==== + .Metadata request (with counts) [%collapsible] ==== diff --git a/modules/manage/pages/security/authorization/acl.adoc b/modules/manage/pages/security/authorization/acl.adoc index e371c402a3..35fec7a6f3 100644 --- a/modules/manage/pages/security/authorization/acl.adoc +++ b/modules/manage/pages/security/authorization/acl.adoc @@ -62,8 +62,8 @@ Understanding these terms helps you configure least-privilege access. | Term | Definition | Example | Principal -| The entity (user or role) requesting access -| `User:analytics-user`, `RedpandaRole:data-engineers` +| The entity (user, role, or group) requesting access +| `User:analytics-user`, `RedpandaRole:data-engineers`, `Group:engineering` | Resource | The Redpanda component being accessed (cluster, topic, consumer group, transactional ID, Schema Registry glossterm:subject[], and Schema Registry operation) @@ -91,7 +91,13 @@ ACL commands work on a multiplicative basis. If you specify two principals and t [[principals]] === Principals -All ACLs require a principal. A principal is composed of two parts: the type, and the name. Redpanda supports the types "User" and "RedpandaRole". When you create user "bar", Redpanda expects you to add ACLs for "User:bar". +All ACLs require a principal. A principal is composed of two parts: the type, and the name. Redpanda supports the types "User", "RedpandaRole", and "Group". When you create user "bar", Redpanda expects you to add ACLs for "User:bar". To grant permissions to an OIDC group, use the `Group:` prefix (for example, `Group:engineering`). +ifndef::env-cloud[] +See xref:manage:security/authorization/gbac.adoc[]. +endif::[] +ifdef::env-cloud[] +See xref:security:authorization/gbac.adoc[]. +endif::[] The `--allow-principal` and `--deny-principal` flags add this prefix for you, if necessary. diff --git a/modules/manage/pages/security/authorization/gbac.adoc b/modules/manage/pages/security/authorization/gbac.adoc new file mode 100644 index 0000000000..8bc8f876b8 --- /dev/null +++ b/modules/manage/pages/security/authorization/gbac.adoc @@ -0,0 +1,17 @@ += Configure Group-Based Access Control +:description: Manage Redpanda permissions at scale using your identity provider's groups. Define access once per group and let your IdP control membership, with no per-user configuration in Redpanda. +:page-topic-type: how-to +:page-categories: Management, Security +:personas: security_engineer, platform_engineer +:learning-objective-1: Configure the cluster properties that enable GBAC +:learning-objective-2: Assign an OIDC group to an RBAC role +:learning-objective-3: Create a group-based ACL using the Group: principal prefix + +ifndef::env-cloud[] +[NOTE] +==== +include::shared:partial$enterprise-license.adoc[] +==== +endif::[] + +include::manage:partial$gbac-dp.adoc[] diff --git a/modules/manage/pages/security/authorization/index.adoc b/modules/manage/pages/security/authorization/index.adoc index 16ff7a1f26..d426846189 100644 --- a/modules/manage/pages/security/authorization/index.adoc +++ b/modules/manage/pages/security/authorization/index.adoc @@ -1,8 +1,8 @@ = Configure Authorization -:description: Redpanda provides two mechanisms for controlling user permissions. +:description: Redpanda provides mechanisms for controlling user permissions, including ACLs, role-based access control, and group-based access control. :page-aliases: security:authorization/index.adoc, manage:security/authorization.adoc :page-categories: Management, Security :page-layout: index -Authorization works in tandem with xref:security/authentication.adoc[authentication]. Authentication grants permission to interact with Redpanda resources while authorization controls what a principal is permitted to do once authenticated. +Authorization works in tandem with xref:security/authentication.adoc[authentication]. Authentication verifies who a principal is. Authorization controls what that principal can do once authenticated. diff --git a/modules/manage/partials/audit-logging.adoc b/modules/manage/partials/audit-logging.adoc index ad1fe36a02..aa2cb57947 100644 --- a/modules/manage/partials/audit-logging.adoc +++ b/modules/manage/partials/audit-logging.adoc @@ -159,10 +159,11 @@ NOTE: The Included column captures whether the event itself is included (for exa |=== |Data Logging Level |Audit Event |Included? |Details -.11+|System Level +.12+|System Level |Date and time stamp for each entry |Yes |`time` field on each event |Successful and failed access attempts |Yes |The `status_id` field shows success/failure for all access attempts for which auditing is enabled |User ID |Yes |`user.name` +|User group memberships |Yes |`user.groups` field with type `idp_group`. Included in authentication events for OIDC users and in authorization events when a group ACL matches. See xref:manage:security/authorization/gbac.adoc[]. |User connect and disconnect time |No |Connect and disconnect time may be inferred from the presence or absence of activity. |Password change |Yes |For SCRAM users managed through Redpanda core, the Admin API call associated with the password change is logged. Note that this does not cover users synced from external IdPs, such as through OIDC. |Changes of security settings |Yes |For example, ACL creation is logged (kafka `create_acls`), and cluster configuration changes are logged (Admin API events) diff --git a/modules/manage/partials/authentication.adoc b/modules/manage/partials/authentication.adoc index ef2ae49d0e..aac5fdbe74 100644 --- a/modules/manage/partials/authentication.adoc +++ b/modules/manage/partials/authentication.adoc @@ -867,6 +867,8 @@ but can instead rely on the trusted authentication capabilities of established I Redpanda's implementation of OIDC provides SASL/OAUTHBEARER support for the Kafka API, and supports standard OIDC authentication across all other HTTP APIs, including Schema Registry, HTTP Proxy, and the Admin API. +TIP: With OIDC enabled, you can also use xref:manage:security/authorization/gbac.adoc[group-based access control (GBAC)] to assign Redpanda permissions to OIDC groups instead of individual users. To use GBAC, configure your IdP to include group claims in the access token (for example, a `groups` claim). See your IdP's documentation for how to add group claims to tokens. + include::manage:partial$security/oidc/limitations.adoc[leveloffset=+3] ===== OIDC credentials flow and access token validation diff --git a/modules/manage/partials/gbac-assign-group-role.adoc b/modules/manage/partials/gbac-assign-group-role.adoc new file mode 100644 index 0000000000..fb94b541be --- /dev/null +++ b/modules/manage/partials/gbac-assign-group-role.adoc @@ -0,0 +1,23 @@ +To assign a group to a role in {ui}: + +. From *Security* on the left navigation menu, select the *Roles* tab. + +. Select the role you want to assign the group to. + +. Click *Edit*. + +. In the *Principals* section, enter the group name using the `Group:` format. For example, `Group:engineering`. + +. Click *Update*. + +To remove a group from a role: + +. From *Security* on the left navigation menu, select the *Roles* tab. + +. Select the role that has the group assignment you want to remove. + +. Click *Edit*. + +. In the *Principals* section, remove the `Group:` entry. + +. Click *Update*. diff --git a/modules/manage/partials/gbac-create-group-acl.adoc b/modules/manage/partials/gbac-create-group-acl.adoc new file mode 100644 index 0000000000..6d80c65ad2 --- /dev/null +++ b/modules/manage/partials/gbac-create-group-acl.adoc @@ -0,0 +1,13 @@ +In {ui}, group-based ACLs are managed through roles. To create an ACL for an OIDC group: + +. From *Security* on the left navigation menu, select the *Roles* tab. + +. Click *Create role* to open the role creation form, or select an existing role and click *Edit*. + +. In the *Principals* field, enter the group principal using the `Group:` format. For example, `Group:engineering`. + +. Define the permissions (ACLs) you want to grant to users in the group. You can configure ACLs for clusters, topics, consumer groups, transactional IDs, Schema Registry subjects, and Schema Registry operations. + +. Click *Create* (or *Update* if editing an existing role). + +NOTE: {ui} assigns ACLs through roles. To grant permissions to a group, create a role for that group, add the group as a principal, and define the ACLs on the role. To create ACLs with a `Group:` principal directly (without creating a role), use `rpk`. diff --git a/modules/manage/partials/gbac-dp.adoc b/modules/manage/partials/gbac-dp.adoc new file mode 100644 index 0000000000..cfa7d0875d --- /dev/null +++ b/modules/manage/partials/gbac-dp.adoc @@ -0,0 +1,554 @@ +// tag::single-source[] +ifdef::env-cloud[:oidc-doc: security:cloud-authentication.adoc#single-sign-on] +ifndef::env-cloud[:oidc-doc: manage:security/authentication.adoc#oidc] +ifdef::env-cloud[:acl-doc: security:authorization/acl.adoc] +ifndef::env-cloud[:acl-doc: manage:security/authorization/acl.adoc] +ifdef::env-cloud[:rbac-doc: security:authorization/rbac/index.adoc] +ifndef::env-cloud[:rbac-doc: manage:security/authorization/rbac.adoc] + +Group-based access control (GBAC) lets you manage Redpanda permissions at scale using the groups that already exist in your identity provider (IdP). Instead of creating and maintaining per-user permissions in Redpanda, you define access once for a group and your IdP controls who belongs to it. When users join or leave a team, their Redpanda access updates automatically at next login with no changes needed in Redpanda. + +GBAC extends xref:{oidc-doc}[OIDC authentication] and supports two ways to grant permissions to groups: create xref:{acl-doc}[ACLs] with `Group:` principals, or assign groups as members of xref:{rbac-doc}[RBAC] roles. Both approaches can be used independently or together. + +After reading this page, you will be able to: + +* [ ] {learning-objective-1} +* [ ] {learning-objective-2} +* [ ] {learning-objective-3} + +== Prerequisites + +To use GBAC, you need: + +ifndef::env-cloud[] +* An xref:get-started:licensing/overview.adoc[Enterprise Edition] license applied to your cluster. +* Superuser access to configure cluster properties and manage ACLs. +endif::[] +* xref:{oidc-doc}[OIDC authentication] configured and enabled on your cluster. +* Your IdP configured to include group claims in the OIDC access token (for example, a `groups` claim). + +== How GBAC works + +When a user authenticates with OIDC, Redpanda reads a configurable claim from the JWT access token (for example, `$.groups`) and extracts the list of groups the user belongs to. Redpanda then matches those group names against `Group:` principals in its ACLs and role assignments. + +Group membership is managed entirely by your IdP. Redpanda never stores or manages group membership directly. It reads group information from the OIDC token at authentication time. Changes you make in the IdP (adding or removing group memberships) take effect at the user's next authentication, when a new token is issued. + +GBAC works across the following Redpanda APIs: + +* Kafka API +* Schema Registry +* HTTP Proxy + +=== Authorization patterns + +GBAC supports two usage patterns: + +* Group as an ACL principal: Create an ACL with a `Group:` principal. Users in that group receive that permission directly. +* Group assigned to a role: Assign a group as a member of a role-based access control (RBAC) role. All users in the group inherit the role's ACLs. + +Both patterns can be used together. When a user belongs to multiple groups, they inherit the combined permissions of all groups. + +Redpanda evaluates all authorization sources (user ACLs, role ACLs, group ACLs, and group-to-role ACLs) in a single unified flow. Deny rules are checked first across all sources. If any source produces a deny, Redpanda rejects the request regardless of allows from other sources. If no deny is found, Redpanda checks for an allow across all sources. If no allow is found, Redpanda denies the request by default. + +.Authorization evaluation flow +[mermaid,width=100%] +.... +flowchart LR + A[Request] --> B{"Check all sources\nfor deny"} + + B -- "Deny found" --> DENY["❌ Deny"] + B -- "No deny found" --> C{"Check all sources\nfor allow"} + + C -- "Allow found" --> ALLOW["✅ Allow"] + C -- "No allow found" --> DEFAULT["❌ Default deny"] + + style DENY fill:#f44,color:#fff + style ALLOW fill:#4a4,color:#fff + style DEFAULT fill:#f44,color:#fff + + subgraph sources [" "] + direction LR + S1["User ACLs"] + S2["Role ACLs\n(RBAC)"] + S3["Group ACLs"] + S4["Group→Role\nACLs"] + end +.... + +== Supported identity providers + +GBAC works with any OIDC-compliant identity provider. These providers are commonly used with Redpanda: + +* https://auth0.com/docs/secure/tokens/json-web-tokens/create-custom-claims[Auth0^]: Configure group claims in Auth0 Actions or Rules. +* https://developer.okta.com/docs/concepts/universal-directory/[Okta^]: Assign groups to applications and include them in token claims. +* https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-fed-group-claims[Microsoft Entra ID (Azure AD)^]: Configure group claims in the application manifest. + +For IdP-specific configuration steps, see your provider's documentation. + +== Limitations + +* Azure AD group limit: Users with more than 200 group memberships in Azure AD receive a URL reference in their token instead of a list of group names. Redpanda does not follow that URL and cannot resolve groups in this case. ++ +Mitigation: Filter token claims to include only the groups relevant to Redpanda. + +* Nested groups: Redpanda does not recursively resolve nested group hierarchies. If group A contains group B, only the direct memberships reported in the token are used. Use xref:reference:properties/cluster-properties.adoc#nested_group_behavior[`nested_group_behavior: suffix`] to extract the last path segment from hierarchical group names when needed. + +* No wildcard ACLs for groups: ACL matching for `Group:` principals uses literal string comparison only. Wildcard patterns are not supported. + +ifdef::env-cloud[] +== Register groups in Redpanda Cloud + +To assign an IdP group to a role or ACL, you must first register the group: + +[tabs] +==== +Cloud UI:: ++ +-- +. In the left navigation menu, select *Organization IAM*, then select the *Groups* tab. +. Click *Create group*. +. Enter a *Name* that matches the group in your IdP exactly (for example, `engineering`). +. Optionally, enter a *Description*, and configure a *Role binding* to assign the group to a role with a specific scope and resource. +. Click *Create*. +-- + +Control Plane API:: ++ +-- +Make a link:/api/doc/cloud-controlplane/operation/operation-groupservice_creategroup[`POST /v1/groups`] request to the xref:redpanda-cloud:manage:api/cloud-byoc-controlplane-api.adoc[Control Plane API]: + +[,bash] +---- +curl -X POST 'https://api.redpanda.com/v1/groups' \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer ' \ + -d '{ + "group": { + "name": "", + "description": "" + } + }' +---- + +Replace `` with the name that matches the group in your IdP (for example, `engineering`). The name must match exactly for GBAC to map the group correctly. +-- +==== +endif::[] + +== Create group-based ACLs + +You can grant permissions directly to a group by creating an xref:{acl-doc}[ACL] with a `Group:` principal. This works the same as creating an ACL for a user, but uses the `Group:` prefix instead of `User:`. + +[tabs] +==== +rpk:: ++ +-- +To grant cluster-level access to the `engineering` group: + +[,bash] +---- +rpk security acl create --allow-principal Group:engineering --operation describe --cluster +---- + +To grant topic-level access: + +[,bash] +---- +rpk security acl create \ + --allow-principal Group:engineering \ + --operation read,describe \ + --topic 'analytics-' \ + --resource-pattern-type prefixed +---- + +-- +{ui}:: ++ +-- +include::manage:partial$gbac-create-group-acl.adoc[] +-- +ifdef::env-cloud[] +Data Plane API:: ++ +-- +Make a link:/api/doc/cloud-dataplane/operation/operation-aclservice_createacl[`POST /v1/acls`] request with a `Group:` principal. For example, to grant the `engineering` group read access to a topic: + +[,bash] +---- +curl -X POST "${DATAPLANE_API_URL}/v1/acls" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "resource_type": "RESOURCE_TYPE_TOPIC", + "resource_name": "analytics-events", + "resource_pattern_type": "RESOURCE_PATTERN_TYPE_LITERAL", + "principal": "Group:engineering", + "host": "*", + "operation": "OPERATION_READ", + "permission_type": "PERMISSION_TYPE_ALLOW" + }' +---- +-- +endif::[] +==== + +== Assign groups to roles + +To manage permissions at scale, assign a group to an xref:{rbac-doc}[RBAC] role. All users in the group inherit the role's ACLs automatically. + +[tabs] +==== +rpk:: ++ +-- +To assign a group to a role: + +[,bash] +---- +rpk security role assign --principal Group: +---- + +For example, to assign the `engineering` group to the `DataEngineers` role: + +[,bash] +---- +rpk security role assign DataEngineers --principal Group:engineering +---- + +To remove a group from a role: + +[,bash] +---- +rpk security role unassign --principal Group: +---- + +For example: + +[,bash] +---- +rpk security role unassign DataEngineers --principal Group:engineering +---- +-- +{ui}:: ++ +-- +include::manage:partial$gbac-assign-group-role.adoc[] +-- +ifdef::env-cloud[] +Data Plane API:: ++ +-- +First, retrieve your cluster's Data Plane API URL: + +[,bash] +---- +export DATAPLANE_API_URL=$(curl -s https://api.redpanda.com/v1/clusters/ \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer " | jq -r .cluster.dataplane_api) +---- + +Make a link:/api/doc/cloud-dataplane/operation/operation-securityservice_updaterolemembership[`PUT /v1/roles/\{role_name}`] request to assign a group to a role: + +[,bash] +---- +curl -X PUT "${DATAPLANE_API_URL}/v1/roles/DataEngineers" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "add": [{"principal": "Group:engineering"}] + }' +---- + +To remove a group from a role, use the `remove` field: + +[,bash] +---- +curl -X PUT "${DATAPLANE_API_URL}/v1/roles/DataEngineers" \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "remove": [{"principal": "Group:engineering"}] + }' +---- +-- +endif::[] +ifndef::env-cloud[] +Admin API:: ++ +-- +Use the Admin API link:/api/doc/admin/v2/group/endpoint-securityservice[`SecurityService`] operations to manage group-to-role assignments. Send all requests as `POST` with a JSON body. For guidance on using the Admin API (ConnectRPC), see xref:manage:use-admin-api.adoc[]. + +To assign a group to a role, make a link:/api/doc/admin/v2/operation/operation-redpanda-core-admin-v2-securityservice-addrolemembers[`POST AddRoleMembers`] request: + +[,bash] +---- +curl -u : \ + --request POST 'http://localhost:9644/redpanda.core.admin.v2.SecurityService/AddRoleMembers' \ + --header 'Content-Type: application/json' \ + --data '{ + "roleName": "DataEngineers", + "members": [{"group": {"name": "engineering"}}] + }' +---- + +To remove a group from a role, make a link:/api/doc/admin/v2/operation/operation-redpanda-core-admin-v2-securityservice-removerolemembers[`POST RemoveRoleMembers`] request: + +[,bash] +---- +curl -u : \ + --request POST 'http://localhost:9644/redpanda.core.admin.v2.SecurityService/RemoveRoleMembers' \ + --header 'Content-Type: application/json' \ + --data '{ + "roleName": "DataEngineers", + "members": [{"group": {"name": "engineering"}}] + }' +---- +-- +endif::[] +==== + +== View groups and roles + +Use the following commands to inspect group assignments and role memberships. + +=== List groups assigned to a role + +[tabs] +==== +rpk:: ++ +-- +To see which groups are assigned to a role, use `--print-members`. Groups are listed alongside other principals such as `User:` and appear as `Group:` entries: + +[,bash] +---- +rpk security role describe --print-members +---- + +For example: + +[,bash] +---- +rpk security role describe DataEngineers --print-members +---- + +To list all roles assigned to a specific group: + +[,bash] +---- +rpk security role list --principal Group: +---- + +For example: + +[,bash] +---- +rpk security role list --principal Group:engineering +---- +-- +{ui}:: ++ +-- +To view groups assigned to a role in {ui}: + +. From *Security* on the left navigation menu, select the *Roles* tab. + +. Select the role you want to inspect. + +. The role details page lists all principals, including any `Group:` entries. +-- +ifdef::env-cloud[] +Data Plane API:: ++ +-- +To list all members of a role (including groups), make a link:/api/doc/cloud-dataplane/operation/operation-securityservice_listrolemembers[`GET /v1/roles/\{role_name}/members`] request: + +[,bash] +---- +curl -X GET "${DATAPLANE_API_URL}/v1/roles/DataEngineers/members" \ + -H "Authorization: Bearer " +---- + +The response includes a `members` array. Group members appear with the `Group:` prefix in the `principal` field. + +To list all roles assigned to a specific group, make a link:/api/doc/cloud-dataplane/operation/operation-securityservice_listroles[`GET /v1/roles`] request with a principal filter: + +[,bash] +---- +curl -X GET "${DATAPLANE_API_URL}/v1/roles?filter.principal=Group:engineering" \ + -H "Authorization: Bearer " +---- +-- +endif::[] +ifndef::env-cloud[] +Admin API:: ++ +-- +These operations use the link:/api/doc/admin/v2/group/endpoint-securityservice[Admin API v2] `SecurityService`. Send all requests as `POST` with a JSON body. + +To retrieve a role's details including all members (users and groups), make a link:/api/doc/admin/v2/operation/operation-redpanda-core-admin-v2-securityservice-getrole[`POST GetRole`] request: + +[,bash] +---- +curl -u : \ + --request POST 'http://localhost:9644/redpanda.core.admin.v2.SecurityService/GetRole' \ + --header 'Content-Type: application/json' \ + --data '{"name": "DataEngineers"}' +---- + +The response includes a `members` array with both `user` and `group` entries. + +To list all roles, make a link:/api/doc/admin/v2/operation/operation-redpanda-core-admin-v2-securityservice-listroles[`POST ListRoles`] request: + +[,bash] +---- +curl -u : \ + --request POST 'http://localhost:9644/redpanda.core.admin.v2.SecurityService/ListRoles' \ + --header 'Content-Type: application/json' \ + --data '{}' +---- + +To verify how Redpanda resolves groups from an OIDC token, make a link:/api/doc/admin/v2/operation/operation-redpanda-core-admin-v2-securityservice-resolveoidcidentity[`POST ResolveOidcIdentity`] request. Pass the token in the `Authorization` header. The response includes the resolved `principal`, token expiry, and a `groups` field listing all groups extracted from the token: + +[,bash] +---- +curl \ + --request POST 'http://localhost:9644/redpanda.core.admin.v2.SecurityService/ResolveOidcIdentity' \ + --header 'Content-Type: application/json' \ + --header 'Authorization: Bearer ' \ + --data '{}' +---- +-- +endif::[] +==== + +== Customize token claim extraction + +Different identity providers store group information in different locations within the JWT token. + +ifdef::env-cloud[] +In Redpanda Cloud, group claim extraction is configured through your SSO connection settings. + +. In the Cloud UI, navigate to *Organization IAM > Single sign-on*, then select your IdP connection. +. Ensure the mapping mode is set to *use_map*. +. Configure *Attributes (JSON)* to map attribute names to claim paths, including `federated_groups` for group claims. ++ +A claim path is a https://goessner.net/articles/JsonPath/[JSON path^] expression that tells Redpanda where to find group information in the OIDC token. The appropriate claim path for each attribute may vary per IdP. ++ +For example, Okta exposes group claims in `${context.userinfo.groups}`. In this case, you must also include `groups` in *Userinfo scope*. +endif::[] + +ifndef::env-cloud[] +Two cluster properties control how Redpanda extracts group names: + +* xref:reference:properties/cluster-properties.adoc#oidc_group_claim_path[`oidc_group_claim_path`]: A https://goessner.net/articles/JsonPath/[JSON path^] expression that tells Redpanda where to find group information in the OIDC token. For example, Auth0 and Okta typically use a top-level `groups` claim (`$.groups`), while Keycloak nests roles inside `realm_access` (`$.realm_access.roles`). Default: `$.groups`. +* xref:reference:properties/cluster-properties.adoc#nested_group_behavior[`nested_group_behavior`]: Controls how Redpanda handles group names that use path-style notation (for example, `/departments/eng/platform`). Set to `none` to use the full path as-is, or `suffix` to extract only the last segment. Default: `none`. ++ +NOTE: When `nested_group_behavior` is set to `suffix`, groups that share a leaf name (for example, `/departments/eng/groupA` and `/departments/sales/groupA`) both resolve to `Group:groupA`. ACLs or role assignments for that principal apply to members of both groups. Design your group naming conventions to avoid unintended collisions. + +To update these properties, use xref:manage:cluster-maintenance/cluster-property-configuration.adoc[any configuration method] (`rpk cluster config set`, the Admin API, or Redpanda Console). Changes take effect immediately without a restart. +endif::[] + +=== Token structure examples + +The following examples show how Redpanda extracts group principals from different token formats. + +==== Flat group values (default) + +With `oidc_group_claim_path: "$.groups"`, Redpanda extracts principals `Group:engineering` and `Group:analytics` from the token. + +[,json] +---- +{"groups": ["engineering", "analytics"]} +---- + +==== Nested claim + +With `oidc_group_claim_path: "$.realm_access.roles"`, Redpanda extracts principals `Group:eng` and `Group:fin` from the token. + +[,json] +---- +{"realm_access": {"roles": ["eng", "fin"]}} +---- + +==== Path-style group names with no suffix extraction (default) + +With `nested_group_behavior: "none"` (the default), Redpanda maps the full path to principals `Group:/departments/eng/platform` and `Group:/departments/eng/infra`. + +[,json] +---- +{"groups": ["/departments/eng/platform", "/departments/eng/infra"]} +---- + +// Not supported in Cloud +ifndef::env-cloud[] +==== Path-style group names with suffix extraction + +When xref:reference:properties/cluster-properties.adoc#nested_group_behavior[`nested_group_behavior`] is set to `suffix`, Redpanda maps the last path segment to principals `Group:platform` and `Group:infra`. + +[,json] +---- +{"groups": ["/departments/eng/platform", "/departments/eng/infra"]} +---- +endif::[] + +==== CSV-formatted group claim + +Some identity providers return group claims as a single comma-separated string instead of an array. + +[,json] +---- +{"groups": "engineering,analytics,finance"} +---- + +Redpanda automatically splits comma-separated values and extracts principals `Group:engineering`, `Group:analytics`, and `Group:finance`. + +ifndef::env-cloud[] +== Troubleshoot GBAC + +If group-based permissions are not working as expected: + +* Decode the JWT access token from your IdP and verify that the expected group claims are present: ++ +[,bash] +---- +echo $ACCESS_TOKEN | cut -d. -f2 | base64 -d 2>/dev/null | jq . +---- ++ +Look for the claim that matches your xref:reference:properties/cluster-properties.adoc#oidc_group_claim_path[`oidc_group_claim_path`] configuration (default: `$.groups`). +* Use the `ResolveOidcIdentity` Admin API endpoint to verify which groups Redpanda extracts from a token. See <>. +* Verify that your cluster configuration matches the token structure: ++ +[,bash] +---- +rpk cluster config get oidc_group_claim_path +rpk cluster config get nested_group_behavior +---- +* Temporarily enable debug logging for the `security` logger to see all claims in the validated JWT: ++ +[,bash] +---- +rpk redpanda admin config log-level set security --level debug +---- ++ +This helps diagnose incorrect claim paths, missing groups, or token content issues. The debug level reverts automatically after the expiry period (default: 300 seconds). +endif::[] + +== Audit logging + +When xref:manage:audit-logging.adoc[audit logging] is enabled, Redpanda includes group information in the following event types: + +ifndef::env-cloud[] +* Authentication events: Events across Kafka API, HTTP Proxy, Schema Registry, and Admin API include the user's IdP group memberships in the `user.groups` field with type `idp_group`. +endif::[] +ifdef::env-cloud[] +* Authentication events: Events across Kafka API, HTTP Proxy, and Schema Registry include the user's IdP group memberships in the `user.groups` field with type `idp_group`. +endif::[] +* Authorization events: When an authorization decision matches a group ACL, the matched group appears in the `actor.user.groups` field with type `idp_group`. + +== Next steps + +* xref:manage:audit-logging.adoc[Set up audit logging] to monitor group-based access events. + +// end::single-source[] diff --git a/modules/reference/pages/rpk/rpk-security/rpk-security-role-assign.adoc b/modules/reference/pages/rpk/rpk-security/rpk-security-role-assign.adoc index 5670fc9dd7..41aaf549c2 100644 --- a/modules/reference/pages/rpk/rpk-security/rpk-security-role-assign.adoc +++ b/modules/reference/pages/rpk/rpk-security/rpk-security-role-assign.adoc @@ -7,18 +7,30 @@ The `--principal` flag accepts principals with the format `: