Skip to content

CNTRLPLANE-2012: Refactor TLS cert generation to support configurable key algorithms#10594

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
hasbro17:pki-2-tls-refactor
Jul 9, 2026
Merged

CNTRLPLANE-2012: Refactor TLS cert generation to support configurable key algorithms#10594
openshift-merge-bot[bot] merged 1 commit into
openshift:mainfrom
hasbro17:pki-2-tls-refactor

Conversation

@hasbro17

@hasbro17 hasbro17 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Part 2 of splitting #10396 into smaller PRs. Depends on #10593.
Refactors pkg/asset/tls/ to support generating signer certificates with configurable key algorithms (RSA or ECDSA):

  • PrivateKeyToPem now returns ([]byte, error) instead of calling logrus.Fatalf
  • PemToPrivateKey supports both RSA and ECDSA private keys
  • GenerateSelfSignedCertificate accepts *PrivateKeyParams to control key algorithm, size, and curve
  • SelfSignedCertKey.Generate accepts *types.PKIConfig to pass through PKI configuration
  • KeyUsage flags are set based on the key algorithm (ECDSA keys cannot perform key encipherment)
  • New helpers: GenerateRSAPrivateKey, GenerateECDSAPrivateKey, PKIConfigToKeyParams

All signer certs pass nil for pkiConfig in this commit, preserving the existing RSA-2048 behavior. Wiring signers to read PKI config is deferred to a follow-up to avoid breaking codepaths that generate
signer certs without an install-config on disk (e.g. agent create certificates, node-joiner add-nodes).

PR chain

  1. CNTRLPLANE-2012: Add PKI config types, validation, and CR manifest generation #10593 — PKI types, validation, CRD, feature gate, PKI CR manifest (this PR depends on)
  2. This PR — TLS engine refactoring
  3. CNTRLPLANE-2012: Wire signer certs to read PKI config via SignerKeyParams #10595 — Wire signer certs + SignerKeyParams
  4. Documentation

Summary by CodeRabbit

  • New Features
    • TLS certificate generation now supports both RSA and ECDSA keys, including automatic algorithm-based certificate settings.
    • Private key PEM import/export now works for RSA, ECDSA, and PKCS#8 formats.
  • Bug Fixes
    • Improved error handling when private key encoding or parsing fails.
    • Self-signed certificate generation now returns errors instead of continuing with invalid key data.
  • Tests
    • Added coverage for key generation, PEM round-trips, signature selection, and cross-algorithm certificate signing.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jun 3, 2026
@openshift-ci-robot

openshift-ci-robot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

@hasbro17: This pull request references CNTRLPLANE-2012 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target either version "5.0." or "openshift-5.0.", but it targets "openshift-4.22" instead.

Details

In response to this:

Summary

Part 2 of splitting #10396 into smaller PRs. Depends on #10593.
Refactors pkg/asset/tls/ to support generating signer certificates with configurable key algorithms (RSA or ECDSA):

  • PrivateKeyToPem now returns ([]byte, error) instead of calling logrus.Fatalf
  • PemToPrivateKey supports both RSA and ECDSA private keys
  • GenerateSelfSignedCertificate accepts *PrivateKeyParams to control key algorithm, size, and curve
  • SelfSignedCertKey.Generate accepts *types.PKIConfig to pass through PKI configuration
  • KeyUsage flags are set based on the key algorithm (ECDSA keys cannot perform key encipherment)
  • New helpers: GenerateRSAPrivateKey, GenerateECDSAPrivateKey, PKIConfigToKeyParams

All signer certs pass nil for pkiConfig in this commit, preserving the existing RSA-2048 behavior. Wiring signers to read PKI config is deferred to a follow-up to avoid breaking codepaths that generate
signer certs without an install-config on disk (e.g. agent create certificates, node-joiner add-nodes).

PR chain

  1. CNTRLPLANE-2012: Add PKI config types, validation, and CR manifest generation #10593 — PKI types, validation, CRD, feature gate, PKI CR manifest (this PR depends on)
  2. This PR — TLS engine refactoring
  3. Wire signer certs + SignerKeyParams
  4. Documentation

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR generalizes the TLS PKI layer from RSA-only to support both RSA and ECDSA key generation. It introduces PrivateKeyParams, algorithm-parameterized key generators, and a new GenerateSelfSignedCertificate(cfg, params) API. PrivateKeyToPem and PemToPrivateKey are updated to handle both key types with proper error returns, and all callers gain corresponding error handling.

Changes

Multi-algorithm PKI support

