Skip to content

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

Open
hasbro17 wants to merge 2 commits into
openshift:mainfrom
hasbro17:pki-2-tls-refactor
Open

CNTRLPLANE-2012: Refactor TLS cert generation to support configurable key algorithms#10594
hasbro17 wants to merge 2 commits into
openshift:mainfrom
hasbro17:pki-2-tls-refactor

Conversation

@hasbro17
Copy link
Copy Markdown
Contributor

@hasbro17 hasbro17 commented Jun 3, 2026

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

    • Add configurable PKI to installer: optional PKI section to choose signer-certificate algorithm (RSA or ECDSA) and parameters (RSA key size, ECDSA curve); installer emits a cluster PKI resource when enabled.
    • Support for generating and using RSA and ECDSA keys across certificate flows.
  • Bug Fixes

    • Improved error handling for private-key PEM encoding and parsing.
    • Stronger validation for PKI/key parameters (ranges, mutual exclusivity).

@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
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Jun 3, 2026

@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
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 52641ca8-02b4-419e-a49f-a5a8e0bff69d

📥 Commits

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

⛔ 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
✅ Files skipped from review due to trivial changes (2)
  • pkg/types/pki/conversion.go
  • pkg/types/defaults/installconfig.go
🚧 Files skipped from review as they are similar to previous changes (27)
  • pkg/explain/printer_test.go
  • pkg/asset/imagebased/configimage/ingressoperatorsigner.go
  • pkg/types/validation/featuregates.go
  • pkg/asset/tls/keypair.go
  • pkg/asset/manifests/operators.go
  • pkg/asset/tls/adminkubeconfig.go
  • pkg/asset/tls/ironictls.go
  • pkg/asset/manifests/pki_test.go
  • pkg/types/validation/installconfig_test.go
  • pkg/types/pki/defaults.go
  • data/data/install.openshift.io_installconfigs.yaml
  • pkg/types/pki/defaults_test.go
  • pkg/asset/manifests/pki.go
  • pkg/types/pki/validation.go
  • pkg/asset/tls/kubelet.go
  • pkg/asset/tls/root.go
  • pkg/types/validation/installconfig.go
  • pkg/asset/tls/tls_test.go
  • pkg/types/validation/featuregate_test.go
  • pkg/asset/tls/certkey_test.go
  • pkg/types/installconfig.go
  • pkg/asset/tls/utils.go
  • pkg/types/pki/validation_test.go
  • pkg/asset/tls/apiserver.go
  • pkg/asset/tls/utils_test.go
  • pkg/asset/tls/certkey.go
  • pkg/asset/tls/tls.go

Walkthrough

Adds feature-gated configurable PKI: CRD schema and InstallConfig types, PKI defaults/conversion, validation and feature-gate wiring, TLS key-parameter APIs and PEM helpers for RSA/ECDSA, updates TLS assets to use the new APIs, and a manifests asset that emits a PKI CR when the feature is enabled.

Changes

Configurable PKI Support

