[
https://issues.apache.org/jira/browse/HDDS-17237?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Dian-Xuan Yang reassigned HDDS-17237:
-------------------------------------
Assignee: Dian-Xuan Yang
> Tenant create on a Kerberos cluster overwrites the creating admin's volume
> list, so their existing volumes disappear from listVolumes
> -------------------------------------------------------------------------------------------------------------------------------------
>
> Key: HDDS-17237
> URL: https://issues.apache.org/jira/browse/HDDS-17237
> Project: Apache Ozone
> Issue Type: Bug
> Affects Versions: 1.3.0, 1.4.0, 2.0.0, 1.4.1, 2.1.0, 2.2.0, 2.1.1, 2.1.2,
> 2.2.1
> Reporter: Siyao Meng
> Assignee: Dian-Xuan Yang
> Priority: Major
> Attachments:
> CR-3-use-volume-owner-as-user-key-on-tenant-create.patch,
> TestBugCR3TenantCreateOwnerVolumeList.java
>
>
> h3. Mechanism
> {{OMTenantCreateRequest.preExecute}} sets the owner of the tenant volume to
> the caller's short name ({{ugi.getShortUserName()}}).
> {{OMTenantCreateRequest.validateAndUpdateCache}} instead uses
> {{UserInfo.userName}} as the owner, which {{OMClientRequest.getUserInfo}}
> fills with {{ugi.getUserName()}}, the full principal under Kerberos (for
> example {{[email protected]}}). It takes the user lock, reads the owner's
> volume list and adds the updated list to the user table cache under that
> principal. {{OMTenantCreateResponse.addToDBBatch}} then writes the list under
> {{getUserKey(omVolumeArgs.getOwnerName())}}, the short name.
> Every other request that writes the user table ({{OMVolumeCreateRequest}},
> {{OMVolumeDeleteRequest}}, {{OMVolumeSetOwnerRequest}}) keys it by the volume
> owner, which {{RpcClient.createVolume}} sets to the short name. So the list
> read under the full principal is normally empty, the computed list is just
> the tenant volume, and the flush replaces the owner's real list with it.
> h3. Trigger
> # On a Kerberos cluster, {{[email protected]}} (mapped to {{alice}} by
> auth_to_local) owns at least one volume, for example {{vol1}} or the volume
> of a tenant she created earlier.
> # alice, an OM admin, runs {{ozone tenant create tenant1}}.
> S3 multi-tenancy can only be enabled with Kerberos, so every tenant create in
> a real deployment runs with a full principal. Without Kerberos (user name
> equals short name) both keys match and the result is correct.
> h3. Impact
> * After the flush the user table row {{alice}} is {{[tenant1]}}.
> {{listVolumes}} for alice, which serves {{OzoneManager.listVolumeByUser}} and
> {{ozone sh volume list}} for the user, no longer returns {{vol1}}. The volume
> still exists, is still owned by alice and its data is untouched.
> * The per-user volume count ({{ozone.om.user.max.volume}}) reads the same
> row, so it undercounts from then on, and it already undercounts in the check
> during tenant create itself.
> * The row is permanent. No request rebuilds the user table from the volume
> table, later volume creates by alice append to the truncated list, and each
> further tenant create by alice truncates it again, so an admin who created
> several tenants sees only the last tenant volume.
> * If the owner's list later becomes empty, for example after the listed
> tenant volume is deleted, the row is removed. Deleting a volume that was
> dropped from the list, or changing its owner, then fails with
> {{USER_NOT_FOUND}} ({{OMVolumeRequest.delVolumeFromOwnerList}}), and the
> volume stays. Creating any volume for the owner first makes both work again.
> h3. Reproduction
> PASS on unmodified source when the defect is present.
> [^TestBugCR3TenantCreateOwnerVolumeList.java]
> ({{hadoop-ozone/ozone-manager}}; target path and Maven command in the class
> comment) sets the RPC caller to a remote UGI {{[email protected]}} with an
> auth_to_local rule mapping it to {{alice}}, as the RPC server does under
> Kerberos. Each request runs through the real {{preExecute}},
> {{validateAndUpdateCache}}, response {{checkAndUpdateDB}}, a batch commit and
> a cache cleanup, and the test waits until the user table cache is evicted, as
> it is on an OM by the next command. alice's row is read from RocksDB.
> * alice owns {{vol1}} and creates {{tenant1}}: her row is {{[tenant1]}}.
> After {{tenant2}} it is {{[tenant2]}}. Setting the owner of {{vol1}} to
> {{bob}} and back to {{alice}} gives {{[tenant2, vol1]}}.
> * alice owns {{vol1}}, creates {{tenant1}}, deletes the tenant and its volume
> (both OK): her row is gone. Deleting {{vol1}} and setting its owner to
> {{bob}} both fail with {{USER_NOT_FOUND User not found: alice}}, and {{vol1}}
> is still in the volume table. After creating {{vol2}} for alice, deleting
> {{vol1}} is OK.
> * Control with caller {{alice}}: the same steps keep {{[vol1, tenant1,
> tenant2]}} and every delete is OK.
> With the patch the two Kerberos tests fail at their first check (alice's row
> is {{[vol1, tenant1]}}, and {{[vol1]}} after the tenant volume is deleted)
> and the control passes. Not run on a Kerberos cluster.
> h3. Patch
> [^CR-3-use-volume-owner-as-user-key-on-tenant-create.patch], against
> 20d95ed37fe35013b5320713665db03c06ee36fa. It also applies to master at
> 41d95dd3286.
> {{validateAndUpdateCache}} takes the owner from the {{VolumeInfo}} built in
> {{preExecute}} instead of {{UserInfo.userName}}, so the user lock, the read,
> the cache entry and the DB write use the same key as the response and the
> volume requests. Audit logging still uses {{UserInfo}}. Lists that were
> already overwritten are not repaired. A dropped volume can be put back by
> setting its owner to another user and back, or, if the owner's row is gone,
> after creating any volume for that owner. During a rolling upgrade an unfixed
> OM still writes the truncated list for the same entry.
> Covered by {{testValidateAndUpdateCacheAddsVolumeToOwnerVolumeList}} in the
> existing {{TestOMTenantCreateRequest}}, parameterized with a short name
> (control, passes before and after) and a full principal in {{UserInfo}},
> checking that the cache holds the owner's list only under the owner key, and
> the list in the cache and in RocksDB after the response is written. Without
> the change the principal case fails because the cache entry is under
> {{[email protected]}}. With it the tenant request suites,
> {{TestOMMultiTenantManager}}, {{TestOMMultiTenantManagerImpl}} and the volume
> request suites, including volume delete and set owner (59 tests), and the
> mini cluster suites {{TestMultiTenantVolume}} and {{TestOzoneTenantShell}}
> (11 tests, without Kerberos, run before the test was extended) pass,
> checkstyle is clean.
> Found by code review of the OM volume, bucket and snapshot lifecycle paths,
> as part of the TLA+ verification effort under HDDS-15926, on commit
> 20d95ed37fe35013b5320713665db03c06ee36fa. 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
(v10.3.26#10030026)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]