Layer / File(s) Summary
Core TLS API: multi-algo key gen, PEM helpers, and GenerateSelfSignedCertificate
pkg/asset/tls/tls.go, pkg/asset/tls/utils.go
Adds PrivateKeyParams, PKIConfigToKeyParams, GenerateRSAPrivateKey, GenerateECDSAPrivateKey, GeneratePrivateKeyWithParams, and an algorithm→x509.KeyUsage mapper. Replaces RSA-only GenerateSelfSignedCertificate(cfg) with GenerateSelfSignedCertificate(cfg, params) that generates the key, derives KeyUsages, and calls SelfSignedCertificate via crypto.Signer. Generalizes SelfSignedCertificate, SignedCertificate, and GenerateSignedCertificate from *rsa.PrivateKey to crypto.PrivateKey/crypto.Signer. PrivateKeyToPem and PemToPrivateKey now handle RSA and ECDSA with proper error returns.
SelfSignedCertKey.Generate PKIConfig wiring and error handling
pkg/asset/tls/certkey.go
SelfSignedCertKey.Generate gains a pkiConfig *types.PKIConfig parameter converted via PKIConfigToKeyParams before calling GenerateSelfSignedCertificate. SignedCertKey.Generate and RegenerateSignedCertKey gain explicit PrivateKeyToPem error checks and switch to fmt.Errorf wrapping.
KeyPair and BoundSASigningKey error handling
pkg/asset/tls/keypair.go, pkg/asset/tls/boundsasigningkey.go
KeyPair.Generate checks and wraps PrivateKeyToPem errors and switches to fmt.Errorf. BoundSASigningKey.Load adds an explicit *rsa.PrivateKey type assertion after PemToPrivateKey and fails fast with a clear error for non-RSA keys.
CA signer callers: drop explicit KeyUsages, pass nil PKIConfig
pkg/asset/tls/root.go, pkg/asset/tls/adminkubeconfig.go, pkg/asset/tls/aggregator.go, pkg/asset/tls/apiserver.go, pkg/asset/tls/kubecontrolplane.go, pkg/asset/tls/kubelet.go, pkg/asset/tls/ironictls.go, pkg/asset/imagebased/configimage/ingressoperatorsigner.go
All CA signer Generate methods remove explicit CertCfg.KeyUsages (now derived by GenerateSelfSignedCertificate) and update SelfSignedCertKey.Generate calls to pass nil for the new pkiConfig parameter. IngressOperatorSigner gains PrivateKeyToPem error handling.
Tests
pkg/asset/tls/utils_test.go, pkg/asset/tls/tls_test.go, pkg/asset/tls/certkey_test.go
Adds PEM roundtrip tests for RSA/ECDSA; adds tests for RSA/ECDSA key generation, GenerateSelfSignedCertificate with params, KeyUsage bitmask selection, and signature algorithm auto-detection; adds PKIConfig-driven and cross-algorithm signing tests to certkey tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • openshift/installer#10593: Introduces the types.PKIConfig struct and PKI manifest plumbing that this PR consumes in PKIConfigToKeyParams and SelfSignedCertKey.Generate.

Suggested labels

verified


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
No-Weak-Crypto ❌ Error Touched TLS code still uses SHA-1 for subject-key-id hashing in tls.go and ingressoperatorsigner.go, violating the no-weak-crypto rule. Either exempt RFC 5280 subjectKeyId hashing from this check or replace it where compatible; the current PR still contains SHA-1 usage.
Docstring Coverage ⚠️ Warning Docstring coverage is 51.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main refactor to TLS cert generation for configurable key algorithms.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed Added test titles are static and deterministic (e.g. 'RSA 4096 CA', 'invalid PEM'); no dynamic or generated identifiers appear in test names.
Test Structure And Quality ✅ Passed PASS: The changed tests are plain table-driven unit tests, not Ginkgo; no cluster resources or Eventually/Consistently waits, and assertion style matches nearby package tests.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the changed tests are plain Go unit tests in pkg/asset/tls and don’t use MicroShift-unsupported APIs.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo/e2e tests were added; the touched tests are pkg/asset/tls unit tests using testing.T, with no multi-node or SNO assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed Only TLS cert-generation/test files changed; no deployment manifests, controllers, or topology/scheduling constraints were added.
Ote Binary Stdout Contract ✅ Passed No stdout writes or process-level suite hooks were added in the touched TLS files; searches found none of fmt.Print/println, os.Stdout, klog, or TestMain/RunSpecs setup.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PASS: The PR only changes pkg/asset/tls unit tests and library code; no Ginkgo e2e tests, hardcoded IPs, or external connectivity requirements were added.
Container-Privileges ✅ Passed Summary-listed changes are Go TLS helpers only; no manifest files or privileged/hostPID/hostNetwork/etc. settings were found.
No-Sensitive-Data-In-Logs ✅ Passed Touched logs are generic debug/error strings; no passwords, tokens, PII, hostnames, or key contents are interpolated.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
pkg/asset/tls/utils.go (1)