Layer / File(s) Summary
CRD schema and InstallConfig PKI types
data/data/install.openshift.io_installconfigs.yaml, pkg/types/installconfig.go, pkg/explain/printer_test.go, pkg/types/defaults/installconfig.go
Adds spec.pki schema and new InstallConfig.PKI-related types and enums (PKIConfig, CertificateConfig, KeyConfig, RSAKeyConfig, ECDSAKeyConfig, KeyAlgorithm, ECDSACurve) with x-kubernetes-validations and test update.
PKI defaults, conversion, and manifests asset
pkg/types/pki/defaults.go, pkg/types/pki/conversion.go, pkg/asset/manifests/pki.go, pkg/asset/manifests/pki_test.go, pkg/asset/manifests/operators.go
Adds DefaultPKIProfile() and EffectiveSignerPKIConfig(), a conversion helper to upstream configv1alpha1.CertificateConfig, and a PKIConfiguration asset that conditionally generates cluster-pki-02-config.yaml when the ConfigurablePKI feature gate is enabled.
PKI validation and feature-gate integration
pkg/types/pki/validation.go, pkg/types/pki/validation_test.go, pkg/types/validation/installconfig.go, pkg/types/validation/installconfig_test.go, pkg/types/validation/featuregates.go, pkg/types/validation/featuregate_test.go
Implements ValidatePKIConfig and ValidateKeyConfig with RSA key-size and ECDSA-curve checks and mutual-exclusivity rules; wires validation into ValidateInstallConfig and feature-gate checks/tests.
TLS core: key params, multi-algorithm support, and utils
pkg/asset/tls/tls.go, pkg/asset/tls/utils.go, pkg/asset/tls/tls_test.go, pkg/asset/tls/utils_test.go
Introduces PrivateKeyParams, GeneratePrivateKeyWithParams, RSA/ECDSA key generators, algorithm-aware KeyUsage selection, generic crypto.PrivateKey/crypto.Signer certificate APIs, and PEM encoding/parsing helpers supporting RSA and ECDSA with tests.
TLS asset updates and error handling
pkg/asset/tls/*.go, pkg/asset/tls/*_test.go, pkg/asset/imagebased/configimage/ingressoperatorsigner.go, pkg/asset/imagebased/*, pkg/asset/tls/keypair.go
Updates many certificate assets to stop setting explicit KeyUsages (let GenerateSelfSignedCertificate infer by algorithm), pass an extra pkiConfig parameter (or nil) to self-signed generators, improve PEM encoding error handling and generic "private key" error messages, and add RSA type assertions where needed.
Tests and minor edits
pkg/asset/manifests/pki_test.go, pkg/asset/tls/*_test.go, pkg/asset/tls/utils_test.go, pkg/types/pki/*_test.go, pkg/types/validation/*_test.go, pkg/explain/printer_test.go
Adds and updates unit tests covering PKI manifest generation, PKI defaults/effective config, PKI validation, TLS key generation for RSA/ECDSA, PEM roundtrip tests, and schema printing expectations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (14 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective of the pull request: refactoring TLS certificate generation to support configurable key algorithms (RSA and ECDSA), as evidenced by extensive changes to pkg/asset/tls/ files and the addition of PKI configuration support.
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 All test names are static, descriptive strings with no dynamic values, timestamps, UUIDs, or generated identifiers. Uses Go testing, not Ginkgo.
Test Structure And Quality ✅ Passed The PR contains no Ginkgo tests; all tests use standard Go testing patterns with testify/assert. The custom check is not applicable to this PR.
Microshift Test Compatibility ✅ Passed PR adds no Ginkgo e2e tests; only standard Go unit tests are added, which are outside the scope of this MicroShift e2e compatibility check.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests were added in this PR. All new tests are unit tests using Go's standard testing.T framework in pkg/ directories, not e2e tests subject to SNO compatibility requirements.
Topology-Aware Scheduling Compatibility ✅ Passed PR introduces no deployment manifests, pod scheduling constraints, affinity rules, or topology dependencies. Changes are TLS refactoring and PKI configuration only.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes found: no init() functions, no module-level fmt/log/klog prints, all logging inside functions only, no Ginkgo suite setup with stdout.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No Ginkgo e2e tests were added in this PR. All 8 test files use Go's standard testing package and table-driven unit tests, not Ginkgo framework.
No-Weak-Crypto ✅ Passed SHA1 found only in X.509 SubjectKeyIdentifier generation (RFC 5280 standard). No MD5, DES, RC4, 3DES, Blowfish, ECB, custom crypto, or insecure secret comparisons detected.
Container-Privileges ✅ Passed No Kubernetes container or pod manifests with privileged configurations found. PR contains only TLS/PKI configuration refactoring with no container security context definitions.
No-Sensitive-Data-In-Logs ✅ Passed All logging in the PR only logs error messages at DEBUG level, never exposing certificate/key data, passwords, tokens, API keys, PII, or other sensitive information.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 3, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign barbacbd for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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 on lines +5087 to +5092
pki:
description: |-
PKI configures cryptographic parameters for installer-generated
signer certificates. When specified, all signer certificates use the
algorithm and parameters from signerCertificates.
Feature gated by ConfigurablePKI.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Don't publish spec.pki as active before signer generation consumes it.

This schema says all installer-generated signer certificates use signerCertificates, but the supplied PR context says signer wiring is still deferred and current behavior remains RSA-2048 via nil PKI config. That makes the CRD/oc explain contract misleading for anyone enabling ConfigurablePKI. Either hold this field until the follow-up lands, or soften the description so it does not claim behavior that is not implemented yet.

🤖 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 `@data/data/install.openshift.io_installconfigs.yaml` around lines 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.

Comment on lines +12 to +116
func ValidatePKIConfig(pkiConfig *types.PKIConfig, fldPath *field.Path, fips bool) field.ErrorList {
allErrs := field.ErrorList{}

if pkiConfig == nil {
return allErrs
}

// signerCertificates.key must be fully specified when pki is present
if pkiConfig.SignerCertificates.Key.Algorithm == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("signerCertificates", "key"),
"signerCertificates.key is required when pki is specified"))
return allErrs
}

allErrs = append(allErrs, ValidateKeyConfig(pkiConfig.SignerCertificates.Key,
fldPath.Child("signerCertificates", "key"), fips)...)

return allErrs
}

// ValidateKeyConfig validates the KeyConfig structure.
// KeyConfig fields are value types: RSA is RSAKeyConfig, ECDSA is ECDSAKeyConfig.
// Use zero-value checks (KeySize == 0, Curve == "") instead of nil checks.
func ValidateKeyConfig(config types.KeyConfig, fldPath *field.Path, fips bool) field.ErrorList {
allErrs := field.ErrorList{}

if config.Algorithm == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("algorithm"),
"algorithm must be specified"))
return allErrs
}

if config.Algorithm != types.KeyAlgorithmRSA && config.Algorithm != types.KeyAlgorithmECDSA {
allErrs = append(allErrs, field.NotSupported(fldPath.Child("algorithm"),
config.Algorithm, []string{string(types.KeyAlgorithmRSA), string(types.KeyAlgorithmECDSA)}))
return allErrs
}

if config.Algorithm == types.KeyAlgorithmRSA {
if config.RSA.KeySize == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("rsa", "keySize"),
"keySize must be specified when algorithm is RSA"))
} else {
allErrs = append(allErrs, validateRSAKeyConfig(config.RSA, fldPath.Child("rsa"), fips)...)
}

if config.ECDSA.Curve != "" {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("ecdsa"),
"ecdsa must not be set when algorithm is RSA"))
}
}

if config.Algorithm == types.KeyAlgorithmECDSA {
if config.ECDSA.Curve == "" {
allErrs = append(allErrs, field.Required(fldPath.Child("ecdsa", "curve"),
"curve must be specified when algorithm is ECDSA"))
} else {
allErrs = append(allErrs, validateECDSAKeyConfig(config.ECDSA, fldPath.Child("ecdsa"), fips)...)
}

if config.RSA.KeySize != 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("rsa"),
"rsa must not be set when algorithm is ECDSA"))
}
}

return allErrs
}

func validateRSAKeyConfig(config types.RSAKeyConfig, fldPath *field.Path, fips bool) field.ErrorList {
allErrs := field.ErrorList{}

// Validate key size — aligned with API kubebuilder validation:
// multiples of 1024 from 2048 to 8192
if config.KeySize < 2048 || config.KeySize > 8192 || config.KeySize%1024 != 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("keySize"), config.KeySize,
"must be a multiple of 1024 from 2048 to 8192"))
}

return allErrs
}

func validateECDSAKeyConfig(config types.ECDSAKeyConfig, fldPath *field.Path, fips bool) field.ErrorList {
allErrs := field.ErrorList{}

validCurves := []types.ECDSACurve{
types.ECDSACurveP256,
types.ECDSACurveP384,
types.ECDSACurveP521,
}
valid := false
for _, curve := range validCurves {
if config.Curve == curve {
valid = true
break
}
}

if !valid {
allErrs = append(allErrs, field.Invalid(fldPath.Child("curve"), config.Curve,
"must be P256, P384, or P521"))
}

return allErrs
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm fips is never read inside the validators and check callers' intent
rg -nP --type=go -C2 '\bfips\b' pkg/types/pki/validation.go
rg -nP --type=go -C3 'Validate(PKIConfig|KeyConfig)\s*\(' --glob '!**/validation.go'

