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

Anton Vinogradov updated IGNITE-29211:
--------------------------------------
    Description: 
Administrators can reload TLS certificates with {{control.sh --ssl reload}}. 
Add optional automatic renewal so nodes can read replacements before expiry 
without that command. Ignite reads the configured source; it does not issue 
certificates.

h3. Schedule

* Renewal is off by default. Add 
{{SslContextFactory.setRenewalEnabled(boolean)}} and {{isRenewalEnabled()}}; 
changing the setting requires a restart. Cover enabled factories used by the 
node's started TCP transports.
* Read certificate chains from the key store actually loaded, including custom 
sources. With renewal enabled, require at least one private key and an X.509 
chain for every private key.
* A chain expires when any certificate in it expires. Select the chain with the 
earliest expiry. Start attempts with 15% of its lifetime remaining, measured 
from the key certificate's validity start. For equal expiries, use the longest 
lifetime. A date already due at startup triggers an immediate attempt.
* After a replacement, recalculate the schedule. If renewal is already due, 
warn and wait one hour before the next automatic attempt. Keep future dates, 
even if closer than one hour. Manual reload remains available during the wait.
* After a failed automatic attempt, retry with a one-minute base delay, 
doubling up to one hour. Add a random delay of up to half the base delay. 
Continue retries after expiry.

h3. Replacement rules

* Manual and automatic replacements in {{SslContextFactory}} must check every 
certificate in the private-key chains against the current date. Accept equal, 
earlier or later expiry. Allow trust-store-only changes. Initial loading keeps 
its existing behavior, including recovery from expired certificates.
* Publish a replacement only after loading and validation succeed. On failure, 
keep the current context and renewal date. Established connections remain 
usable; new connections use the accepted context.
* If keys, certificate chains, trust certificates and TLS settings are 
unchanged, keep the context. The manual command reports {{unchanged}}, 
preserves the retry schedule and failure count, and continues with other 
factories. An unchanged automatic attempt is logged and counted as a failure.
* If custom trust managers or non-exportable keys prevent a reliable 
comparison, reload instead of reporting {{unchanged}}. Factories extending only 
{{AbstractSslContextFactory}} keep their own manual loading behavior.

h3. API and execution

Expose {{getRenewalTime()}}, {{void renew()}} and {{boolean reload()}} on 
{{SslContextFactory}}. Preserve {{void init()}}. The getter returns an 
epoch-millisecond date, or {{0}} if disabled or not initialized. {{reload()}} 
returns whether it replaced the context.

{{renew()}} rechecks the date after waiting for an active load. It skips 
loading when disabled, not initialized or not due. Before a due load, an 
interrupted thread throws {{IgniteInterruptedException}} without clearing the 
flag. Loading, validation and unchanged-material failures also throw. After any 
normal return, the node rereads the date.

Manual and automatic loads run one at a time. Each node keeps its own schedule; 
nodes sharing a factory may query the source in the same window. Startup may 
load the same factory twice, sequentially.

Once shutdown starts, start no further automatic attempts and count no further 
failures. Cancel queued work and interrupt an automatic attempt waiting for the 
factory. A load already started may finish and install a validated replacement. 
Startup initialization already waiting for the factory may still proceed. 
Custom sources must bound load time so shutdown can finish.

h3. Feedback and checks

* Log failures and the next attempt with the affected transports.
* {{ssl.ConsecutiveRenewalFailures}} sums consecutive automatic failures on the 
node. Reset a factory's count after replacement or an automatic skip because 
renewal is no longer due. Manual failures and shutdown cancellation do not 
increment it.
* Add {{ssl.ManualReloadAttempts}} and {{ssl.AutomaticRenewalAttempts}}. Count 
calls per factory, including failures, unchanged material and automatic skips. 
A shared transport factory counts once per attempt. Exclude startup, direct 
application calls and queued calls cancelled before execution.
* Test dates, custom sources, unchanged and trust-only loads, error recovery, 
scheduling, shared factories, shutdown and metrics. Verify renewal through a 
new TLS connection and {{unchanged}} through the real manual command.
* Document preparation, trust rollout, command results and recovery.

Depends on IGNITE-29210. IGNITE-29212 adds HTTPS. A separate status command and 
certificate inventory are outside this ticket.