15-39: 💤 Low value

pem.EncodeToMemory can return nil on encoding failure.

While rare in practice for valid blocks, pem.EncodeToMemory returns nil if the block cannot be encoded. The function should check for this case to avoid returning nil, nil which could cause subtle bugs downstream.

♻️ Proposed fix to check for nil result
-	return pem.EncodeToMemory(block), nil
+	encoded := pem.EncodeToMemory(block)
+	if encoded == nil {
+		return nil, fmt.Errorf("failed to encode PEM block")
+	}
+	return encoded, nil
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/asset/tls/utils.go` around lines 15 - 39, In PrivateKeyToPem, after
calling pem.EncodeToMemory(block) ensure the returned []byte is not nil before
returning; if pem.EncodeToMemory(block) returns nil, return an explicit error
(e.g., "failed to encode PEM") instead of returning nil, nil. Update the
function to call pem.EncodeToMemory(block), check for nil, and return the
encoded bytes on success or a descriptive error when encoding fails; reference
the PrivateKeyToPem function and the pem.EncodeToMemory call to locate the
change.
pkg/types/installconfig.go (1)

262-268: 💤 Low value

Documentation inconsistency: Key field marked +optional but effectively required.

CertificateConfig has MinProperties=1 validation, and Key is the only property. This means Key must be present, contradicting the +optional annotation. Per the PKIConfig docstring stating "signerCertificates must be fully specified with algorithm and key parameters," consider changing to +required.

Proposed fix
 type CertificateConfig struct {
 	// key specifies the cryptographic parameters for the certificate's key pair.
-	// +optional
+	// +required
 	Key KeyConfig `json:"key,omitzero"`
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/types/installconfig.go` around lines 262 - 268, CertificateConfig's Key
is documented as optional but Package-level validation
(+kubebuilder:validation:MinProperties=1) makes it required; update the field
annotation for Key in the CertificateConfig struct (the Key field of type
KeyConfig) to reflect that it is required (replace `+optional` with `+required`)
so the docstring, kubebuilder validation and the json tag
(`json:"key,omitzero"`) are consistent; ensure the change is applied to the
CertificateConfig definition and any related comments mentioning
signerCertificates if present.
pkg/types/pki/validation_test.go (1)

12-263: 💤 Low value

No case exercises fips: true.

Both tables declare a fips field but every case leaves it false, mirroring the unused fips parameter in validation.go. When FIPS-specific validation is implemented (see the validation.go comment), add cases covering fips: true so the FIPS constraints are actually verified.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/types/pki/validation_test.go` around lines 12 - 263, Tests don't exercise
FIPS mode: both TestValidatePKIConfig and TestValidateKeyConfig declare a fips
field but never set it true, so FIPS-specific validation logic in
ValidatePKIConfig and ValidateKeyConfig is untested; add new table entries with
fips: true in both test tables (use the existing fldPath variables) that cover
expected FIPS constraints (e.g., disallow RSA sizes/curves not permitted under
FIPS and require FIPS-approved algorithms), and set expectError/errorCount
accordingly so FIPS-specific branches are actually validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@data/data/install.openshift.io_installconfigs.yaml`:
- Around line 5087-5092: The field description for spec.pki currently asserts
that installer-generated signer certificates use signerCertificates (and implies
the feature is active under ConfigurablePKI) which is untrue until signer wiring
is implemented; update the description or withhold publishing spec.pki: either
(a) soften the text to state that signerCertificates will be used once the
signer wiring is implemented and that current behavior defaults to RSA-2048 when
PKI is nil, referencing spec.pki and signerCertificates and the ConfigurablePKI
feature gate, or (b) remove/hold the spec.pki entry from the published schema
until the follow-up that wires signer generation lands so oc explain does not
advertise unimplemented behavior.

In `@pkg/types/pki/validation.go`:
- Around line 12-116: The fips bool is never used; either implement
FIPS-specific checks or remove it — remove it here: drop the fips parameter from
ValidatePKIConfig, ValidateKeyConfig, validateRSAKeyConfig, and
validateECDSAKeyConfig (and from any callers/tests), update their signatures to
not accept fips, and remove the fips forwarding in ValidatePKIConfig →
ValidateKeyConfig and ValidateKeyConfig →
validateRSAKeyConfig/validateECDSAKeyConfig so the validators remain consistent
and compile.