Repository: openshift/installer

Length of output: 3756


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Show every occurrence of `fips` in the PKI validator file
rg -n --type=go '\bfips\b' pkg/types/pki/validation.go

# 2) Check whether tests assert any FIPS-specific behavior
rg -n --type=go '\bfips\b' pkg/types/pki/validation_test.go

# 3) Inspect where `c.FIPS` is sourced/used in installconfig validation
sed -n '250,330p' pkg/types/validation/installconfig.go

Repository: openshift/installer

Length of output: 4483


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search all PKI validation code for any actual usage of `fips`
rg -n --type=go '\bfips\b' pkg/types/pki -g'*.go'

# In this specific file, check whether `fips` is referenced in any expressions (if/for/return/etc.)
rg -n --type=go 'fips\s*($|[)\],.;:])|if\s*\(.*\bfips\b|switch\s*\(.*\bfips\b|\bfips\b\s*(==|!=|<=|>=|<|>|\{|\!)' pkg/types/pki/validation.go

Repository: openshift/installer

Length of output: 1513


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Simple checks: does `validation.go` contain any comparison/if/switch using `fips`?
rg -n --type=go 'if\s*\(.*\bfips\b|switch\s*\(.*\bfips\b|^\s*case\s+.*\bfips\b|\bfips\b\s*(==|!=|<|<=|>|>=)\s*' pkg/types/pki/validation.go || true
rg -n --type=go '\bfips\b' pkg/types/pki/validation.go