[Implementation in PR #13786|https://github.com/apache/ignite/pull/13786]


  was:
After IGNITE-29210, administrators can load replacement certificates with 
{{control.sh --ssl reload}}. They still have to run it before the certificates 
expire. Add optional renewal that loads replacements from the configured 
source. If no acceptable replacement is available, keep the working context and 
retry. Ignite does not issue certificates.

h3. When to load a replacement

# Add {{SslContextFactory.setRenewalEnabled(boolean)}} and 
{{isRenewalEnabled()}}. Renewal is off by default; changing the setting 
requires a restart. Each node schedules only enabled factories used by its 
started TCP transports.
# Read certificate chains from the key store used to build the accepted 
context, including stores returned by overridden loaders. A chain contains the 
key's certificate and its issuing certificates. Its usable lifetime ends at the 
earliest expiry in that chain, including CA certificates. With renewal enabled, 
reject startup unless the store contains at least one private key and every 
private key has an X.509 chain.
# Select the key chain with the earliest expiry. Start renewal when it has 15% 
of its lifetime left, measured from the key certificate's validity start to 
that expiry. If several chains share the earliest expiry, use the longest 
lifetime. If the renewal time has passed, attempt immediately.

h3. Which replacements to accept

# An automatic replacement must contain a key chain. Before accepting it, check 
that every certificate in its key chains is within its validity dates and that 
the earliest expiry moves later. Unchanged earliest expiry counts as a failure 
even if other store contents changed.
# Loading or validation failure must preserve the current context and its 
renewal dates. Retry even after expiry: start with a one-minute base delay, 
double it up to one hour, and add a random delay of up to half the base delay.
# Manual and automatic loads of a factory run one at a time. With renewal 
enabled, manual loads also need a key chain, but do not require current 
certificate validity or a later expiry. This permits a manual trust-only 
reload. After any successful manual reload on the node, reread the renewal time 
and attempt immediately if it is due. Nodes sharing a factory keep separate 
schedules and may both query the source in one renewal window. At startup, they 
may load the same factory twice, one at a time.

h3. Factory API

Expose public {{getRenewalTime()}} and {{void renew()}} on 
{{SslContextFactory}}. The getter returns the renewal time in epoch 
milliseconds, or {{0}} when disabled or not initialized. After waiting for 
other loads, {{renew()}} rechecks the renewal time. It skips loading if 
disabled, not initialized or not yet due. Before loading, an interrupted thread 
throws {{IgniteInterruptedException}} without clearing its interrupt flag. 
Loading and validation failures also throw. After any normal return, including 
a skip, the node rereads the renewal time.

h3. Shutdown and operator feedback

* Once shutdown starts, start no further automatic attempts and record no 
further failures. An automatic attempt waiting for another load exits without 
reading the source. One already allowed to start may finish and install a 
replacement that passes validation. Startup initialization already waiting for 
the factory may still load material after shutdown starts.
* Log the next attempt and failures with the affected transports. Add 
{{ssl.ConsecutiveRenewalFailures}}: the sum of each factory's consecutive 
automatic failures on that node, or zero without renewal. Clear a factory's 
count after an accepted automatic replacement, any successful manual reload or 
a skipped attempt. Manual failures and shutdown cancellation do not increment 
it.
* Document configuration, retries, the metric, recovery and custom loaders 
using {{loadKeyStore()}} or {{openFileInputStream()}}. Custom loaders must 
limit load time: a stuck source call can delay manual reload and node shutdown.

h3. Done when

Tests confirm scheduling from the certificates actually loaded, including a 
custom loader, and rejection at startup without a chain. Verify the public API, 
including zero renewal time and no source load from {{renew()}} when renewal is 
disabled or the waiting thread is interrupted. Cover the disabled default, date 
calculations, invalid and unchanged replacements, retries after expiry, manual 
reload, shared factories, shutdown and counter resets. A new TLS connection 
must use the renewed material while an established connection stays usable.

Depends on IGNITE-29210. IGNITE-29212 adds HTTPS and its renewal test. A 
separate status command and certificate inventory are outside this ticket.

[Implementation plan in PR #13786|https://github.com/apache/ignite/pull/13786]



> Renew TLS certificates automatically before expiry
> --------------------------------------------------
>
>                 Key: IGNITE-29211
>                 URL: https://issues.apache.org/jira/browse/IGNITE-29211
>             Project: Ignite
>          Issue Type: Sub-task
>            Reporter: Anton Vinogradov
>            Assignee: Anton Vinogradov
>            Priority: Major
>              Labels: ise
>          Time Spent: 1h 10m
>  Remaining Estimate: 0h
>
> Administrators can reload TLS certificates with {{control.sh --ssl reload}}. 
> Add optional automatic renewal so nodes can read replacements before expiry 
> without that command. Ignite reads the configured source; it does not issue 
> certificates.
> h3. Schedule
> * Renewal is off by default. Add 
> {{SslContextFactory.setRenewalEnabled(boolean)}} and {{isRenewalEnabled()}}; 
> changing the setting requires a restart. Cover enabled factories used by the 
> node's started TCP transports.
> * Read certificate chains from the key store actually loaded, including 
> custom sources. With renewal enabled, require at least one private key and an 
> X.509 chain for every private key.
> * A chain expires when any certificate in it expires. Select the chain with 
> the earliest expiry. Start attempts with 15% of its lifetime remaining, 
> measured from the key certificate's validity start. For equal expiries, use 
> the longest lifetime. A date already due at startup triggers an immediate 
> attempt.
> * After a replacement, recalculate the schedule. If renewal is already due, 
> warn and wait one hour before the next automatic attempt. Keep future dates, 
> even if closer than one hour. Manual reload remains available during the wait.
> * After a failed automatic attempt, retry with a one-minute base delay, 
> doubling up to one hour. Add a random delay of up to half the base delay. 
> Continue retries after expiry.
> h3. Replacement rules
> * Manual and automatic replacements in {{SslContextFactory}} must check every 
> certificate in the private-key chains against the current date. Accept equal, 
> earlier or later expiry. Allow trust-store-only changes. Initial loading 
> keeps its existing behavior, including recovery from expired certificates.
> * Publish a replacement only after loading and validation succeed. On 
> failure, keep the current context and renewal date. Established connections 
> remain usable; new connections use the accepted context.
> * If keys, certificate chains, trust certificates and TLS settings are 
> unchanged, keep the context. The manual command reports {{unchanged}}, 
> preserves the retry schedule and failure count, and continues with other 
> factories. An unchanged automatic attempt is logged and counted as a failure.
> * If custom trust managers or non-exportable keys prevent a reliable 
> comparison, reload instead of reporting {{unchanged}}. Factories extending 
> only {{AbstractSslContextFactory}} keep their own manual loading behavior.
> h3. API and execution
> Expose {{getRenewalTime()}}, {{void renew()}} and {{boolean reload()}} on 
> {{SslContextFactory}}. Preserve {{void init()}}. The getter returns an 
> epoch-millisecond date, or {{0}} if disabled or not initialized. {{reload()}} 
> returns whether it replaced the context.
> {{renew()}} rechecks the date after waiting for an active load. It skips 
> loading when disabled, not initialized or not due. Before a due load, an 
> interrupted thread throws {{IgniteInterruptedException}} without clearing the 
> flag. Loading, validation and unchanged-material failures also throw. After 
> any normal return, the node rereads the date.
> Manual and automatic loads run one at a time. Each node keeps its own 
> schedule; nodes sharing a factory may query the source in the same window. 
> Startup may load the same factory twice, sequentially.
> Once shutdown starts, start no further automatic attempts and count no 
> further failures. Cancel queued work and interrupt an automatic attempt 
> waiting for the factory. A load already started may finish and install a 
> validated replacement. Startup initialization already waiting for the factory 
> may still proceed. Custom sources must bound load time so shutdown can finish.
> h3. Feedback and checks
> * Log failures and the next attempt with the affected transports.
> * {{ssl.ConsecutiveRenewalFailures}} sums consecutive automatic failures on 
> the node. Reset a factory's count after replacement or an automatic skip 
> because renewal is no longer due. Manual failures and shutdown cancellation 
> do not increment it.
> * Add {{ssl.ManualReloadAttempts}} and {{ssl.AutomaticRenewalAttempts}}. 
> Count calls per factory, including failures, unchanged material and automatic 
> skips. A shared transport factory counts once per attempt. Exclude startup, 
> direct application calls and queued calls cancelled before execution.
> * Test dates, custom sources, unchanged and trust-only loads, error recovery, 
> scheduling, shared factories, shutdown and metrics. Verify renewal through a 
> new TLS connection and {{unchanged}} through the real manual command.
> * Document preparation, trust rollout, command results and recovery.
> Depends on IGNITE-29210. IGNITE-29212 adds HTTPS. A separate status command 
> and certificate inventory are outside this ticket.
> [Implementation in PR #13786|https://github.com/apache/ignite/pull/13786]



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to