{
  "id": "migrate-rolespermissions",
  "title": "Migrate from REDB rolesPermissions",
  "url": "https://redis.io/docs/latest/operate/kubernetes/security/access-control/migrate-rolespermissions/",
  "summary": "Move database role assignments from the deprecated RedisEnterpriseDatabase.spec.rolesPermissions field to the RBAC CRD model.",
  "tags": [
    "docs",
    "operate",
    "kubernetes"
  ],
  "last_updated": "2026-07-24T10:52:10-07:00",
  "page_type": "content",
  "content_hash": "746e9a636943183a62efef07f2dfc8a569574b240ea6c3e41dcf7e0b99d77bf4",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "`RedisEnterpriseDatabase.spec.rolesPermissions` assigns Redis Software role and ACL names directly to a database. The field is deprecated, replaced by the RBAC CRDs (`RedisEnterpriseRole`, `RedisEnterpriseACL`, and bindings), which let you manage roles, ACLs, and assignments as Kubernetes resources.\n\nThis page covers moving an existing database from `rolesPermissions` to the CRD model, then disabling the deprecated field at the cluster level."
    },
    {
      "id": "before-you-start",
      "title": "Before you start",
      "role": "content",
      "text": "- Requires Redis Software for Kubernetes operator 8.2.0-12 or later.\n- Every user who currently holds access through `rolesPermissions` must exist as a `RedisEnterpriseUser` resource before you can bind a CRD role to them. If you created users through the Redis Software REST API or Cluster Manager UI, migrate them first. See [Manage users](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-users).\n- List which Redis Software users hold each role. The CRD inventory only captures the database side of the assignment; the user-to-role mapping lives in Redis Software. Pull it from the Cluster Manager UI or the [Redis Software users REST API](https://redis.io/docs/latest/operate/rs/references/rest-api/objects/user)."
    },
    {
      "id": "how-the-two-sources-interact",
      "title": "How the two sources interact",
      "role": "content",
      "text": "By default, the operator reconciles both sources of database role permissions:\n\n- The deprecated `RedisEnterpriseDatabase.spec.rolesPermissions` list on each REDB.\n- Permissions derived from `RedisEnterpriseRole` resources that scope to the REDB.\n\nThe operator merges and de-duplicates the two sets before sending them to Redis Software. `RedisEnterpriseDatabase.status.rolesPermissions` shows the merged result:\n\n- Entries from the deprecated field use Redis Software's internal role and ACL names.\n- Entries from CRDs reference `RedisEnterpriseRole` and `RedisEnterpriseACL` resources.\n\nYou can run both sources in parallel during migration. Once every database is completely migrated, disable the deprecated field cluster-wide (see [Disable the deprecated field](#disable-the-deprecated-field))."
    },
    {
      "id": "reference-existing-redis-software-objects",
      "title": "Reference existing Redis Software objects",
      "role": "related",
      "text": "You don't have to recreate every database, ACL, and role as a custom resource. When an object was created directly through the Redis Software REST API or Cluster Manager UI, a CRD reference can point at it by name using an internal kind, so you can bring it under CRD-managed bindings without redefining it:\n\n| Field | Internal kind | References |\n| --- | --- | --- |\n| `scopes[].kind` | `bdb` | An internal Redis Software database by name. Name only — no selector. The role grants management access only; its ACL isn't bound to that database. |\n| `acl.kind` | `redis_acl` | An internal Redis Software ACL by name. |\n| `roleRef.kind` | `role` | An internal Redis Software role by name, from a binding. |\n\nThe reference resolves by name against the existing Redis Software object. Use internal references to migrate assignments incrementally, then replace them with full `RedisEnterpriseDatabase`, `RedisEnterpriseACL`, and `RedisEnterpriseRole` resources as you bring each object under the CRD model."
    },
    {
      "id": "migrate-a-database",
      "title": "Migrate a database",
      "role": "content",
      "text": "For each database, capture what `rolesPermissions` currently grants, recreate it as CRDs, verify the result, then remove the deprecated field."
    },
    {
      "id": "1-inventory-the-existing-entries",
      "title": "1. Inventory the existing entries",
      "role": "content",
      "text": "List the `rolesPermissions` entries on every REDB in the operator namespace:\n\n[code example]\n\nEach entry has a `role` (Redis Software role name) and an `acl` (Redis Software ACL name). The `type` is always `redis-enterprise`."
    },
    {
      "id": "2-create-redisenterpriseacl-resources",
      "title": "2. Create RedisEnterpriseACL resources",
      "role": "content",
      "text": "For every distinct ACL name in the inventory, create a `RedisEnterpriseACL` resource that holds the same rule string. See [Manage ACLs](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-acls).\n\n[code example]\n\nThe resource `metadata.name` doesn't have to match the original Redis Software ACL name, but matching makes the merged `status.rolesPermissions` easier to read."
    },
    {
      "id": "3-create-redisenterpriserole-resources",
      "title": "3. Create RedisEnterpriseRole resources",
      "role": "content",
      "text": "For each role-ACL-REDB combination in the inventory, create a `RedisEnterpriseRole` scoped to the target REDB. See [Manage roles](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-roles).\n\n[code example]\n\nSet `managementRole` to match the Redis Software role's management level. If the original entry only granted data-path access, omit `managementRole` — it defaults to `None`.\n\nIf the same role-ACL pair applies to more than one REDB, collapse them into a single `RedisEnterpriseRole` with multiple `scopes` entries instead of creating one role per REDB:\n\n[code example]"
    },
    {
      "id": "4-create-bindings-for-affected-users",
      "title": "4. Create bindings for affected users",
      "role": "content",
      "text": "For each user that previously gained access through `rolesPermissions`, create a `RedisEnterpriseRoleBinding` that references the new role. See [Manage role bindings](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-bindings).\n\n[code example]"
    },
    {
      "id": "5-verify",
      "title": "5. Verify",
      "role": "content",
      "text": "Confirm Redis Software still grants the expected access:\n\n[code example]\n\nThe merged `status.rolesPermissions` shows entries from both sources. Before you remove the deprecated entries, authenticate as one of the affected users and run a Redis command the role allows:\n\n[code example]\n\nReplace the endpoint and port with the values from the REDB's `status.publicService` (or `status.internalService`)."
    },
    {
      "id": "6-remove-the-deprecated-entries",
      "title": "6. Remove the deprecated entries",
      "role": "content",
      "text": "Once verification passes, remove the migrated entries from `spec.rolesPermissions`:\n\n[code example]\n\nAfter the next reconcile, `status.rolesPermissions` should contain only CRD-derived entries. Repeat for every REDB."
    },
    {
      "id": "disable-the-deprecated-field",
      "title": "Disable the deprecated field",
      "role": "content",
      "text": "After every database is completely migrated, switch the cluster policy to ignore `spec.rolesPermissions` so no one can re-introduce it:\n\n[code example]\n\nWith `allowREDBRolesPermissions: false`:\n\n- The operator stops reconciling `spec.rolesPermissions` on every REDB.\n- The operator removes from Redis Software any permissions that came only from `spec.rolesPermissions`.\n- The operator emits a `RolesPermissionsIgnored` event on any REDB that still has the deprecated field set.\n\nThe default is `true` (both sources reconciled). Set the flag back to `true` only as a rollback."
    },
    {
      "id": "roll-back",
      "title": "Roll back",
      "role": "content",
      "text": "To revert to the deprecated field, set `allowREDBRolesPermissions: true` (or omit it) on the `RedisEnterpriseCluster` and re-add the previous entries to each REDB's `spec.rolesPermissions`. CRD-managed permissions continue to work in parallel."
    },
    {
      "id": "troubleshoot",
      "title": "Troubleshoot",
      "role": "errors",
      "text": "- **A user is missing access after you remove the deprecated entries** — A `RedisEnterpriseRole` or binding is missing for that user. Check `RedisEnterpriseUser.status.roles` against the original inventory and add the missing CRDs.\n- **`status.rolesPermissions` is empty after migration** — The new roles haven't reconciled. Each `RedisEnterpriseRole` needs `status.uid` populated before it contributes to a REDB. Check the role's events.\n- **`RolesPermissionsIgnored` event on a REDB after disabling the field** — A `spec.rolesPermissions` entry remains on the REDB. Edit the REDB and remove the field entirely."
    },
    {
      "id": "related-topics",
      "title": "Related topics",
      "role": "related",
      "text": "- [Manage roles](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-roles) — full details on `RedisEnterpriseRole` and `RedisEnterpriseClusterRole`.\n- [Manage ACLs](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-acls) — define the data-path permissions roles reference.\n- [Manage role bindings](https://redis.io/docs/latest/operate/kubernetes/security/access-control/manage-bindings) — assign the new roles to users.\n- [`RedisEnterpriseDatabase` API reference](https://redis.io/docs/latest/operate/kubernetes/reference/api/redis_enterprise_database_api) — the source schema, including the deprecated `rolesPermissions` field.\n- [`RedisEnterpriseCluster` API reference](https://redis.io/docs/latest/operate/kubernetes/reference/api/redis_enterprise_cluster_api) — the `accessControl.policy.allowREDBRolesPermissions` flag."
    }
  ],
  "examples": [
    {
      "id": "1-inventory-the-existing-entries-ex0",
      "language": "sh",
      "code": "kubectl get redisenterprisedatabase -o yaml | \\\n  yq '.items[] | {name: .metadata.name, rolesPermissions: .spec.rolesPermissions}'",
      "section_id": "1-inventory-the-existing-entries"
    },
    {
      "id": "2-create-redisenterpriseacl-resources-ex0",
      "language": "yaml",
      "code": "apiVersion: app.redislabs.com/v1alpha1\nkind: RedisEnterpriseACL\nmetadata:\n  name: read-only\nspec:\n  acl: \"+@read ~*\"",
      "section_id": "2-create-redisenterpriseacl-resources"
    },
    {
      "id": "3-create-redisenterpriserole-resources-ex0",
      "language": "yaml",
      "code": "apiVersion: app.redislabs.com/v1alpha1\nkind: RedisEnterpriseRole\nmetadata:\n  name: orders-viewer\nspec:\n  managementRole: DBViewer\n  scopes:\n  - name: orders\n  acl:\n    name: read-only",
      "section_id": "3-create-redisenterpriserole-resources"
    },
    {
      "id": "3-create-redisenterpriserole-resources-ex1",
      "language": "yaml",
      "code": "spec:\n  managementRole: DBViewer\n  scopes:\n  - name: orders\n  - name: customers\n  - name: inventory\n  acl:\n    name: read-only",
      "section_id": "3-create-redisenterpriserole-resources"
    },
    {
      "id": "4-create-bindings-for-affected-users-ex0",
      "language": "yaml",
      "code": "apiVersion: app.redislabs.com/v1alpha1\nkind: RedisEnterpriseRoleBinding\nmetadata:\n  name: alice-orders-viewer\nspec:\n  roleRef:\n    name: orders-viewer\n  subjects:\n  - name: alice",
      "section_id": "4-create-bindings-for-affected-users"
    },
    {
      "id": "5-verify-ex0",
      "language": "sh",
      "code": "kubectl get redisenterprisedatabase orders -o yaml | \\\n  yq '.status.rolesPermissions'",
      "section_id": "5-verify"
    },
    {
      "id": "5-verify-ex1",
      "language": "sh",
      "code": "redis-cli -h <db-endpoint> -p <db-port> --user alice --pass <password> GET some:key",
      "section_id": "5-verify"
    },
    {
      "id": "6-remove-the-deprecated-entries-ex0",
      "language": "sh",
      "code": "kubectl edit redisenterprisedatabase orders",
      "section_id": "6-remove-the-deprecated-entries"
    },
    {
      "id": "disable-the-deprecated-field-ex0",
      "language": "yaml",
      "code": "apiVersion: app.redislabs.com/v1\nkind: RedisEnterpriseCluster\nmetadata:\n  name: rec\nspec:\n  accessControl:\n    policy:\n      allowREDBRolesPermissions: false",
      "section_id": "disable-the-deprecated-field"
    }
  ]
}
