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

Anton Vinogradov updated IGNITE-29211:
--------------------------------------
    Description: 
Load replacement certificates supplied by an external system before the current 
chains expire. This removes the need to issue a reload command for each 
scheduled certificate rotation. Ignite does not issue certificates or watch 
files; trust-store-only changes and immediate operator action still use {{--ssl 
reload}}.

h3. Result and acceptance

* Renewal is opt-in. Schedule from the earliest expiry across all reported 
X.509 chains, including CA certificates. Require available, nonempty 
certificate metadata at startup and on replacement.
* Install the whole replacement only when all reported certificates are 
currently valid and the earliest expiry advances. Alias changes are allowed. 
Retain current material on failure or unchanged expiry and retry with bounded 
backoff and jitter, including after expiry.
* Serialize automatic attempts and manual {{init()}}. Direct initialization 
replans renewal; stale or interrupted attempts must not install material. Node 
shutdown ends renewal without recording cancellation as a failed reload or 
renewal.
* Show the next attempt in {{--ssl status}}. The node metric 
{{ssl.ConsecutiveRenewalFailures}} sums unsuccessful automatic attempts across 
distinct factories, counting a shared factory once. Unchanged expiry counts; 
failed manual reloads do not. Reset the affected count only when an installed 
bundle advances earliest expiry.
* Test expiry across chains, unchanged/invalid material, retries, metrics, 
direct initialization, races, shutdown and restart. Default configuration 
schedules no renewal work.

h3. Operation and lifecycle

Supply and trust replacements before the renewal window. Configure renewal 
before startup and restart nodes to change its settings. Use a separate 
renewal-enabled factory per running node; it may attach to a new node after the 
old executor stops. Reusing the same initialized factory retains material until 
explicit initialization or successful renewal.

See [Prepare Certificate Delivery and Enable 
Renewal|https://github.com/anton-vinogradov/ignite/blob/ignite-29211/docs/_docs/security/ssl-tls.adoc#renewing-certificates-automatically]
 for rollout and recovery, and the [setting contracts and 
defaults|https://github.com/anton-vinogradov/ignite/blob/ignite-29211/modules/commons/src/main/java/org/apache/ignite/ssl/AbstractSslContextFactory.java#L155]
 for scheduling details. Entries without eligible X.509 chains are omitted from 
monitoring. No renewal result proves that peers trust the replacement.

h3. Delivery and HTTP integration

Open the PR after IGNITE-29210 merges. IGNITE-29212 is an independent consumer 
of the same reload mechanism and may merge before or after this task.

After IGNITE-29211 and IGNITE-29212 are both present, include the single [joint 
integration 
commit|https://github.com/anton-vinogradov/ignite/commit/e1a7c86c428cf775ef86750bfdca746d1cdeb88c]
 in the PR that merges second. Apply it once, without replaying older 
integration patches. It adds HTTPS automatic-renewal coverage and the 
corresponding documentation/Javadoc. Run {{JettySslContextReloadTest}} and 
{{SslRenewalNodeTest}} on that combined branch.

Final head: {{34b1f7a7}}. Local validation in the combined integration 
{{ed06380c}}: 86 targeted SSL tests passed, two existing JMX variants were 
skipped, and Checkstyle passed. This is local combined validation, not full CI.


  was:
Automatically load certificates delivered by an external system before the 
current chain expires. That system issues and publishes replacements; Ignite 
loads them at scheduled attempts. Manual file replacement and trust-store-only 
changes still use {{--ssl reload}}: renewal does not watch files for changes.

h3. How renewal works

Add opt-in settings to AbstractSslContextFactory, disabled by default. Use the 
current {{SslBundle}} to schedule from the earliest expiry across all reported 
X.509 chains, including CA certificates. The renewal window is 
renewBeforeFraction of the interval from the selected chain's leaf validity 
start to its earliest expiry. When expiry dates tie, use the earliest leaf 
validity start to determine the window.

Require at least one reported X.509 chain at startup and on every replacement. 
A null map means metadata is unknown; an empty map means no eligible chains 
were found. Reject both when renewal is enabled because neither supplies an 
expiry date. Entries without a nonempty X.509 chain are omitted by 
{{KeyMaterial}} and are not monitored.

The factory owns the accepted bundle, replacement checks and reload outcome 
from IGNITE-29210. It also owns its renewal planner and unsuccessful-attempt 
count; the node supplies and stops the executor. Automatic attempts call 
{{renew(expectedContext)}} on the factory, using the same fresh-loading hook 
and replacement checks as manual {{init()}}.

Install the whole bundle only when every reported chain is currently valid and 
the minimum expiry across all reported chains increases. Aliases may be 
renamed, added or removed; no match with the previous alias names is required. 
If an entry loses its chain, its alias disappears from metadata and renewal 
uses the remaining chains, just as when an alias is removed.

If the minimum expiry does not advance, loading fails or validation rejects the 
replacement, retain the current bundle and retry with bounded backoff and 
jitter, including after expiry. Show the next attempt in {{--ssl status}} and 
log the cause.

Serialize renewal and manual {{init()}} on the factory, replan after a 
successful replacement and prevent an obsolete automatic attempt from 
installing its result. Direct application calls to {{init()}} use the same 
replacement, replan and counter rules. Use the node's operation context so 
scheduled work is attributed to the node. Shutdown interrupts and finishes 
renewal work; cancellation must neither count as failure nor overwrite the last 
reload result.

A factory with renewal enabled may attach to only one running node's renewal 
executor. Use a separate factory instance for each running node. After that 
executor stops, the same factory may attach to the restarted node with the 
renewal settings configured for that restart. Reusing the factory object 
retains its accepted material until {{init()}} loads a replacement; restarting 
the node does not itself reread stores through that already initialized object.

h3. Monitoring and acceptance

Publish one node metric, {{ssl.ConsecutiveRenewalFailures}}, so monitoring can 
detect unsuccessful delivery or loading. Sum consecutive unsuccessful automatic 
attempts across distinct factories and count a shared factory once. An 
unchanged minimum expiry counts as unsuccessful. Reset only the affected 
factory's count when renewal or manual reload installs a bundle whose minimum 
expiry across all reported chains is later. Failed manual reloads do not 
increment this metric.

Test scheduling across all reported X.509 chains, CA expiry, retries after 
expiry, unchanged material, alias changes and omitted chains, metric 
aggregation and reset, reload races and shutdown. Cover direct {{init()}} 
calls, reuse after the old executor stops and rejection of attachment to two 
running renewal executors. Verify that a node with default renewal settings 
plans no attempt and starts no renewal thread. Explain delivery prerequisites, 
enabling renewal, inspecting failures and recovering with reload.

h3. Dependencies and remaining work

Implementation, tests and documentation are prepared on {{ignite-29211}}. Open 
its PR after IGNITE-29210 is merged and run CI on the updated branch. HTTP REST 
integration in IGNITE-29212 is independent.

After both IGNITE-29211 and IGNITE-29212 are present, apply the single 
[prepared integration 
commit|https://github.com/anton-vinogradov/ignite/commit/e1a7c86c428cf775ef86750bfdca746d1cdeb88c]
 to the PR that merges second. It replaces the previous integration commits; do 
not apply the old patch list as well. It updates HTTP REST renewal 
documentation and Javadoc and adds an HTTPS test proving that automatic renewal 
presents the replacement certificate on a new connection. On that combined 
branch, run JettySslContextReloadTest and SslRenewalNodeTest.



> 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
>
> Load replacement certificates supplied by an external system before the 
> current chains expire. This removes the need to issue a reload command for 
> each scheduled certificate rotation. Ignite does not issue certificates or 
> watch files; trust-store-only changes and immediate operator action still use 
> {{--ssl reload}}.
> h3. Result and acceptance
> * Renewal is opt-in. Schedule from the earliest expiry across all reported 
> X.509 chains, including CA certificates. Require available, nonempty 
> certificate metadata at startup and on replacement.
> * Install the whole replacement only when all reported certificates are 
> currently valid and the earliest expiry advances. Alias changes are allowed. 
> Retain current material on failure or unchanged expiry and retry with bounded 
> backoff and jitter, including after expiry.
> * Serialize automatic attempts and manual {{init()}}. Direct initialization 
> replans renewal; stale or interrupted attempts must not install material. 
> Node shutdown ends renewal without recording cancellation as a failed reload 
> or renewal.
> * Show the next attempt in {{--ssl status}}. The node metric 
> {{ssl.ConsecutiveRenewalFailures}} sums unsuccessful automatic attempts 
> across distinct factories, counting a shared factory once. Unchanged expiry 
> counts; failed manual reloads do not. Reset the affected count only when an 
> installed bundle advances earliest expiry.
> * Test expiry across chains, unchanged/invalid material, retries, metrics, 
> direct initialization, races, shutdown and restart. Default configuration 
> schedules no renewal work.
> h3. Operation and lifecycle
> Supply and trust replacements before the renewal window. Configure renewal 
> before startup and restart nodes to change its settings. Use a separate 
> renewal-enabled factory per running node; it may attach to a new node after 
> the old executor stops. Reusing the same initialized factory retains material 
> until explicit initialization or successful renewal.
> See [Prepare Certificate Delivery and Enable 
> Renewal|https://github.com/anton-vinogradov/ignite/blob/ignite-29211/docs/_docs/security/ssl-tls.adoc#renewing-certificates-automatically]
>  for rollout and recovery, and the [setting contracts and 
> defaults|https://github.com/anton-vinogradov/ignite/blob/ignite-29211/modules/commons/src/main/java/org/apache/ignite/ssl/AbstractSslContextFactory.java#L155]
>  for scheduling details. Entries without eligible X.509 chains are omitted 
> from monitoring. No renewal result proves that peers trust the replacement.
> h3. Delivery and HTTP integration
> Open the PR after IGNITE-29210 merges. IGNITE-29212 is an independent 
> consumer of the same reload mechanism and may merge before or after this task.
> After IGNITE-29211 and IGNITE-29212 are both present, include the single 
> [joint integration 
> commit|https://github.com/anton-vinogradov/ignite/commit/e1a7c86c428cf775ef86750bfdca746d1cdeb88c]
>  in the PR that merges second. Apply it once, without replaying older 
> integration patches. It adds HTTPS automatic-renewal coverage and the 
> corresponding documentation/Javadoc. Run {{JettySslContextReloadTest}} and 
> {{SslRenewalNodeTest}} on that combined branch.
> Final head: {{34b1f7a7}}. Local validation in the combined integration 
> {{ed06380c}}: 86 targeted SSL tests passed, two existing JMX variants were 
> skipped, and Checkstyle passed. This is local combined validation, not full 
> CI.



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

Reply via email to