In `@pkg/types/validation/installconfig_test.go`:
- Around line 3120-3149: These two negative test cases ("invalid PKI signer with
unsupported algorithm" and "invalid PKI signer with bad RSA key size") are
tripping the global pki feature-gate instead of exercising PKI validation;
update their setup to opt into ConfigurablePKI by enabling the "pki" feature
gate around the test (e.g., set the feature gate to true before constructing the
InstallConfig and restore it after), so the assertion targets types.PKIConfig
validation (SignerCertificates/Key) rather than the gate check; reference the
test case names and types.PKIConfig/ConfigurablePKI when making the change.

---

Nitpick comments:
In `@pkg/asset/tls/utils.go`:
- Around line 15-39: In PrivateKeyToPem, after calling pem.EncodeToMemory(block)
ensure the returned []byte is not nil before returning; if
pem.EncodeToMemory(block) returns nil, return an explicit error (e.g., "failed
to encode PEM") instead of returning nil, nil. Update the function to call
pem.EncodeToMemory(block), check for nil, and return the encoded bytes on
success or a descriptive error when encoding fails; reference the
PrivateKeyToPem function and the pem.EncodeToMemory call to locate the change.

In `@pkg/types/installconfig.go`:
- Around line 262-268: CertificateConfig's Key is documented as optional but
Package-level validation (+kubebuilder:validation:MinProperties=1) makes it
required; update the field annotation for Key in the CertificateConfig struct
(the Key field of type KeyConfig) to reflect that it is required (replace
`+optional` with `+required`) so the docstring, kubebuilder validation and the
json tag (`json:"key,omitzero"`) are consistent; ensure the change is applied to
the CertificateConfig definition and any related comments mentioning
signerCertificates if present.

In `@pkg/types/pki/validation_test.go`:
- Around line 12-263: Tests don't exercise FIPS mode: both TestValidatePKIConfig
and TestValidateKeyConfig declare a fips field but never set it true, so
FIPS-specific validation logic in ValidatePKIConfig and ValidateKeyConfig is
untested; add new table entries with fips: true in both test tables (use the
existing fldPath variables) that cover expected FIPS constraints (e.g., disallow
RSA sizes/curves not permitted under FIPS and require FIPS-approved algorithms),
and set expectError/errorCount accordingly so FIPS-specific branches are
actually validated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 79bf9351-dd9e-4d6e-a89c-4378addd4242

📥 Commits

Reviewing files that changed from the base of the PR and between d3fba60 and ed2ed81.

⛔ Files ignored due to path filters (1)
  • pkg/types/zz_generated.deepcopy.go is excluded by !**/zz_generated*
📒 Files selected for processing (32)
  • data/data/install.openshift.io_installconfigs.yaml
  • pkg/asset/imagebased/configimage/ingressoperatorsigner.go
  • pkg/asset/manifests/operators.go
  • pkg/asset/manifests/pki.go
  • pkg/asset/manifests/pki_test.go
  • pkg/asset/tls/adminkubeconfig.go
  • pkg/asset/tls/aggregator.go
  • pkg/asset/tls/apiserver.go
  • pkg/asset/tls/boundsasigningkey.go
  • pkg/asset/tls/certkey.go
  • pkg/asset/tls/certkey_test.go
  • pkg/asset/tls/ironictls.go
  • pkg/asset/tls/keypair.go
  • pkg/asset/tls/kubecontrolplane.go
  • pkg/asset/tls/kubelet.go
  • pkg/asset/tls/root.go
  • pkg/asset/tls/tls.go
  • pkg/asset/tls/tls_test.go
  • pkg/asset/tls/utils.go
  • pkg/asset/tls/utils_test.go
  • pkg/explain/printer_test.go
  • pkg/types/defaults/installconfig.go
  • pkg/types/installconfig.go
  • pkg/types/pki/conversion.go
  • pkg/types/pki/defaults.go
  • pkg/types/pki/defaults_test.go
  • pkg/types/pki/validation.go
  • pkg/types/pki/validation_test.go
  • pkg/types/validation/featuregate_test.go
  • pkg/types/validation/featuregates.go
  • pkg/types/validation/installconfig.go
  • pkg/types/validation/installconfig_test.go

Comment thread data/data/install.openshift.io_installconfigs.yaml
Comment thread pkg/types/pki/validation.go Outdated
Comment thread pkg/types/validation/installconfig_test.go
@hasbro17

hasbro17 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

/hold

Depends on #10593

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jun 3, 2026
@hasbro17
hasbro17 force-pushed the pki-2-tls-refactor branch 2 times, most recently from cb0bd95 to 96bfc2d Compare June 8, 2026 18:45
@hasbro17
hasbro17 force-pushed the pki-2-tls-refactor branch from 96bfc2d to 194d9f5 Compare June 25, 2026 17:39
@hasbro17

hasbro17 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto #10593 which is not yet merged.
See the 2nd commit for the actual changes

@hasbro17
hasbro17 force-pushed the pki-2-tls-refactor branch from 194d9f5 to 7e5b690 Compare June 25, 2026 20:04
@sanchezl

Copy link
Copy Markdown
Contributor

/retest-required

@tthvo

tthvo commented Jun 29, 2026

Copy link
Copy Markdown
Member

@hasbro17 Let's rebase this PR now that the part-1 PR is merged?

@sanchezl

Copy link
Copy Markdown
Contributor

/hold cancel

@openshift-ci openshift-ci Bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jun 30, 2026
@sanchezl

Copy link
Copy Markdown
Contributor

/retest

@sanchezl

Copy link
Copy Markdown
Contributor

Verification Analysis

Signer Certificate Verification — RSA-2048 Behavior Preserved

From e2e-aws-ovn job artifacts (build 2071673058841595904), all 8 signer CA certificates decoded from openshift-kube-apiserver-operator secrets:

Signer Algorithm Key Size KeyUsage
aggregator-signer RSA 2048 DigitalSignature, KeyEncipherment, CertSign
kube-apiserver-to-kubelet-signer RSA 2048 DigitalSignature, KeyEncipherment, CertSign
kube-control-plane-signer RSA 2048 DigitalSignature, KeyEncipherment, CertSign
kube-apiserver-lb-signer RSA 2048 DigitalSignature, KeyEncipherment, CertSign
localhost-recovery-serving-signer RSA 2048 DigitalSignature, KeyEncipherment, CertSign
kube-apiserver-localhost-signer RSA 2048 DigitalSignature, KeyEncipherment, CertSign
node-system-admin-signer RSA 2048 DigitalSignature, KeyEncipherment, CertSign
kube-apiserver-service-network-signer RSA 2048 DigitalSignature, KeyEncipherment, CertSign

No PKI CR manifest in rendered assets (correct — non-TechPreview job, ConfigurablePKI gate disabled).

CI Results

  • 21 jobs passed — unit, codegen, vendor, lint, govet, e2e-aws-ovn, e2e-metal-assisted, e2e-metal-ipi-ovn, e2e-metal-ipi-ovn-ipv6, e2e-metal-ipi-ovn-swapped-hosts, e2e-metal-ipi-ovn-virtualmedia, e2e-metal-ovn-two-node-fencing, integration-tests, and others
  • 3 infrastructure failures (unrelated, consistent across 2 runs each):
    • e2e-metal-single-node-live-iso — ofcir connection timeout (bare metal provisioner unreachable)
    • e2e-metal-ipi-ovn-dualstack — openstack-installer DockerBuildFailed
    • e2e-metal-ovn-two-node-arbiter — openstack-installer DockerBuildFailed

Unit Test Coverage

New tests verify configurable key algorithm support:

  • TestSelfSignedCertKeyGenerateWithPKIConfig — RSA-4096 and ECDSA-P384 CA generation
  • TestCrossAlgorithmCertificateSigning — ECDSA CA signing RSA leaf, full chain verification
  • TestKeyUsageForAlgorithm — RSA vs ECDSA KeyUsage flags (ECDSA omits KeyEncipherment)
  • TestSignatureAlgorithmAutoDetection — SHA256WithRSA, ECDSAWithSHA256/384/512
  • TestPrivateKeyToPemRoundtrip — RSA and ECDSA PEM serialization roundtrip
  • TestGenerateRSAPrivateKey, TestGenerateECDSAPrivateKey — key generation with all supported params

@sanchezl

Copy link
Copy Markdown
Contributor

/verified by "TestSelfSignedCertKeyGenerateWithPKIConfig,TestCrossAlgorithmCertificateSigning,TestKeyUsageForAlgorithm,TestSignatureAlgorithmAutoDetection,TestPrivateKeyToPemRoundtrip",pull-ci-openshift-installer-main-e2e-aws-ovn

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Jun 30, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@sanchezl: This PR has been marked as verified by "TestSelfSignedCertKeyGenerateWithPKIConfig,TestCrossAlgorithmCertificateSigning,TestKeyUsageForAlgorithm,TestSignatureAlgorithmAutoDetection,TestPrivateKeyToPemRoundtrip",pull-ci-openshift-installer-main-e2e-aws-ovn.

Details

In response to this:

/verified by "TestSelfSignedCertKeyGenerateWithPKIConfig,TestCrossAlgorithmCertificateSigning,TestKeyUsageForAlgorithm,TestSignatureAlgorithmAutoDetection,TestPrivateKeyToPemRoundtrip",pull-ci-openshift-installer-main-e2e-aws-ovn

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@sanchezl sanchezl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jun 30, 2026
@hasbro17
hasbro17 force-pushed the pki-2-tls-refactor branch from 7e5b690 to 6102421 Compare June 30, 2026 04:51
@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Jun 30, 2026
@tthvo

tthvo commented Jul 2, 2026

Copy link
Copy Markdown
Member

/retest

@tthvo

tthvo commented Jul 2, 2026

Copy link
Copy Markdown
Member

/test e2e-agent-compact-ipv4
/test e2e-agent-two-node-fencing-ipv4
/test e2e-agent-ha-dualstack e2e-agent-sno-ipv6

@rh-roman

rh-roman commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

/retest

@sanchezl

sanchezl commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

/payload-job periodic-ci-openshift-release-main-ci-5.0-e2e-aws-ovn-techpreview

@sanchezl

sanchezl commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

/payload-job periodic-ci-openshift-release-main-nightly-5.0-e2e-aws-ovn-fips

@sanchezl

sanchezl commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

/payload-job periodic-ci-openshift-release-main-nightly-5.0-e2e-aws-ovn-single-node-techpreview

@openshift-ci

openshift-ci Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@sanchezl: trigger 1 job(s) for the /payload-(with-prs|job|aggregate|job-with-prs|aggregate-with-prs) command

  • periodic-ci-openshift-release-main-nightly-5.0-e2e-aws-ovn-fips

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/05ad4210-793e-11f1-9c73-909afdf30fe2-0

@openshift-ci

openshift-ci Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@sanchezl: trigger 1 job(s) for the /payload-(with-prs|job|aggregate|job-with-prs|aggregate-with-prs) command

  • periodic-ci-openshift-release-main-nightly-5.0-e2e-aws-ovn-single-node-techpreview

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/064f0050-793e-11f1-9c55-90fce9d7e935-0

@openshift-ci

openshift-ci Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@sanchezl: trigger 1 job(s) for the /payload-(with-prs|job|aggregate|job-with-prs|aggregate-with-prs) command

  • periodic-ci-openshift-release-main-ci-5.0-e2e-aws-ovn-techpreview

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/06e1a360-793e-11f1-9b68-4fbe5e833d61-0

@tthvo

tthvo commented Jul 6, 2026

Copy link
Copy Markdown
Member

/payload-job periodic-ci-openshift-release-main-nightly-5.0-e2e-aws-ovn-fips
/payload-job periodic-ci-openshift-release-main-ci-5.0-e2e-aws-ovn-techpreview

@openshift-ci

openshift-ci Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@tthvo: trigger 2 job(s) for the /payload-(with-prs|job|aggregate|job-with-prs|aggregate-with-prs) command

  • periodic-ci-openshift-release-main-nightly-5.0-e2e-aws-ovn-fips
  • periodic-ci-openshift-release-main-ci-5.0-e2e-aws-ovn-techpreview

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/f0a7f110-7962-11f1-8a28-ee7e4521dd30-0

@tthvo

tthvo commented Jul 6, 2026

Copy link
Copy Markdown
Member

/retest

@tthvo

tthvo commented Jul 6, 2026

Copy link
Copy Markdown
Member

/test e2e-metal-ipi-ovn e2e-metal-single-node-live-iso

@sanchezl

sanchezl commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

/retest ci/prow/e2e-aws-ovn-techpreview ci/prow/e2e-azure-ovn ci/prow/e2e-metal-ipi-ovn ci/prow/e2e-metal-single-node-live-iso

@tthvo

tthvo commented Jul 7, 2026

Copy link
Copy Markdown
Member

/test e2e-aws-ovn-techpreview e2e-azure-ovn e2e-metal-ipi-ovn e2e-metal-single-node-live-iso

@hasbro17

hasbro17 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

/retest

@sanchezl

sanchezl commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

/retest-required

@tthvo

tthvo commented Jul 7, 2026

Copy link
Copy Markdown
Member

@coderabbitai Following #10594 (comment), let's do the same analysis again on the latest e2e jobs.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
gh pr checks 10594 --repo openshift/installer --required=false 2>&1 | head -150
echo "---detailed statuses---"
gh api repos/openshift/installer/commits/pki-2-tls-refactor/status --paginate 2>&1 | python3 -c "
import json,sys
d=json.load(sys.stdin)
for s in d.get('statuses', []):
    print(s.get('context'), s.get('state'), s.get('target_url'))
" 2>&1 | sort | head -300

Length of output: 10418


🏁 Script executed:

#!/bin/bash
set -euo pipefail
pip install pyyaml cryptography -q 2>/dev/null || true

declare -A JOBS=(
  [e2e-aws-ovn-fips]="pull-ci-openshift-installer-main-e2e-aws-ovn-fips:2072717973004488704"
  [e2e-aws-ovn-single-node]="pull-ci-openshift-installer-main-e2e-aws-ovn-single-node:2072717973042237440"
  [e2e-aws-ovn-upgrade]="pull-ci-openshift-installer-main-e2e-aws-ovn-upgrade:2072717973163872256"
  [e2e-aws-ovn-techpreview]="pull-ci-openshift-installer-main-e2e-aws-ovn-techpreview:2074511197255766016"
  [e2e-metal-assisted]="pull-ci-openshift-installer-main-e2e-metal-assisted:2072540769855475712"
  [e2e-metal-ipi-ovn]="pull-ci-openshift-installer-main-e2e-metal-ipi-ovn:2074511203127791616"
  [e2e-metal-ovn-two-node-arbiter]="pull-ci-openshift-installer-main-e2e-metal-ovn-two-node-arbiter:2072540784107720704"
)

for shortname in "${!JOBS[@]}"; do
  IFS=":" read -r job build <<< "${JOBS[$shortname]}"
  echo "=== $shortname (build=$build) ==="
  PREFIX="pr-logs/pull/openshift_installer/10594/${job}/${build}/artifacts/${shortname}/"
  LIST=$(curl -s "https://storage.googleapis.com/storage/v1/b/test-platform-results/o?prefix=${PREFIX}&delimiter=/")
  echo "$LIST" | python3 -c "import json,sys; d=json.load(sys.stdin); print('\n'.join(d.get('prefixes',[])))" | grep -E "gather-extra|gather-must-gather|common-gather" || echo "  (no gather step found)"
done

Length of output: 3759


🏁 Script executed:

#!/bin/bash
set -euo pipefail
pip install pyyaml cryptography -q 2>/dev/null || true

declare -A JOBS=(
  [e2e-aws-ovn-fips]="pull-ci-openshift-installer-main-e2e-aws-ovn-fips:2072717973004488704"
  [e2e-aws-ovn-single-node]="pull-ci-openshift-installer-main-e2e-aws-ovn-single-node:2072717973042237440"
  [e2e-aws-ovn-upgrade]="pull-ci-openshift-installer-main-e2e-aws-ovn-upgrade:2072717973163872256"
  [e2e-aws-ovn-techpreview]="pull-ci-openshift-installer-main-e2e-aws-ovn-techpreview:2074511197255766016"
  [e2e-metal-ovn-two-node-arbiter]="pull-ci-openshift-installer-main-e2e-metal-ovn-two-node-arbiter:2072540784107720704"
)

mkdir -p /tmp/certs2

for shortname in "${!JOBS[@]}"; do
  IFS=":" read -r job build <<< "${JOBS[$shortname]}"
  URL="https://storage.googleapis.com/test-platform-results/pr-logs/pull/openshift_installer/10594/${job}/${build}/artifacts/${shortname}/gather-extra/artifacts/inspect/namespaces/openshift-kube-apiserver-operator/core/secrets.yaml"
  OUT="/tmp/certs2/${shortname}.yaml"
  status=$(curl -s -o "$OUT" -w "%{http_code}" "$URL")
  echo "$shortname: HTTP $status size=$(wc -c < "$OUT" 2>/dev/null || echo 0)"
done

Length of output: 1512


🏁 Script executed:

#!/bin/bash
set -euo pipefail
pip install pyyaml cryptography -q 2>/dev/null || true

python3 << 'EOF'
import yaml, base64, glob, os
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa, ec

for path in sorted(glob.glob('/tmp/certs2/*.yaml')):
    shortname = os.path.basename(path).replace('.yaml','')
    with open(path) as f:
        content = f.read()
    if not content.strip() or content.strip().startswith('<'):
        print(f"=== {shortname}: not valid yaml/empty ===")
        continue
    print(f"\n=== {shortname} ===")
    docs = yaml.safe_load(content)
    items = docs.get('items', docs if isinstance(docs, list) else [])
    found = False
    for item in items:
        name = item.get('metadata', {}).get('name', '')
        if 'signer' not in name:
            continue
        data = item.get('data', {})
        crt_b64 = data.get('tls.crt')
        if not crt_b64:
            continue
        found = True
        crt_der = base64.b64decode(crt_b64)
        cert = x509.load_pem_x509_certificate(crt_der, default_backend())
        pub = cert.public_key()
        if isinstance(pub, rsa.RSAPublicKey):
            alg = f"RSA-{pub.key_size}"
        elif isinstance(pub, ec.EllipticCurvePublicKey):
            alg = f"ECDSA-{pub.curve.name}"
        else:
            alg = str(type(pub))
        ku = cert.extensions.get_extension_for_class(x509.KeyUsage).value
        usages = [a for a in ['digital_signature','key_encipherment','key_cert_sign','crl_sign'] if getattr(ku, a, False)]
        print(f"  {name}: {alg} KeyUsage={usages}")
    if not found:
        print("  No signer secrets found!")
EOF

echo "---checking techpreview gather-extra structure---"
JOB="pull-ci-openshift-installer-main-e2e-aws-ovn-techpreview"
BUILD="2074511197255766016"
PREFIX="pr-logs/pull/openshift_installer/10594/${JOB}/${BUILD}/artifacts/e2e-aws-ovn-techpreview/gather-extra/artifacts/inspect/namespaces/"
curl -s "https://storage.googleapis.com/storage/v1/b/test-platform-results/o?prefix=${PREFIX}&delimiter=/" | python3 -c "
import json,sys
d=json.load(sys.stdin)
prefixes = d.get('prefixes',[])
matches = [p for p in prefixes if 'kube-apiserver' in p]
print('\n'.join(matches) if matches else 'no kube-apiserver namespace dirs found')
print('total namespace dirs:', len(prefixes))
"

Length of output: 6291


🏁 Script executed:

#!/bin/bash
set -euo pipefail
JOB="pull-ci-openshift-installer-main-e2e-aws-ovn-techpreview"
BUILD="2074511197255766016"
curl -s "https://storage.googleapis.com/test-platform-results/pr-logs/pull/openshift_installer/10594/${JOB}/${BUILD}/finished.json" | python3 -m json.tool 2>/dev/null | head -20
echo "---metal-ipi-ovn---"
JOB2="pull-ci-openshift-installer-main-e2e-metal-ipi-ovn"
BUILD2="2074511203127791616"
curl -s "https://storage.googleapis.com/test-platform-results/pr-logs/pull/openshift_installer/10594/${JOB2}/${BUILD2}/finished.json" | python3 -m json.tool 2>/dev/null | head -20

Length of output: 1473


Enough evidence gathered to compose a concise final analysis.

Latest e2e job verification (signer CA cert algorithm/KeyUsage)

@tthvo Same method as before (decoding tls.crt from openshift-kube-apiserver-operator secrets in gather-extra/artifacts/inspect/namespaces/.../core/secrets.yaml), using the most recent completed builds:

Job Build Result
e2e-aws-ovn-fips 2072717973004488704 ✅ All 8 signers RSA-2048, KeyUsage={DigitalSignature, KeyEncipherment, CertSign}
e2e-aws-ovn-single-node 2072717973042237440 ✅ All 8 signers RSA-2048, same KeyUsage
e2e-aws-ovn-upgrade 2072717973163872256 ✅ All 8 signers RSA-2048, same KeyUsage
e2e-metal-ovn-two-node-arbiter 2072540784107720704 ✅ All 8 signers RSA-2048, same KeyUsage
e2e-metal-assisted 2072540769855475712 ❓ Still not verifiable — assisted-common-gather doesn't dump namespace/secret artifacts
e2e-aws-ovn-techpreview 2074511197255766016 ❌ Not verifiable — job failed (result: FAILURE), and gather-extra captured no namespace artifacts at all, meaning the cluster never came up far enough to inspect (unrelated to this PR's cert logic per se, but no data to confirm behavior on this run)
e2e-metal-ipi-ovn 2074511203127791616 ❌ Not verifiable — job errored with a pod scheduling timeout before any gather step ran (infra issue, no cluster)
e2e-azure-ovn ⏳ Still pending/in-flight at the time of this check — no completed run to inspect yet

So for the jobs with usable artifacts, RSA-2048 preservation continues to hold as expected (no regression from the previous check). No ECDSA signers showed up in this batch — the prior ECDSA P-384 finding on TechPreview came from an earlier successful TechPreview run; this latest TechPreview attempt failed before reaching a gatherable state, so I can't re-confirm the operator-side ECDSA rotation behavior on this specific build. I'd suggest re-running this check once e2e-aws-ovn-techpreview, e2e-metal-ipi-ovn, and e2e-azure-ovn land a green (or at least gather-capable) run.

@tthvo

tthvo commented Jul 7, 2026

Copy link
Copy Markdown
Member

/verified by CI

I'm happy with the e2e results so far. Let's get this in early so if something breaks, we will notice it during the week.

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Jul 7, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@tthvo: This PR has been marked as verified by CI.

Details

In response to this:

/verified by CI

I'm happy with the e2e results so far. Let's get this in early so if something breaks, we will notice it during the week.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@tthvo

tthvo commented Jul 7, 2026

Copy link
Copy Markdown
Member

/skip
/tide refresh

@tthvo

tthvo commented Jul 7, 2026

Copy link
Copy Markdown
Member

/tide refresh

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD 6d13655 and 2 for PR HEAD 7ff079b in total

@hasbro17

hasbro17 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

/retest-required

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD bb68686 and 1 for PR HEAD 7ff079b in total

@openshift-ci

openshift-ci Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

@hasbro17: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-metal-single-node-live-iso 7ff079b link false /test e2e-metal-single-node-live-iso
ci/prow/e2e-aws-ovn-techpreview 7ff079b link false /test e2e-aws-ovn-techpreview

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD 64847fc and 0 for PR HEAD 7ff079b in total

@openshift-merge-bot
openshift-merge-bot Bot merged commit 36d3074 into openshift:main Jul 9, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants