Siyao Meng created HDDS-16854:
---------------------------------
Summary: Ranger background sync never retries a failed role delete
of a removed tenant, so the tenant can never be created again
Key: HDDS-16854
URL: https://issues.apache.org/jira/browse/HDDS-16854
Project: Apache Ozone
Issue Type: Bug
Reporter: Siyao Meng
Attachments: CR-3-retry-failed-ranger-role-deletes-in-sync.patch,
TestBugCR3OrphanRoleCleanup.java
h3. Mechanism
{{OMRangerBGSyncService}} removes the Ranger state of a tenant that is not in
the OM DB by deleting its labeled policies in {{processAllPoliciesFromOMDB}}
and then its roles in {{processAllRolesFromOMDB}}. A failed role delete is only
logged ("Failed to delete role", without the exception). The sync learns about
roles only from the role ACLs of the policies labeled {{OzoneTenant}}
({{loadAllPoliciesAndRoleNamesFromRanger}}), and those policies are already
gone. So no later run sees the role again, and the run records the Ranger
service version as in sync. {{createRole}} fails when a role with the same name
exists (HDDS-15982 kept creation fail fast), so every later create of that
tenant fails.
HDDS-16188 describes the same end state reached through a partially failed
tenant create. This report is about the cleanup path of the sync, which needs
its own change.
h3. Trigger
# A tenant create leaves Ranger roles and policies without a tenant in OM. One
way: {{OMTenantCreateRequest.preExecute}} creates them, then the apply fails,
for example with {{VOLUME_ALREADY_EXISTS}} because the volume was created
concurrently. {{preExecute}} expects the sync to clean this up.
# The sync deletes both policies, then the delete of {{tenant1-UserRole}} fails
once (HTTP 5xx, timeout, Ranger restart).
# Later sync runs, also runs that execute because the Ranger service version
changed, never delete the role.
# Every {{ozone tenant create tenant1}} fails with {{TENANT_AUTHORIZER_ERROR}},
cause "Role already exists". {{ozone tenant delete tenant1}} cannot help
because OM has no such tenant (argued, not run).
h3. Impact
The tenant id cannot be created again until an operator deletes the leftover
roles in Ranger by hand. It needs two independent events: a tenant create that
fails after its Ranger objects were created, and a failed Ranger call during
the cleanup. No data is lost. Creating a tenant requires cluster admin
privilege.
h3. Reproduction
PASS, deterministic, unmodified source. [^TestBugCR3OrphanRoleCleanup.java]
({{hadoop-ozone/ozone-manager}}) runs the real {{OMTenantCreateRequest}}
({{preExecute}}, then {{validateAndUpdateCache}} after a volume of the same
name was added to the OM DB), the real {{AuthorizerOp}}, the real
{{OMRangerBGSyncService.triggerRangerSyncOnce}} and a real OM DB. Ranger is the
in-memory controller that OM uses with {{ozone.om.tenant.dev.skip.ranger}},
wrapped in a Mockito spy that fails one delete of the user role. Before the
second and third sync run the test changes the Ranger service version with an
unrelated labeled policy, so that the sync executes. Output on the unmodified
source:
{noformat}
create #1: VOLUME_ALREADY_EXISTS; Ranger roles [tenant1-UserRole,
tenant1-AdminRole], policies [tenant1-BucketAccess, tenant1-VolumeAccess],
tenant in OM DB: false
sync run 1: completed true; Ranger roles [tenant1-UserRole], policies []
sync run 2: completed true; Ranger roles [tenant1-UserRole], policies []
sync run 3: completed true; Ranger roles [tenant1-UserRole], policies []
retry 1: TENANT_AUTHORIZER_ERROR java.io.IOException: Role already exists.
retry 2: TENANT_AUTHORIZER_ERROR java.io.IOException: Role already exists.
{noformat}
With real Ranger, the admin role delete is then refused too, because the user
role still names it as delegated admin ({{RoleDBStore.ensureRoleDeleteAllowed}}
refuses to delete a role referenced by a policy, another role or a security
zone), so both roles are left. The in-memory controller does not check this, so
only the user role is left here. A passing test means the defect is present.
Not run against a real Ranger.
h3. Suggested fix
Remember the roles whose delete failed and retry them in the following runs,
skipping any role that belongs to a tenant in OM again. Finding tenant roles in
Ranger by name or description instead was rejected, because Ranger roles are
not scoped to a service, so the sync of one cluster could delete the tenant
roles of another cluster using the same Ranger. Persisting the pending deletes
in the OM DB would survive a leader change, but needs a new DB entry.
h3. Patch
[^CR-3-retry-failed-ranger-role-deletes-in-sync.patch], against
a6b7bdb937109ba2893688b41a89470bc95c88cf. It also applies to master at
b0aa6475b78.
The sync keeps the names of roles whose delete failed in memory. At the start
of each run, before the version check, it retries each of them once, under the
authorizer write lock and against the tenant cache read inside that lock
(tenant requests hold the lock until their cache update), so a role that
belongs to a tenant again, for example one re-created after a manual cleanup,
is dropped instead of deleted. A successful retry changes the Ranger service
version, so the normal sync follows as today. The first failure of a delete is
now logged with its exception, a failed retry with one line. Behaviour changes
only while a role delete keeps failing, which includes a delete that Ranger
refuses permanently (a leftover role that is referenced from another policy,
role or security zone): each sync run (default every 600s) then makes one
Ranger delete call per such role and logs one line, with no reload and no
{{SetRangerServiceVersion}} request. The set lives on the leader only and is
cleared when the sync task runs on an OM that is not the ready leader, so a
leader change or restart before the retry succeeds loses it.
Covered by two tests in the existing {{TestOMMultiTenantManagerImpl}}.
{{testRangerSyncRetriesFailedRoleDelete}}: the user role delete fails in the
first run and in the retry of the second run, which then submits no
{{SetRangerServiceVersion}} request; the third run deletes the role and the
fourth issues no further delete. Without the change it fails with
"tenant2-UserRole left in Ranger".
{{testRangerSyncKeepsRoleOfRecreatedTenant}}: after a failed delete, the role
is deleted by hand and the tenant is created again; the next run keeps the new
tenant's role. With the change the multi-tenancy unit suites in
{{hadoop-ozone/ozone-manager}} (35 tests) and {{TestOzoneTenantShell}} and
{{TestMultiTenantVolume}} on a mini cluster (11 tests) pass, checkstyle is
clean. With the patch the reproduction fails after the second sync run, because
no role is left.
Found by code review of the OM multi-tenancy and Ranger sync paths, as part of
the TLA+ verification effort under HDDS-15926, on commit
a6b7bdb937109ba2893688b41a89470bc95c88cf. Checked against HDDS issues and
apache/ozone pull requests for duplicates before filing. The attached patch is
a proposal for review. Generated with Specula (Claude Opus 5.5).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]