Siyao Meng created HDDS-17200:
---------------------------------

             Summary: S3SecretManagerImpl.getSecretString ignores the deleted 
marker of an S3 secret cache entry and returns its secret
                 Key: HDDS-17200
                 URL: https://issues.apache.org/jira/browse/HDDS-17200
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: CR-10-treat-deleted-s3-secret-cache-entry-as-absent.patch

h3. Mechanism
{{S3SecretManagerImpl.getSecretString}} does its own cache lookup: it calls 
{{S3SecretCache.get}} for the access key and, for any entry it finds, returns 
{{S3SecretValue.getAwsSecret}} of that entry. It never consults 
{{S3SecretValue.isDeleted}}. The in memory cache keeps a revoked secret as an 
entry that still carries the secret string and is marked as deleted, until the 
double buffer flush cleans the entry up (HDDS-9444), so a marked entry is a 
value that the cache holds precisely to record that the secret is gone.

{{S3SecretManagerImpl.getSecret}}, the other reader of the same cache on the 
same class, treats an entry marked as deleted as absent and returns null for it 
without consulting the store. {{getSecretString}} bypasses {{getSecret}} 
entirely, so the two readers of one cache state disagree: {{getSecret}} reports 
the secret as absent and {{getSecretString}} returns its secret string. On a 
cache miss {{getSecretString}} also reads {{S3SecretStore.getSecret}} itself 
and writes the result back into the cache with {{updateCache}}, instead of 
going through {{getSecret}}.

h3. Trigger
# The S3 secret cache holds an entry for an access key that is marked as 
deleted and is not yet flushed.
# {{S3SecretManagerImpl.getSecretString}} is called for that access key.

h3. Impact
* For an access key whose cache entry is marked as deleted, {{getSecretString}} 
returns the secret string of that entry instead of throwing 
{{OzoneSecurityException}} with {{S3_SECRET_NOT_FOUND}}, which is what the same 
class reports through {{getSecret}} for the same state. Confirmed by the 
regression test below.
* The disagreement lasts as long as the marked entry stays in the cache, that 
is until the flush removes it; after that {{getSecretString}} reads the store 
and the secret is reported as absent (code reading, not run).
* No secret value and no stored row is changed by the read path, and the result 
for an entry that is not marked as deleted is the same before and after the 
patch.
* By history, not run on older code: the cache entries marked as deleted 
arrived with HDDS-9444, so a marked entry can only exist from that change 
onwards.

h3. Reproduction
There is no standalone reproduction; the regression test is in the attached 
patch. {{TestS3GetSecretRequest.testGetSecretStringOfRevokedSecret}}, added to 
the existing suite, drives a get and then a revoke through 
{{S3RevokeSecretRequest.validateAndUpdateCache}} without a flush, asserts that 
the cache entry is marked as deleted and that {{getSecret}} returns null, and 
then expects {{getSecretString}} to throw with {{S3_SECRET_NOT_FOUND}}. Without 
the change it fails with "Expected 
org.apache.hadoop.hdds.security.exception.OzoneSecurityException to be thrown, 
but nothing was thrown."

h3. Patch
[^CR-10-treat-deleted-s3-secret-cache-entry-as-absent.patch], against 
a6b7bdb937109ba2893688b41a89470bc95c88cf. It also applies to master at 
1753288f333.

{{S3SecretManagerImpl.getSecretString}} no longer reads the cache and the store 
itself. It calls {{getSecret}} for the access key, which is the reader that 
treats an entry marked as deleted as absent without consulting the store, and 
throws {{OzoneSecurityException}} with {{S3_SECRET_NOT_FOUND}} when the result 
is null. The direct cache lookup is dropped; on a cache miss {{getSecret}} 
reads the store and caches the result as {{getSecretString}} did before, so 
there is one reader of the cache state for both methods. There is no wire or 
protocol change and nothing stored changes.

With the patch 125 unit tests pass ({{TestS3GetSecretRequest}}, 
{{TestOzoneDelegationTokenSecretManager}}, {{TestOzoneManagerDoubleBuffer}}, 
{{TestS3DerivedKey}}, {{TestS3SecurityUtil}}, the other S3 secret request 
tests, and the tenant request and manager tests), 
{{TestSecureOzoneCluster#testGetSetRevokeS3Secret}} and 
{{TestMultiTenantVolume}} pass on a mini cluster (6 tests), and checkstyle is 
clean.

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. Related but not a 
duplicate: HDDS-9444 (introduced the in memory S3 secret cache entries that are 
marked as deleted). 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]

Reply via email to