[ 
https://issues.apache.org/jira/browse/HDDS-17409?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Siyao Meng updated HDDS-17409:
------------------------------
    Affects Version/s: 2.3.0

> Revoking an S3 secret should record an STS revocation cutoff for the access id
> ------------------------------------------------------------------------------
>
>                 Key: HDDS-17409
>                 URL: https://issues.apache.org/jira/browse/HDDS-17409
>             Project: Apache Ozone
>          Issue Type: Bug
>    Affects Versions: 2.3.0
>            Reporter: Siyao Meng
>            Priority: Major
>         Attachments: MC-3-record-sts-revocation-cutoff-on-secret-revoke.patch
>
>
> h3. Mechanism
> {{S3SecurityUtil.validateS3Credential}} runs two revocation checks for an STS 
> session token. {{isRevokedStsToken}} compares the signed creation time of the 
> token with the cutoff stored for its {{originalAccessKeyId}} in 
> {{s3RevokedStsTokenTable}}. {{isOriginalAccessKeyIdRevoked}} treats the 
> creator as revoked when no S3 secret exists for that access id 
> ({{!hasS3Secret(originalAccessKeyId)}}).
> {{S3RevokeSecretRequest}} (behind {{ozone s3 revokesecret}}) removes the 
> secret and writes nothing to {{s3RevokedStsTokenTable}}. The revocation of 
> the secret is therefore represented only by the absence of a secret, and no 
> revocation time is kept. The STS design doc ({{ozone-sts.md}}, section 3.5) 
> says that when the secret of the user that created an STS token is revoked 
> with {{ozone s3 revokesecret}}, all existing unexpired STS tokens that user 
> created are revoked, and HDDS-14364 states the same requirement. With only 
> the presence check, that holds as long as the access id has no secret.
> h3. Trigger
> The secret for an access id is removed by {{S3RevokeSecretRequest}} and a 
> secret is later stored for the same access id, while STS tokens issued under 
> the first secret are unexpired (an STS token lives up to 12 hours). From that 
> point neither check reflects the earlier revocation: a secret exists, and no 
> cutoff was recorded.
> While the access id has no secret, {{S3RevokeSTSTokenRequest.preExecute}} 
> refuses to record a cutoff for it ({{ACCESS_ID_NOT_FOUND}}). That check is 
> intended (it keeps entries for unknown ids out of the table), but it means a 
> cutoff can be recorded with {{ozone s3 revokeststoken}} only once a secret 
> exists for the access id.
> h3. Impact
> * For STS tokens issued before the secret was revoked, the revocation 
> described in the design doc lasts only until a secret is stored for the same 
> access id. From then on {{validateS3Credential}} handles them like tokens of 
> an access id that was never revoked, until they expire.
> * No data is lost or changed. STS is not part of a released Ozone version.
> h3. Reproduction
> The regression tests in the attached patch cover it, in 
> {{TestS3GetSecretRequest}} ({{hadoop-ozone/ozone-manager}}). They drive the 
> real request classes on a real {{OmMetadataManagerImpl}} and commit each 
> response to the DB:
> * {{testRevokeSecretRecordsStsRevocationCutoff}}: revoking a secret records 
> the cutoff stamped in {{preExecute}} in {{s3RevokedStsTokenTable}}, and the 
> cutoff is still there after a new secret is stored for the access id. Without 
> the change it fails because {{preExecute}} attaches no cutoff ({{Expecting 
> actual: 0L to be greater than: 0L}}).
> * {{testRevokeSecretKeepsLaterStsRevocationCutoff}}: an existing later cutoff 
> is kept, not lowered. Without the change it fails with {{expected: <60000> 
> but was: <null>}}, since nothing is written to the DB.
> * {{testRevokeSecretWithoutAttachedCutoffRecordsNone}}: a revoke entry 
> applied without {{preExecute}}, as from a leader without the change, removes 
> the secret and records no cutoff, in the cache or in the DB. It passes with 
> and without the change.
> * {{testRevokeMissingSecretRecordsNoStsRevocationCutoff}}: revoking an access 
> id that has no secret ({{S3_SECRET_NOT_FOUND}}) records no cutoff. It passes 
> with and without the change.
> No standalone reproduction is attached. Not run: a multi OM cluster, or the 
> RPC path end to end.
> h3. Patch
> [^MC-3-record-sts-revocation-cutoff-on-secret-revoke.patch], against 
> 5f7111a27ea07ce6b7bf5284a4213ebacb65f2ae. It also applies to master at 
> 65320362775.
> {{S3RevokeSecretRequest.preExecute}} attaches a {{RevokeSTSTokenRequest}} to 
> the {{OMRequest}} with the leader's current time as {{revocationTimeMillis}}, 
> as {{S3RevokeSTSTokenRequest}} stamps its cutoff and as 
> {{S3GetSecretRequest}} attaches the leader generated 
> {{UpdateGetS3SecretRequest}}. This is an existing field of {{OMRequest}}, so 
> there is no proto change. When {{validateAndUpdateCache}} removes the secret, 
> it records that time for the access id in the {{s3RevokedStsTokenTable}} 
> cache, keeping the larger value if a cutoff already exists, and 
> {{S3RevokeSecretResponse}} writes it in the same batch as the secret 
> deletion. A log entry without the attached cutoff is applied as before, and a 
> revoke of an access id with no secret records nothing.
> With the cutoff in place, {{isRevokedStsToken}} rejects every token of the 
> access id created before the revocation, whether or not a secret is stored 
> later. Tokens created after the revocation are unaffected. 
> {{RevokedSTSTokenCleanupService}} purges the DB row after the usual 
> threshold, by which time all tokens it covers have expired; the copy in the 
> table cache stays in memory until the cache is rebuilt, for example on OM 
> restart (unless HDDS-17406 lands). Each successful {{revokesecret}} now adds 
> one such row, also when STS is not used.
> The "keep the larger cutoff" logic is the same as in the change proposed in 
> HDDS-17408 for {{S3RevokeSTSTokenRequest}}; whichever lands second should 
> move it into one shared helper. Rows written by this path are subject to the 
> purge behaviour addressed in HDDS-17406. 
> {{OMTenantRevokeUserAccessIdRequest}} removes the secret of a tenant access 
> id the same way, without recording a cutoff; that path is handled in a 
> separate issue.
> With the patch, {{TestS3GetSecretRequest}}, {{TestS3RevokeSTSTokenRequest}}, 
> {{TestS3SecurityUtil}}, {{TestS3AssumeRoleRequest}}, 
> {{TestS3SecretRequestHelper}}, {{TestRevokedSTSTokenCleanupService}}, 
> {{TestOmMetadataManager}}, 
> {{TestSecureOzoneCluster.testGetSetRevokeS3Secret}} and 
> {{TestMultiTenantVolume}} pass, and checkstyle on 
> {{hadoop-ozone/ozone-manager}} is clean.
> Found by TLA+ model checking and code review of the OM STS token revocation 
> and cleanup paths under HDDS-15926, on commit 
> 5f7111a27ea07ce6b7bf5284a4213ebacb65f2ae. Checked against HDDS issues and 
> apache/ozone pull requests for duplicates before filing. Related but not 
> duplicates: HDDS-14364 (added the secret presence check), HDDS-14066 and 
> HDDS-14067 (the revocation cutoff table and {{revokeststoken}}), HDDS-14094 
> (the cleanup service). 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]

Reply via email to