# 2) Check whether lint script enables revive/unparam/unuedparam-style checks
sed -n '1,200p' hack/go-lint.sh 2>/dev/null || true
rg -n 'revive|unparam|unusedparam|parameter' hack -S || true

Repository: openshift/installer

Length of output: 1113


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for revive/unparam/unused parameter linters in the golangci-lint config
rg -n --hidden --no-ignore-vcs '(revive|unparam|unusedparam|unuedparam|gocritic.*(unparam|unused)|stylecheck|U1000|unused|dupl|ineffassign)' .golangci-lint-v2.yaml

# Show the relevant enabled-linters section(s) if present
rg -n --hidden --no-ignore-vcs 'enabled-linters|disabled-linters|linters:' .golangci-lint-v2.yaml

Repository: openshift/installer

Length of output: 157


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,130p' .golangci-lint-v2.yaml

Repository: openshift/installer

Length of output: 2658


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Focus on revive + any parameter/unused-related linters in the config
sed -n '1,220p' .golangci-lint-v2.yaml

Repository: openshift/installer

Length of output: 2872


🏁 Script executed:

rg -n 'unparam|unusedparam|U1000' .golangci-lint-v2.yaml

Repository: openshift/installer

Length of output: 45


🏁 Script executed:

rg -n --type=go '\bfips\b' pkg/types | head -n 50

Repository: openshift/installer

Length of output: 1533


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n --type=go '\bfips\b' pkg/types | head -n 50

Repository: openshift/installer

Length of output: 1533


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1500,1560p' pkg/types/validation/installconfig.go

Repository: openshift/installer

Length of output: 2745


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,160p' pkg/types/pki/validation_test.go

Repository: openshift/installer

Length of output: 3660


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '160,340p' pkg/types/pki/validation_test.go

Repository: openshift/installer

Length of output: 2512


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1510,1555p' pkg/types/validation/installconfig.go

Repository: openshift/installer

Length of output: 2036


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '1,160p' pkg/types/pki/validation_test.go

Repository: openshift/installer

Length of output: 3660


🏁 Script executed:

#!/bin/bash
set -euo pipefail
sed -n '160,340p' pkg/types/pki/validation_test.go

Repository: openshift/installer

Length of output: 2512


Apply fips to PKI signer-key validation (or remove it)

pkg/types/pki/validation.go threads the fips flag through ValidatePKIConfigValidateKeyConfigvalidateRSAKeyConfig/validateECDSAKeyConfig, but never uses it to change any validation behavior. pkg/types/pki/validation_test.go also exercises tc.fips without asserting any FIPS-specific differences.

  • Implement the intended FIPS-mode restrictions for PKI signer key parameters, or drop the fips parameter from these validators until it’s needed.
🤖 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.go` around lines 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.

Comment thread pkg/types/validation/installconfig_test.go
@hasbro17
Copy link
Copy Markdown
Contributor Author

hasbro17 commented Jun 3, 2026

/hold

Depends on #10593

hasbro17 added 2 commits June 4, 2026 12:46
Add the configurable PKI API surface to InstallConfig behind the
ConfigurablePKI feature gate. When the gate is active, the installer
generates a config.openshift.io/v1alpha1 PKI custom resource manifest
that day-2 operators use for certificate rotation parameters.

The default PKI profile uses RSA-4096 until all day-2 operators (CKAO,
CKMO, etc.) support ECDSA rotation. When pki is not specified in
install-config the PKI CR uses mode: Default. When pki is specified the
PKI CR uses mode: Custom with DefaultPKIProfile as the base and user
signerCertificates overrides layered on top.

No certificate generation changes are included — all certs remain
RSA-2048. Non-TechPreview clusters are completely unaffected.

Assisted-by: Claude Code (Opus 4.6)
Refactor 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, and
GenerateSelfSignedCertificate accepts PrivateKeyParams to control key
generation. KeyUsage flags are set based on the algorithm since ECDSA
keys cannot perform key encipherment.

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).

Assisted-by: Claude Code (Opus 4.6)
@hasbro17 hasbro17 force-pushed the pki-2-tls-refactor branch from ed2ed81 to cb0bd95 Compare June 4, 2026 19:58
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 5, 2026

@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 cb0bd95 link false /test e2e-metal-single-node-live-iso
ci/prow/e2e-metal-ovn-two-node-fencing cb0bd95 link false /test e2e-metal-ovn-two-node-fencing
ci/prow/verify-deps cb0bd95 link true /test verify-deps

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants