Siyao Meng created HDDS-17179:
---------------------------------

             Summary: OM skips the secret key expiry check before symmetric 
token signing is finalized, so a runtime finalize issues tokens that fail early
                 Key: HDDS-17179
                 URL: https://issues.apache.org/jira/browse/HDDS-17179
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: 
CR-2-check-secret-key-expiry-before-symmetric-token-finalization.patch, 
TestBugCR2FinalizeSkipsSecretKeyGuard.java

h3. Mechanism
HDDS-13343 added a check to 
{{OzoneManager.createDelegationTokenSecretManager}}: OM refuses to start unless 
{{hdds.secret.key.rotate.duration}} + 
{{ozone.manager.delegation.token.max-lifetime}} + 
{{ozone.manager.delegation.remover.scan.interval}} is at most 
{{hdds.secret.key.expiry.duration}}, so that no SCM secret key expires while a 
token it signed can still be renewed. The check only runs when 
{{DELEGATION_TOKEN_SYMMETRIC_SIGN}} is already finalized at construction; an OM 
that is not finalized only checks the certificate grace period.

{{OzoneDelegationTokenSecretManager.createToken}} checks 
{{isAllowed(DELEGATION_TOKEN_SYMMETRIC_SIGN)}} on every call, and finalization 
({{finalizeupgrade}}, then {{OMCompleteFinalizeUpgradeRequest}} and 
{{OMVersionManager.finalizeUpgrade}}) does not restart OM and does not run the 
check. So an OM that started before finalization with a configuration the check 
would refuse signs delegation tokens with SCM secret keys from the moment 
finalization completes, and the check only fires at the next OM start.

h3. Trigger
# A secure cluster that has not finalized {{DELEGATION_TOKEN_SYMMETRIC_SIGN}} 
(layout 8, added in 2.0.0; for example a cluster upgraded from 1.4.x) runs this 
version with a configuration that breaks the rule. The default 
{{hdds.secret.key.expiry.duration}} became 9d in 2.1.0; before that it was 7d, 
so an {{ozone-site.xml}} that sets it explicitly to the old default (7d with a 
7d token lifetime and 1d rotation) is enough. With default values the rule 
holds and nothing happens.
# An administrator runs {{ozone admin om finalizeupgrade}}. OM finalizes 
without a restart.
# A client gets a delegation token, now signed with the current SCM secret key.
# SCM removes that key when it expires, while the token's max date is still in 
the future (for a token signed just before the next rotation, rotation period 
plus token lifetime minus key expiry, so 1d with the values above).
# Renewing the token fails ("Tampered/Invalid token", caused by "Secret verify 
key ... not found"), and the token cannot recover. Authenticating with it goes 
through the same signature check in 
{{OzoneDelegationTokenSecretManager.retrievePassword}} (code reading, not run).
# The next OM start fails with the check's {{IllegalArgumentException}}. A 
checkpoint install from the leader fails the same way, see Impact.

h3. Impact
Tokens issued between finalization and the next OM restart lose up to the last 
day of their lifetime with the configuration above (computed from the formula; 
the scaled run shows the same effect), which breaks long-running jobs that 
renew their tokens up to the max lifetime. The OM then refuses to start until 
the configuration is fixed. An OM that has finalized also terminates when it 
next installs a checkpoint from the leader: {{reloadOMState}} calls 
{{instantiateServices(true)}}, which runs the same check, and 
{{installCheckpoint}} exits the process when the reload throws (code reading, 
not run). Requires an explicit non-compliant configuration on a cluster that 
finalizes this layout feature at runtime; default configurations are not 
affected.

Affected versions: 2.1.0 and later (2.1.0, 2.1.1, 2.1.2, 2.2.0, 2.2.1), the 
releases that contain the check from HDDS-13343. 2.0.0 has layout 8 but no 
check at all.

h3. Reproduction
PASS on the unmodified source. [^TestBugCR2FinalizeSkipsSecretKeyGuard.java] 
({{hadoop-ozone/integration-test}}) starts a secure SCM (no datanodes, safe 
mode off) and a secure OM with MiniKdc, with the OM storage initialized at 
{{HBASE_SUPPORT}} (layout 7) through the existing 
{{OMStorage.TESTING_INIT_APPARENT_VERSION_KEY}} hook, and scaled timings 
(rotate 10s, expiry 20s, token max lifetime 45s, remover interval 1s). It then 
calls {{finalizeUpgrade}}, gets a token, waits until SCM has removed the 
signing key, renews the token and restarts the OM. Output on the unmodified 
source:
{noformat}
OM started pre-finalized, apparent version HBASE_SUPPORT (7), symmetric DT 
allowed false
pre-finalize token secretKeyId='null' (RSA signed)
OM finalized at runtime, apparent version GET_KEY_INFO_REJECTS_OBS (103)
symmetric token issued=1792500182109 maxDate=1792500227109 
signedBy=f068b740-... keyExpiry=1792500196294 (key expires 30815 ms before 
maxDate)
SCM removed key f068b740-... at 1792500196962, token maxDate 1792500227109 is 
still 30147 ms away
(OM log) SCMSecurityException: Secret verify key f068b740-... not found for 
token (...)
renew of unexpired token rejected at 1792500196983 (30126 ms before maxDate, 
...): TOKEN_ERROR_OTHER ... Delegation token renewal failed ...
control token signed by 4ee85a92-... renewed, new expiry 1792500241984
OM restart after runtime finalization refused: Secret key expiry duration 
hdds.secret.key.expiry.duration should be greater than value of (...)
{noformat}
A passing test means the defect is present. With the patch the first OM start 
already fails with the check's message.

h3. Patch
[^CR-2-check-secret-key-expiry-before-symmetric-token-finalization.patch], 
against b94df213f20ec0d675f079b57a4566e4e64e4060. It also applies to master at 
df42f7f60a2.

The secret key check now runs at every OM start, whether or not 
{{DELEGATION_TOKEN_SYMMETRIC_SIGN}} is finalized; the certificate grace period 
check still runs only before finalization. This changes behaviour for one setup 
only: an OM that is not finalized and has a configuration that breaks the rule 
now refuses to start (with the same message as after finalization) instead of 
starting and failing later. The {{ozone.manager.delegation.token.max-lifetime}} 
description in {{ozone-default.xml}} now says that a secure Ozone Manager fails 
to start if the rule does not hold. The same check also runs in the checkpoint 
reload, so with the patch such an OM refuses at start instead of exiting during 
a later install.

HDDS-16958 (open) changes the same check and the same {{ozone-default.xml}} 
description. Each patch applies to b94df213f20ec0d675f079b57a4566e4e64e4060 on 
its own; this one does not apply on top of the patch attached to HDDS-16958 
({{OzoneManager.java}} and {{ozone-default.xml}} conflict, the test applies), 
so whichever lands second needs a small rebase, and the {{ozone-default.xml}} 
clause here can be dropped if HDDS-16958 lands first.

Rejected alternatives: checking in {{OMFinalizeUpgradeRequestBase.preExecute}} 
covers only the leader's configuration and not an OM that finalizes from a 
leader snapshot; an upgrade action for the layout feature runs during Ratis 
apply, and if it threw on one OM that OM would stay at the previous layout 
while its peers move on.

Covered by an extension of 
{{assertSecureOmInitFailsWithInvalidTokenAndSecretKeyConfig}} in the existing 
{{TestSecureOzoneCluster}}: OM initialization with the invalid configuration is 
refused when the OM is not finalized (new) and when it is (existing), and an OM 
that is not finalized still starts with a valid configuration. Without the 
change it fails at the case that is not finalized ({{Expected 
java.lang.IllegalArgumentException to be thrown, but nothing was thrown.}}). 
With it {{TestSecureOzoneCluster}} (9 tests), {{TestDelegationToken}}, 
{{TestSecureOzoneManager}} and {{TestOMUpgradeFinalization}} (7 tests) on mini 
clusters and the OM unit suites for the finalize requests, the finalize 
service, the delegation token secret manager and the bucket and key managers 
(83 tests) pass, and checkstyle is clean.

h3. Release note
A secure Ozone Manager that has not finalized 
{{DELEGATION_TOKEN_SYMMETRIC_SIGN}} now refuses to start if 
{{hdds.secret.key.rotate.duration}} + 
{{ozone.manager.delegation.token.max-lifetime}} + 
{{ozone.manager.delegation.remover.scan.interval}} exceeds 
{{hdds.secret.key.expiry.duration}}, as a finalized one already did. This hits 
secure clusters upgraded from 1.4.x or older and not yet finalized whose 
{{ozone-site.xml}} sets the expiry explicitly (for example to the old 7d 
default) or raises the token max lifetime or rotate duration; raise 
{{hdds.secret.key.expiry.duration}} on SCM and OM (9d covers the defaults) 
before upgrading.

Found by code review of the OM delegation token secret manager and request 
paths, as part of the TLA+ verification effort under HDDS-15926, on commit 
b94df213f20ec0d675f079b57a4566e4e64e4060. 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]

Reply via email to