Skip to content

CNTRLPLANE-2012: Add configurable PKI support for installer-generated signer certificates#10396

Open
hasbro17 wants to merge 6 commits intoopenshift:mainfrom
hasbro17:install-config-pki
Open

CNTRLPLANE-2012: Add configurable PKI support for installer-generated signer certificates#10396
hasbro17 wants to merge 6 commits intoopenshift:mainfrom
hasbro17:install-config-pki

Conversation

@hasbro17
Copy link
Copy Markdown
Contributor

@hasbro17 hasbro17 commented Mar 16, 2026

Overview:
Currently, the OpenShift installer hard-codes all signer certificates to use RSA 2048-bit keys.
This PR adds configurable PKI support to the installer, allowing users to specify cryptographic parameters for the 11 installer-generated signer certificates via a new pki field in the InstallConfig. The
feature is gated behind ConfigurablePKI (TechPreviewNoUpgrade/DevPreviewNoUpgrade).

When ConfigurablePKI is enabled and pki is omitted, signer certificates default to ECDSA P-384 (matching the DefaultPKIProfile from library-go).
When the feature gate is disabled, behavior is unchanged (RSA 2048).

Example usage in install-config.yaml:

featureSet: TechPreviewNoUpgrade
pki:
  signerCertificates:
    key:
      algorithm: ECDSA
      ecdsa:
        curve: P384

Key changes:

  • Define custom PKI *types.PKIConfig field on InstallConfig exposing only signerCertificates, reusing vendored sub-types from openshift/api (PR CNTRLPLANE-1752: Add PKI API to config.openshift.io/v1alpha1 api#2645)
  • Register ConfigurablePKI feature gate check in GatedFeatures()
  • Validate PKI config (algorithm/params matching, key size range, curve validity) via ValidatePKIConfig()
  • Refactor pkg/asset/tls/ to support both RSA and ECDSA key generation with algorithm-appropriate KeyUsage flags
  • Update PrivateKeyToPem() to return ([]byte, error) and handle both RSA and ECDSA key formats
  • All 11 signer certificate assets use EffectiveSignerPKIConfig() to determine key parameters
  • Generate a config.openshift.io/v1alpha1 PKI CR manifest (cluster-pki-02-config.yaml) when ConfigurablePKI is enabled, with DefaultPKIProfile defaults and user overrides
  • Leaf certificates (signed by these CAs) continue using RSA 2048 — unaffected by PKI config

TODO:

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Mar 16, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Mar 16, 2026

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

Details

In response to this:

See PKI config enhancement openshift/enhancements#1882 for background

Overview:
Currently, the OpenShift installer hard-codes all signer certificates to use RSA 2048-bit keys.
This PR adds configurable PKI support to the installer, allowing users to specify cryptographic parameters for the 10 installer-generated signer certificates via a new pki field in the InstallConfig. The
feature is gated behind ConfigurablePKI (TechPreviewNoUpgrade/DevPreviewNoUpgrade).

Example usage in install-config.yaml:

 featureSet: TechPreviewNoUpgrade
 pki:
   signerCertificates:
     key:
       algorithm: ECDSA
       ecdsa:
         curve: P384

Key changes:

  • Add PKI *configv1alpha1.PKIProfile field to InstallConfig, using the official type from openshift/api (PR CNTRLPLANE-1752: Add PKI API to config.openshift.io/v1alpha1 api#2645)
  • Register ConfigurablePKI feature gate check in GatedFeatures()
  • Validate PKI config (algorithm/params matching, key size range, curve validity) via ValidatePKIProfile()
  • Refactor pkg/asset/tls/ to support both RSA and ECDSA key generation with algorithm-appropriate KeyUsage flags
  • Update SelfSignedCertKey.Generate() to accept a pkiProfile parameter
  • Update PemToPrivateKey()/PrivateKeyToPem() to handle both RSA and ECDSA key formats
  • All 10 signer certificate assets now depend on InstallConfig and pass PKI config to key generation
  • Leaf certificates (signed by these CAs) continue using RSA 2048 — unaffected by PKI config

TODO:

  • Day-2 PKI Resource: Create cluster PKI resource that persists the effective config specified in the InstallConfig
  • Validate with e2e test in origin/release that installs a cluster with ConfigurablePKI featuregate enabled and verifies the signer certs and PKI resource

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.

@hasbro17 hasbro17 changed the title CNTRLPLANE-2012: Add configurable PKI support for installer-generated signer certificates WIP: CNTRLPLANE-2012: Add configurable PKI support for installer-generated signer certificates Mar 16, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 16, 2026

Walkthrough

Adds feature-gated configurable PKI: new InstallConfig pki field and CRD schema, PKI types, defaults, and validation; generates a PKI manifest asset when enabled; refactors TLS/key generation to support RSA and ECDSA, generalizes PEM helpers, and updates tests accordingly.

Changes

Cohort / File(s) Summary
CRD Schema & Docs
data/data/install.openshift.io_installconfigs.yaml, docs/user/customization.md
Adds top-level pki schema to InstallConfig CRD and documents pki.signerCertificates.key with algorithm enum, RSA key-size and ECDSA curve constraints, examples, and feature-gate behavior.
InstallConfig Types & DeepCopy
pkg/types/installconfig.go, pkg/types/zz_generated.deepcopy.go
Adds PKI *PKIConfig to InstallConfig, defines PKI/Key/RSA/ECDSA types and enums, and updates deepcopy generation to copy PKI.
PKI Defaults & Resolution
pkg/types/pki/defaults.go, pkg/types/pki/defaults_test.go
Introduces DefaultPKIProfile() and EffectiveSignerPKIConfig(...) to provide defaults and derive effective signer PKI based on feature gate and InstallConfig.
PKI Validation & Tests
pkg/types/pki/validation.go, pkg/types/pki/validation_test.go, pkg/types/validation/featuregates.go
Adds validators for PKI/Key config enforcing algorithm presence, RSA/ECDSA-specific requirements, RSA key-size constraints, ECDSA curve enum, and wiring to the ConfigurablePKI feature gate.
InstallConfig Validation Integration & Tests
pkg/types/validation/installconfig.go, pkg/types/validation/installconfig_test.go, pkg/types/validation/featuregate_test.go
Integrates PKI validation into InstallConfig validation and adds test cases for gated/ungated scenarios and invalid PKI inputs.
PKI Manifest Asset & Integration
pkg/asset/manifests/pki.go, pkg/asset/manifests/pki_test.go, pkg/asset/manifests/operators.go
Adds PKIConfiguration asset that emits manifests/cluster-pki-02-config.yaml (config/v1alpha1 PKI CR) when feature gate enabled and integrates it into manifests generation.
TLS Core Refactor
pkg/asset/tls/tls.go, pkg/asset/tls/tls_test.go
Generalizes key/cert generation to support algorithm-parameterized keys (PrivateKeyParams), accept crypto.PrivateKey/crypto.Signer, algorithm-driven KeyUsage/signature selection, and adds extensive tests for RSA/ECDSA behavior.
PEM & Key Utilities + Tests
pkg/asset/tls/utils.go, pkg/asset/tls/utils_test.go
Generalizes PEM helpers to accept/return crypto.PrivateKey, support RSA and ECDSA PEM formats, return errors, and adds round-trip and format tests.
Cert-Key Flows & Tests
pkg/asset/tls/certkey.go, pkg/asset/tls/certkey_test.go, pkg/asset/tls/keypair.go
Updates SelfSigned/Signed cert flows to take PKI params, generalizes private-key handling, adds error handling for PEM encoding, and adds tests including cross-algorithm signing.
Signer Assets Updated
pkg/asset/tls/root.go, pkg/asset/tls/apiserver.go, pkg/asset/tls/kubelet.go, pkg/asset/tls/kubecontrolplane.go, pkg/asset/tls/aggregator.go, pkg/asset/tls/adminkubeconfig.go, pkg/asset/tls/ironictls.go
Most signer assets now depend on installconfig.InstallConfig, obtain effective signer PKI, pass it into SelfSignedCertKey.Generate, and stop setting KeyUsages explicitly.
Key Parsing & Enforcement
pkg/asset/tls/utils.go, pkg/asset/tls/boundsasigningkey.go
PemToPrivateKey/PrivateKeyToPem generalized for multiple key types; bound service-account signing key still enforces RSA and errors if not RSA.
Machine Ignition Tests
pkg/asset/ignition/machine/..._test.go
Updated multiple machine ignition tests to pass populated parent sets (including installConfig) into RootCA generation so PKI defaults/config are available.
Manifest/TLS Consumers Error Handling
pkg/asset/imagebased/configimage/ingressoperatorsigner.go, pkg/asset/tls/keypair.go, pkg/asset/manifests/...
Adds PEM-encoding error propagation and handling where private-key PEM encoding previously ignored errors.
PKI Conversion Helper
pkg/types/pki/conversion.go
Adds conversion from local CertificateConfig to upstream configv1alpha1.CertificateConfig.
Explain & Misc
pkg/explain/printer_test.go, pkg/types/defaults/installconfig.go
Updates expected schema printer output to include pki and a minor trailing newline change in defaults file.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

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

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 openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Mar 16, 2026
@openshift-ci openshift-ci Bot requested review from andfasano and tthvo March 16, 2026 20:15
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Mar 16, 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 dtantsur 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

@hasbro17
Copy link
Copy Markdown
Contributor Author

The unit tests cover the following areas but add quite a bit of volume to this PR:

  • PKI helpers
  • PKI validation (valid/invalid RSA, ECDSA, mismatches)
  • Key generation (RSA/ECDSA), KeyUsage flags, signature algorithm auto-detection
  • PEM encode/decode roundtrip (RSA + ECDSA)
  • Validation integration in ValidateInstallConfig
  • ConfigurablePKI feature gate (TechPreview, CustomNoUpgrade, disabled)
  • SelfSignedCertKey.Generate() with PKI profiles
  • Cross-algorithm signing (ECDSA CA → RSA leaf, cert chain verification)

I've split most of the unit tests into their own commit, and looking at the actual PKI integration and TLS changes commit-wise would make it easier to review

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: 7

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

57-89: Add a PKCS#8 case for the new parser branch.

PemToPrivateKey now has a "PRIVATE KEY" path in pkg/asset/tls/utils.go, but this suite still only exercises PKCS#1 and EC blocks. One PKCS#8 RSA/ECDSA case would keep that branch from regressing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/asset/tls/utils_test.go` around lines 57 - 89, Test suite is missing a
PKCS#8 ("PRIVATE KEY") case for the new PemToPrivateKey branch; add a subtest
that takes an RSA or ECDSA private key (use GenerateRSAPrivateKey or
GenerateECDSAPrivateKey), marshal it with x509.MarshalPKCS8PrivateKey to produce
PKCS#8 bytes, wrap those bytes in a PEM block labeled "PRIVATE KEY" (similar to
PrivateKeyToPem), feed that PEM to PemToPrivateKey and assert no error and that
the returned value is the expected *rsa.PrivateKey or *ecdsa.PrivateKey type so
the PKCS#8 branch is exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@data/data/install.openshift.io_installconfigs.yaml`:
- Around line 4898-4899: The schema currently requires pki.defaults but the spec
states it is auto-populated; update the YAML schema so pki.defaults is optional
(remove it from any required[] lists or mark it nullable/optional in the pki
object definition) and ensure the pki object still allows a signerCertificates
override without defaults present; apply the same change where pki.defaults is
similarly enforced (the other occurrence referenced) and update the pki.defaults
description to note it is auto-populated when omitted.
- Around line 4902-5152: The schema exposes clientCertificates,
servingCertificates, and defaults as general PKI overrides but the installer
only applies them to installer-generated signer certs—remove or hide these
fields (clientCertificates, servingCertificates, defaults) from the
InstallConfig schema in install.openshift.io_installconfigs.yaml so the API does
not promise unsupported overrides; alternatively, if you must keep them for
compatibility, update their descriptions to explicitly state they only affect
installer-generated signer certificates and add a schema marker (e.g.,
x-kubernetes-hidden or a clear deprecation note) so callers are not misled.
Ensure you update the definitions and any x-kubernetes-validations that
reference these symbols (clientCertificates, servingCertificates, defaults) so
the schema and documentation consistently reflect the limited scope.

In `@docs/user/customization.md`:
- Around line 57-66: The docs currently mention that `defaults` is
auto-populated but never documents `defaults.key`, causing confusion about
whether `defaults.key` is a user-supplied field or internal-only; update the
`pki` section to either (A) document `defaults.key` under `signerCertificates`
(describe its shape and allowed subfields `key.algorithm`, `key.rsa.keySize`,
`key.ecdsa.curve`, valid values and whether it may be provided by users), or (B)
remove/clarify the statement that `defaults` is auto-populated and stop
referring to `defaults.key` as if it were user-configurable; reference `pki`,
`signerCertificates`, and `defaults.key` when making the change.

In `@pkg/asset/tls/tls.go`:
- Around line 266-273: The current code clobbers any caller-set cfg.KeyUsages by
replacing adjustedCfg.KeyUsages with baseUsage; instead preserve caller bits:
compute baseUsage := keyUsageForAlgorithm(params.Algorithm) and then set
adjustedCfg.KeyUsages = cfg.KeyUsages | baseUsage (and if cfg.IsCA also OR
x509.KeyUsageCertSign) so existing explicit bits on cfg.KeyUsages remain honored
while still applying the algorithm-derived and CA bits.

In `@pkg/asset/tls/utils.go`:
- Around line 86-95: The PKCS#8 branch currently calls x509.ParsePKCS8PrivateKey
which can return key types other than RSA/ECDSA and those will later break
PrivateKeyToPem and generateSubjectKeyID; change the "PRIVATE KEY" case
(x509.ParsePKCS8PrivateKey) to assert the returned key is either *rsa.PrivateKey
or *ecdsa.PrivateKey and return an explicit error for any other types so
unsupported PKCS#8 keys are rejected at decode time (refer to the "PRIVATE KEY"
case, x509.ParsePKCS8PrivateKey, and the downstream uses PrivateKeyToPem and
generateSubjectKeyID).

In `@pkg/types/pki/validation.go`:
- Around line 19-23: The current guard in the signer key validation (using
profile.SignerCertificates.Key.Algorithm != "") lets partial key configs (e.g.,
rsa.keySize or ecdsa.curve) skip validation and be silently ignored; change the
check so ValidateKeyConfig is invoked whenever the Key block is non-empty (i.e.,
any of Key.Algorithm, Key.KeySize, Key.Curve or other key fields are set) rather
than only when Algorithm is set, and make the same non-empty-key detection
change in GetEffectiveSignerKeyConfig so fallback/default merging is validated
correctly; add regression tests covering partial defaults and partial
signerCertificates.key inputs to ensure these are validated.

In `@pkg/types/validation/installconfig.go`:
- Around line 284-286: The PKI profile validation call in ValidatePKIProfile
(invoked from install-config validation when c.PKI != nil) currently only checks
profile.SignerCertificates.Key and therefore misses validating pki.defaults.key;
update pkivalidation.ValidatePKIProfile to explicitly validate the defaults.key
field (and any related key fields under profile.Defaults) using the same key
validation logic as for SignerCertificates.Key so invalid default keys fail fast
during install-config validation rather than later during certificate
generation.

---

Nitpick comments:
In `@pkg/asset/tls/utils_test.go`:
- Around line 57-89: Test suite is missing a PKCS#8 ("PRIVATE KEY") case for the
new PemToPrivateKey branch; add a subtest that takes an RSA or ECDSA private key
(use GenerateRSAPrivateKey or GenerateECDSAPrivateKey), marshal it with
x509.MarshalPKCS8PrivateKey to produce PKCS#8 bytes, wrap those bytes in a PEM
block labeled "PRIVATE KEY" (similar to PrivateKeyToPem), feed that PEM to
PemToPrivateKey and assert no error and that the returned value is the expected
*rsa.PrivateKey or *ecdsa.PrivateKey type so the PKCS#8 branch is exercised.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f0fc8704-7ecb-42db-a25a-ef8fbe0e10af

📥 Commits

Reviewing files that changed from the base of the PR and between 3528292 and dfa87a6.

📒 Files selected for processing (34)
  • data/data/install.openshift.io_installconfigs.yaml
  • docs/user/customization.md
  • pkg/asset/ignition/machine/arbiter_ignition_customizations_test.go
  • pkg/asset/ignition/machine/arbiter_test.go
  • pkg/asset/ignition/machine/master_ignition_customizations_test.go
  • pkg/asset/ignition/machine/master_test.go
  • pkg/asset/ignition/machine/worker_ignition_customizations_test.go
  • pkg/asset/ignition/machine/worker_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/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/types/defaults/installconfig.go
  • pkg/types/defaults/installconfig_test.go
  • pkg/types/defaults/validation/featuregates.go
  • pkg/types/installconfig.go
  • pkg/types/pki/helpers.go
  • pkg/types/pki/helpers_test.go
  • pkg/types/pki/validation.go
  • pkg/types/pki/validation_test.go
  • pkg/types/validation/featuregate_test.go
  • pkg/types/validation/installconfig.go
  • pkg/types/validation/installconfig_test.go
  • pkg/types/zz_generated.deepcopy.go

Comment thread data/data/install.openshift.io_installconfigs.yaml Outdated
Comment thread data/data/install.openshift.io_installconfigs.yaml Outdated
Comment thread docs/user/customization.md
Comment thread pkg/asset/tls/tls.go
Comment thread pkg/asset/tls/utils.go
Comment thread pkg/types/pki/validation.go Outdated
Comment thread pkg/types/validation/installconfig.go
@hasbro17
Copy link
Copy Markdown
Contributor Author

/test ?

@hasbro17
Copy link
Copy Markdown
Contributor Author

/test e2e-aws-ovn-techpreview
/test e2e-gcp-ovn-techpreview

@hasbro17 hasbro17 force-pushed the install-config-pki branch from dfa87a6 to 71dcced Compare March 17, 2026 20:24
@hasbro17
Copy link
Copy Markdown
Contributor Author

/test e2e-aws-ovn-techpreview
/test e2e-gcp-ovn-techpreview

@hasbro17 hasbro17 force-pushed the install-config-pki branch from 71dcced to d792394 Compare March 18, 2026 20:00
@hasbro17
Copy link
Copy Markdown
Contributor Author

/retest-required

@hasbro17
Copy link
Copy Markdown
Contributor Author

/test e2e-aws-ovn-techpreview
/test e2e-gcp-ovn-techpreview

@hasbro17
Copy link
Copy Markdown
Contributor Author

/retest-required
/test e2e-aws-ovn-techpreview
/test e2e-gcp-ovn-techpreview

Comment thread docs/user/customization.md
@hasbro17
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 23, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

♻️ Duplicate comments (1)
data/data/install.openshift.io_installconfigs.yaml (1)

4946-4949: ⚠️ Potential issue | 🟠 Major

Remove stale defaults/overrides wording from the schema description.

Line 4949 says key settings can come from “defaults” in an “overrides entry”, but this InstallConfig schema only exposes pki.signerCertificates. That description now documents behavior users cannot configure and can mislead API consumers.

Suggested doc fix
                   key:
                     description: |-
                       key specifies the cryptographic parameters for the certificate's key pair.
-                      Currently this is the only configurable parameter. When omitted in an
-                      overrides entry, the key configuration from defaults is used.
+                      Currently this is the only configurable parameter for signer certificates.

As per coding guidelines, "Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@data/data/install.openshift.io_installconfigs.yaml` around lines 4946 - 4949,
Update the schema description for the "key" entry under pki.signerCertificates
to remove the stale references to "defaults" and "overrides" and instead
describe the actual configurable surface (i.e., that only the key cryptographic
parameters for the certificate's key pair are configurable via
pki.signerCertificates). Locate the block containing the description text that
mentions "defaults" and "overrides" and replace that wording with a concise
sentence stating that the schema exposes configuration of the certificate key
parameters via pki.signerCertificates and that if omitted, the signer
certificate uses its built-in/default key configuration (do not mention
non-existent overrides mechanism).
🧹 Nitpick comments (3)
pkg/asset/tls/utils_test.go (1)

57-89: Add PKCS#8 coverage for PemToPrivateKey.

pkg/asset/tls/utils.go now has a "PRIVATE KEY" branch, and pkg/asset/tls/boundsasigningkey.go routes user-provided keys through it. These tests only exercise PKCS#1 and SEC1 PEM, so that compatibility path can regress unnoticed.

🧪 Suggested test addition
 import (
 	"crypto/ecdsa"
 	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
 	"testing"
@@
 func TestPemToPrivateKeyFormats(t *testing.T) {
@@
 	t.Run("EC PEM block", func(t *testing.T) {
 		key, err := GenerateECDSAPrivateKey(configv1alpha1.ECDSACurveP256)
 		assert.NoError(t, err)
 		pemBytes := PrivateKeyToPem(key)
 
 		decoded, err := PemToPrivateKey(pemBytes)
 		assert.NoError(t, err)
 		_, ok := decoded.(*ecdsa.PrivateKey)
 		assert.True(t, ok, "expected *ecdsa.PrivateKey")
 	})
+
+	t.Run("PKCS#8 RSA PEM block", func(t *testing.T) {
+		key, err := GenerateRSAPrivateKey(2048)
+		assert.NoError(t, err)
+		der, err := x509.MarshalPKCS8PrivateKey(key)
+		assert.NoError(t, err)
+		pemBytes := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: der})
+
+		decoded, err := PemToPrivateKey(pemBytes)
+		assert.NoError(t, err)
+		assert.IsType(t, &rsa.PrivateKey{}, decoded)
+	})
+
+	t.Run("PKCS#8 EC PEM block", func(t *testing.T) {
+		key, err := GenerateECDSAPrivateKey(configv1alpha1.ECDSACurveP256)
+		assert.NoError(t, err)
+		der, err := x509.MarshalPKCS8PrivateKey(key)
+		assert.NoError(t, err)
+		pemBytes := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: der})
+
+		decoded, err := PemToPrivateKey(pemBytes)
+		assert.NoError(t, err)
+		assert.IsType(t, &ecdsa.PrivateKey{}, decoded)
+	})
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/asset/tls/utils_test.go` around lines 57 - 89, Tests for PemToPrivateKey
only cover PKCS#1/SEC1 formats; add a test that encodes both RSA and ECDSA
private keys as PKCS#8 ("PRIVATE KEY") PEM blocks and asserts PemToPrivateKey
correctly decodes them to *rsa.PrivateKey and *ecdsa.PrivateKey respectively
(reuse GenerateRSAPrivateKey, GenerateECDSAPrivateKey and PrivateKeyToPem
helpers or produce PKCS#8 PEM for those keys), so the "PRIVATE KEY" branch
exercised by boundsasigningkey.go is covered. Ensure the test cases mirror
existing patterns (error cases + decoding assertions) and use the same function
names PemToPrivateKey, GenerateRSAPrivateKey, GenerateECDSAPrivateKey,
PrivateKeyToPem to locate insertion points.
pkg/asset/tls/certkey_test.go (2)

199-202: Also pin the leaf RSA size here.

The PR keeps leaf certificates at RSA-2048, but this only checks *rsa.PrivateKey. A different RSA size would still pass.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/asset/tls/certkey_test.go` around lines 199 - 202, The test currently
only asserts the leaf key type from PemToPrivateKey(certKey.Key()) is
*rsa.PrivateKey; update it to also type-assert the returned leafKey to
*rsa.PrivateKey (after the existing assert) and assert its modulus bit-length
equals 2048 (e.g., check rsaKey.N.BitLen() == 2048) so the test pins the RSA
size used by SignedCertKey.

105-159: Assert the configured signer parameters, not just the algorithm family.

This still passes if RSA-4096 regresses to RSA-2048 or if P-384 regresses to a different ECDSA curve. Since this test is validating PKIConfig propagation, please assert the generated key size / curve too.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/asset/tls/certkey_test.go` around lines 105 - 159, Update
TestSelfSignedCertKeyGenerateWithPKIConfig to assert the concrete key parameters
from the generated private key in addition to algorithm: after calling
PemToPrivateKey(key) and the existing IsType/assertions, for the RSA case assert
the rsa.PrivateKey.Size()*8 or rsa.N.BitLen() equals 4096, and for the ECDSA
case assert the ecdsa.PrivateKey.Curve matches the expected curve (e.g.,
elliptic.P384()). These checks should be added directly in the subtest after key
is decoded (inside the t.Run callback) and reference the existing test helpers
and types (TestSelfSignedCertKeyGenerateWithPKIConfig, CertCfg,
SelfSignedCertKey.Generate, PemToPrivateKey) so the test fails if PKIConfig
key-size/curve isn’t propagated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/user/customization.md`:
- Around line 57-66: Update the pki docs to match the implemented defaults:
change the default signer key size from RSA-2048 to RSA-4096 when the
ConfigurablePKI feature gate is enabled and pki is omitted, and clarify that
when a top-level pki block is present the signerCertificates and its nested key
object are required (with algorithm required and rsa.keySize valid multiples of
1024 between 2048–8192); reference the ConfigurablePKI feature gate,
signerCertificates, key, algorithm and rsa.keySize symbols so the maintainer can
find the corresponding logic in defaults and tests.

In `@pkg/asset/tls/tls.go`:
- Around line 28-65: PKIConfigToKeyParams currently applies hardcoded defaults
(DefaultKeyAlgorithm/DefaultRSAKeySize) when pkiConfig is nil, which
duplicates/defaults signer key params here instead of in the PKI layer; remove
that nil-path defaulting so this helper only converts an already-resolved
config. Change PKIConfigToKeyParams to not return RSA-2048 for a nil
*types.PKIConfig — either require callers to pass a non-nil/resolved pkiConfig
or return the zero-value PrivateKeyParams when pkiConfig is nil — and update
callers to perform resolution using the PKI defaulting logic in the PKI layer
(pkg/types/pki/defaults.go / pkg/asset/manifests/pki.go). Ensure the conversion
still uses keyConfig := pkiConfig.SignerCertificates.Key and preserves the
switch on keyConfig.Algorithm (configv1alpha1.KeyAlgorithmRSA /
KeyAlgorithmECDSA) to populate RSAKeySize or ECDSACurve.

In `@pkg/asset/tls/utils.go`:
- Around line 15-38: The helper PrivateKeyToPem currently calls logrus.Fatalf on
marshal/unsupported-type errors which terminates the process; change its
signature to return ([]byte, error) instead of []byte, replace logrus.Fatalf
calls with returning wrapped errors (e.g., fmt.Errorf or errors.Wrap) for the
ECDSA marshal failure and unsupported key type, and return the PEM bytes with a
nil error on success; update all call sites that use PrivateKeyToPem (such as
pkg/asset/tls/certkey.go and pkg/asset/tls/keypair.go) to handle the returned
error and propagate it upward instead of relying on process exit.

---

Duplicate comments:
In `@data/data/install.openshift.io_installconfigs.yaml`:
- Around line 4946-4949: Update the schema description for the "key" entry under
pki.signerCertificates to remove the stale references to "defaults" and
"overrides" and instead describe the actual configurable surface (i.e., that
only the key cryptographic parameters for the certificate's key pair are
configurable via pki.signerCertificates). Locate the block containing the
description text that mentions "defaults" and "overrides" and replace that
wording with a concise sentence stating that the schema exposes configuration of
the certificate key parameters via pki.signerCertificates and that if omitted,
the signer certificate uses its built-in/default key configuration (do not
mention non-existent overrides mechanism).

---

Nitpick comments:
In `@pkg/asset/tls/certkey_test.go`:
- Around line 199-202: The test currently only asserts the leaf key type from
PemToPrivateKey(certKey.Key()) is *rsa.PrivateKey; update it to also type-assert
the returned leafKey to *rsa.PrivateKey (after the existing assert) and assert
its modulus bit-length equals 2048 (e.g., check rsaKey.N.BitLen() == 2048) so
the test pins the RSA size used by SignedCertKey.
- Around line 105-159: Update TestSelfSignedCertKeyGenerateWithPKIConfig to
assert the concrete key parameters from the generated private key in addition to
algorithm: after calling PemToPrivateKey(key) and the existing
IsType/assertions, for the RSA case assert the rsa.PrivateKey.Size()*8 or
rsa.N.BitLen() equals 4096, and for the ECDSA case assert the
ecdsa.PrivateKey.Curve matches the expected curve (e.g., elliptic.P384()). These
checks should be added directly in the subtest after key is decoded (inside the
t.Run callback) and reference the existing test helpers and types
(TestSelfSignedCertKeyGenerateWithPKIConfig, CertCfg,
SelfSignedCertKey.Generate, PemToPrivateKey) so the test fails if PKIConfig
key-size/curve isn’t propagated.

In `@pkg/asset/tls/utils_test.go`:
- Around line 57-89: Tests for PemToPrivateKey only cover PKCS#1/SEC1 formats;
add a test that encodes both RSA and ECDSA private keys as PKCS#8 ("PRIVATE
KEY") PEM blocks and asserts PemToPrivateKey correctly decodes them to
*rsa.PrivateKey and *ecdsa.PrivateKey respectively (reuse GenerateRSAPrivateKey,
GenerateECDSAPrivateKey and PrivateKeyToPem helpers or produce PKCS#8 PEM for
those keys), so the "PRIVATE KEY" branch exercised by boundsasigningkey.go is
covered. Ensure the test cases mirror existing patterns (error cases + decoding
assertions) and use the same function names PemToPrivateKey,
GenerateRSAPrivateKey, GenerateECDSAPrivateKey, PrivateKeyToPem to locate
insertion points.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 68544947-cf52-4b23-8a47-7d56e6024c29

📥 Commits

Reviewing files that changed from the base of the PR and between b4f5094 and d7b8103.

📒 Files selected for processing (37)
  • data/data/install.openshift.io_installconfigs.yaml
  • docs/user/customization.md
  • pkg/asset/ignition/machine/arbiter_ignition_customizations_test.go
  • pkg/asset/ignition/machine/arbiter_test.go
  • pkg/asset/ignition/machine/master_ignition_customizations_test.go
  • pkg/asset/ignition/machine/master_test.go
  • pkg/asset/ignition/machine/worker_ignition_customizations_test.go
  • pkg/asset/ignition/machine/worker_test.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/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/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
  • pkg/types/zz_generated.deepcopy.go

Comment thread docs/user/customization.md
Comment thread pkg/asset/tls/tls.go
Comment thread pkg/asset/tls/utils.go Outdated
Copy link
Copy Markdown
Contributor

@sanchezl sanchezl left a comment

Choose a reason for hiding this comment

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

N/A

@sanchezl
Copy link
Copy Markdown
Contributor

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

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Mar 24, 2026

@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-4.22-e2e-aws-ovn-techpreview

See details on https://pr-payload-tests.ci.openshift.org/runs/ci/1e48cc80-27b4-11f1-9131-75ee6cd16cdf-0

@hasbro17 hasbro17 force-pushed the install-config-pki branch from d7b8103 to 8596880 Compare March 24, 2026 20:10
Copy link
Copy Markdown
Contributor

@sanchezl sanchezl left a comment

Choose a reason for hiding this comment

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

N/A

@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented Mar 30, 2026

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

Details

In response to this:

Overview:
Currently, the OpenShift installer hard-codes all signer certificates to use RSA 2048-bit keys.
This PR adds configurable PKI support to the installer, allowing users to specify cryptographic parameters for the 11 installer-generated signer certificates via a new pki field in the InstallConfig. The
feature is gated behind ConfigurablePKI (TechPreviewNoUpgrade/DevPreviewNoUpgrade).

When ConfigurablePKI is enabled and pki is omitted, signer certificates default to ECDSA P-384 (matching the DefaultPKIProfile from
library-go
).
When the feature gate is disabled, behavior is unchanged (RSA 2048).

Example usage in install-config.yaml:

featureSet: TechPreviewNoUpgrade
pki:
  signerCertificates:
    key:
      algorithm: ECDSA
      ecdsa:
        curve: P384

Key changes:

  • Define custom PKI *types.PKIConfig field on InstallConfig exposing only signerCertificates, reusing vendored sub-types from openshift/api (PR CNTRLPLANE-1752: Add PKI API to config.openshift.io/v1alpha1 api#2645)
  • Register ConfigurablePKI feature gate check in GatedFeatures()
  • Validate PKI config (algorithm/params matching, key size range, curve validity) via ValidatePKIConfig()
  • Refactor pkg/asset/tls/ to support both RSA and ECDSA key generation with algorithm-appropriate KeyUsage flags
  • Update PrivateKeyToPem() to return ([]byte, error) and handle both RSA and ECDSA key formats
  • All 11 signer certificate assets use EffectiveSignerPKIConfig() to determine key parameters
  • Generate a config.openshift.io/v1alpha1 PKI CR manifest (cluster-pki-02-config.yaml) when ConfigurablePKI is enabled, with DefaultPKIProfile defaults and user overrides
  • Leaf certificates (signed by these CAs) continue using RSA 2048 — unaffected by PKI config

TODO:

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.

@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 Apr 9, 2026
@hasbro17
Copy link
Copy Markdown
Contributor Author

hasbro17 commented Apr 9, 2026

After letting claude analyze both artifact dumps

The kube-controller-manager-operator CertRotationController is crash-looping with:

  CertRotationController reconciliation failed: KubeControllerManager.operator.openshift.io "cluster"
  is invalid: [status.nodeStatuses[0].currentRevision: Invalid value: cannot be unset once set,
  status.nodeStatuses[1].currentRevision: Invalid value: cannot be unset once set,
  status.nodeStatuses[2].currentRevision: Invalid value: cannot be unset once set]
  
  The CertRotationController can't reconcile because it's trying to update the KubeControllerManager operator status and hitting a validation error:
  status.nodeStatuses[N].currentRevision: Invalid value: cannot be unset once set.

  This blocks the entire cert rotation pipeline — the csr-signer secret never gets created, which cascades to aggregator-client and kube-scheduler-client-cert-key never being created, which blocks the static pod
  installers, which blocks OAuth, which fails the bootstrap.

But then why is the RSA 4096 run passing/succeeding install?
https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_installer/10396/pull-ci-openshift-installer-main-e2e-aws-ovn-pki-rsa-techpreview/2042135215551287296

The cannot be unset once set status error is the blocker, and it's pre-existing. 
Both runs have it — 842 times in the ECDSA run vs 401 in the RSA run. This error prevents the CertRotationController from
  completing ANY reconciliation, which blocks cert secret creation (aggregator-client, csr-signer, kube-scheduler-client-cert-key), which blocks static pods, which fails bootstrap.

  There are zero ECDSA-specific errors. No x509 parsing failures, no "unsupported key type", no TLS handshake errors, no PEM parsing issues
  
  The RSA run recovers from the same deadlock; the ECDSA run doesn't. The difference could be timing-related — the CertRotationController can't reconcile until nodeStatuses[N].currentRevision is set, and that
  requires static pods to deploy, which requires the secrets that CertRotation creates. In the RSA run this chicken-and-egg situation resolves (possibly because bootstrap completes faster or the initial cert
  setup is subtly different); in the ECDSA run it doesn't.

Not quite sure if that's right. Seems pretty consistently failing but will check to see if this could be a flake.

@hasbro17
Copy link
Copy Markdown
Contributor Author

hasbro17 commented Apr 9, 2026

/test e2e-aws-ovn-pki-default-techpreview

@hasbro17
Copy link
Copy Markdown
Contributor Author

hasbro17 commented Apr 9, 2026

This might be the reason why the new default ECDSA signer presubmit is failing at install time:

library-go's signCertificate() calls x509.CreateCertificate() with the template that has SignatureAlgorithm: x509.SHA256WithRSA hardcoded. When the issuerKey is an ECDSA key, Go's
  x509.CreateCertificate will return an error because SHA256WithRSA is incompatible with an ECDSA signing key.

https://github.com/openshift/library-go/blob/c57da2bf57206193fc88724e436930b98cfafb61/pkg/crypto/crypto.go#L1067

  The flow in the operators:
  1. Operator reads the signer CA secret (our ECDSA P-384 key)
  2. Calls ca.SignCertificate(template, leafPubKey)
  3. SignCertificate calls signCertificate(template, requestKey, caCert, ca.Config.Key)
  4. Template has SignatureAlgorithm: x509.SHA256WithRSA
  5. x509.CreateCertificate(rand, template, issuer, leafPubKey, ecdsaCAKey) → error
  6. Leaf cert secret never gets created

  This also explains why there are no explicit ECDSA errors in the logs — the signCertificate error gets caught by the CertRotationController reconciliation, which then tries to update the operator status, hits
  the cannot be unset once set error, and reports THAT error instead. The original cert signing error is masked.

openshift/library-go#2127 and openshift/library-go#2145 are both merged but the actual operators (e.g kube-controller-manager-operator) haven't been updated to use that new path to auto-detect the signature algorithm from the CA's key
https://github.com/openshift/library-go/blob/c57da2bf57206193fc88724e436930b98cfafb61/pkg/crypto/cert_config.go#L109-L110

@hasbro17
Copy link
Copy Markdown
Contributor Author

So we have controller-manager and apiserver-operator updated
openshift/cluster-kube-apiserver-operator#2051
openshift/cluster-kube-controller-manager-operator#925

Let's see if the default PKI config case for ECDSA passes now.

@hasbro17
Copy link
Copy Markdown
Contributor Author

/test e2e-aws-ovn-pki-default-techpreview
/test e2e-aws-ovn-pki-rsa-techpreview

@hasbro17
Copy link
Copy Markdown
Contributor Author

Looks like an infra issue

 Error creating: pods "kube-apiserver-operator-769ff5b4b7-" is forbidden:
  autoscaling.openshift.io/ManagementCPUsOverride the cluster does not have any nodes

/test e2e-aws-ovn-pki-rsa-techpreview

@hasbro17
Copy link
Copy Markdown
Contributor Author

Same on this one
/test e2e-aws-ovn-pki-default-techpreview

@hasbro17
Copy link
Copy Markdown
Contributor Author

Techpreview jobs are broken
https://redhat.atlassian.net/browse/OCPBUGS-83533

@hasbro17
Copy link
Copy Markdown
Contributor Author

/test e2e-aws-ovn-techpreview

@hasbro17
Copy link
Copy Markdown
Contributor Author

/test e2e-aws-ovn-pki-default-techpreview
/test e2e-aws-ovn-pki-rsa-techpreview

@hasbro17
Copy link
Copy Markdown
Contributor Author

Okay promising that e2e-aws-ovn-pki-rsa-techpreview passed.
And e2e-aws-ovn-pki-default-techpreview for the ECDSA case all but passed since the test is outdated for my changes on setting the PKI CR mode to default now. Test expects custom which I'll need to update.


--- Checking PKI CR ---
  FAIL: Expected mode 'Custom', got 'Default'

=============================================
PKI Verification Summary
=============================================
STATUS | CHECK                                         | DETAIL
-------+-----------------------------------------------+-------
PASS   | root-ca                                       | openshift-machine-config-operator/machine-config-server-ca
PASS   | kube-apiserver-to-kubelet-signer              | openshift-kube-apiserver-operator/kube-apiserver-to-kubelet-signer
PASS   | kube-apiserver-localhost-signer               | openshift-kube-apiserver-operator/localhost-serving-signer
PASS   | kube-apiserver-service-network-signer         | openshift-kube-apiserver-operator/service-network-serving-signer
PASS   | kube-apiserver-lb-signer                      | openshift-kube-apiserver-operator/loadbalancer-serving-signer
PASS   | kube-control-plane-signer                     | openshift-kube-apiserver-operator/kube-control-plane-signer
PASS   | aggregator-signer                             | openshift-kube-apiserver-operator/aggregator-client-signer
FAIL   | PKI CR                                        | mode=Default

Total: 8, Passed: 7, Failed: 1
=============================================

But this PR should be in good shape to review again. Will iron out the remaining integration failures.

@hasbro17
Copy link
Copy Markdown
Contributor Author

Seeing a new linter issue now. Not sure why:
https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_installer/10396/pull-ci-openshift-installer-main-golint/2042129800130203648

level=info msg="[runner] linters took 2m16.615142394s with stages: goanalysis_metalinter: 1m6.548495703s"
pkg/asset/tls/utils_test.go:1:9: var-naming: avoid package names that conflict with Go standard library package names (revive)
package tls
        ^

The pkg/asset/tls package has been named tls since its creation, and all existing test files (tls_test.go, cabundle_test.go, certkey_test.go) use the same package tls declaration. The linter only flags our new
file because it's the only one in the diff. Renaming the package or switching to an external test package is out of scope for this feature PR.

@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 16, 2026
@hasbro17
Copy link
Copy Markdown
Contributor Author

hasbro17 commented Apr 16, 2026

Problem: Our TLS refactor added &installconfig.InstallConfig{} as a new dependency to signer certificates that previously had no dependencies. This breaks the agent create certificates command when
run without an install-config on disk.

The agent create certificates command (cmd/openshift-install/agent.go:118-132) is a hidden command used by set-node-zero.sh at runtime during UI-based agent installations (PR #9557). It runs inside a
container with an empty directory — no install-config present. When the asset store encounters the new InstallConfig dependency, it tries to generate one from scratch, which triggers the interactive platform
prompt, hits EOF, and fails.

Affected signer certificates — all four in agentCertificatesTarget had Dependencies() returning []asset.Asset{} on main, now return []asset.Asset{&installconfig.InstallConfig{}}:

  • KubeAPIServerLBSignerCertKey
  • KubeAPIServerLocalhostSignerCertKey
  • KubeAPIServerServiceNetworkSignerCertKey
  • AdminKubeConfigSignerCertKey

Exploring potential solutions on how we side step this issue without breaking agent create certificates.

@hasbro17 hasbro17 force-pushed the install-config-pki branch from c7403e2 to 68341be Compare April 16, 2026 21:41
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 16, 2026
@hasbro17
Copy link
Copy Markdown
Contributor Author

Fixed the create certificates cmd but there's other places where the dependency breaks the agent cmds.
E.g node-joiner add-nodes.

Will need a more comprehensive fix with an intermediate asset WritableAsset that wraps the InstallConfig lookup and skips if not present on disk to preserve the behavior of these cmds.

@hasbro17 hasbro17 force-pushed the install-config-pki branch from b0d099a to 0dbe7e4 Compare April 22, 2026 21:32
Add configurable PKI support to InstallConfig behind the ConfigurablePKI
feature gate, allowing users to specify cryptographic parameters for
installer-generated signer certificates.

PKI sub-types (CertificateConfig, KeyConfig, etc.) are defined locally
rather than reusing configv1alpha1 types, so that upstream field
additions don't silently expand the install-config API surface.
Conversion to upstream types happens at the manifest boundary.

Assisted-by: Claude Code (Opus 4.6)
Update pkg/asset/tls/ to generate signer certificates with either RSA
or ECDSA keys based on the PKI config from InstallConfig. Leaf
certificates continue to use RSA 2048.

KeyUsage flags are set based on the algorithm since ECDSA keys cannot
perform key encipherment. All signer assets now depend on InstallConfig
and pass PKI config through to key generation.

Assisted-by: Claude Code (Opus 4.6)
Add tests covering PKI validation, feature gate enforcement,
certificate generation with configurable PKI configs, cross-algorithm
certificate signing (ECDSA CA signing RSA leaf), and PEM
encode/decode roundtrips for both key types.

Assisted-by: Claude Code (Opus 4.6)
Document the configurable PKI feature in docs/user/customization.md,
following the existing inline documentation pattern for install-config
properties.

Key additions:
- Add pki field entry with nested signerCertificates structure
- Add RSA 4096 and ECDSA P-384 install-config example fragments
- Document ConfigurablePKI feature gate requirement
- Note scope: signer certificates only, leaf certs unaffected

Assisted-by: Claude Code (Opus 4.6)
…abled

When the ConfigurablePKI feature gate is active, the installer generates
a config.openshift.io/v1alpha1 PKI custom resource manifest that is
applied to the cluster during bootstrap. This CR provides day-2
operators with the certificate parameters to use when rotating
certificates.

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 overrides from
pki.signerCertificates layered on top.

When the feature gate is enabled but pki is not specified, the installer
also aligns its own signer cert generation to ECDSA P-384 (matching
DefaultPKIProfile) instead of the legacy RSA-2048 default.

Assisted-by: Claude Code (Opus 4.6)
…onfig

The TLS refactor for configurable PKI added InstallConfig as a
dependency to 4 signer certificates that previously had none. This
broke codepaths that generate signer certs without an install-config
on disk, such as `agent create certificates` (used by set-node-zero.sh
in UI-based agent installs) and `node-joiner add-nodes`.

Introduce a SignerKeyParams WritableAsset that wraps the InstallConfig
dependency. When no install-config is on disk, its Load() returns
defaults (nil PKIConfig = RSA-2048), short-circuiting the asset store
before it tries to generate InstallConfig interactively. When an
install-config is present, Generate() reads the actual PKI config.

Assisted-by: Claude Code (Opus 4.6)
@hasbro17
Copy link
Copy Markdown
Contributor Author

/retest-required

@hasbro17 hasbro17 force-pushed the install-config-pki branch from 0dbe7e4 to 200625a Compare April 23, 2026 06:23
@hasbro17
Copy link
Copy Markdown
Contributor Author

/test integration-tests-nodejoiner

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 23, 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-aws-ovn-pki-default-techpreview c7403e2 link false /test e2e-aws-ovn-pki-default-techpreview
ci/prow/e2e-agent-two-node-fencing-ipv4 b0d099a link false /test e2e-agent-two-node-fencing-ipv4
ci/prow/e2e-agent-ha-dualstack b0d099a link false /test e2e-agent-ha-dualstack
ci/prow/e2e-agent-compact-ipv4 b0d099a link true /test e2e-agent-compact-ipv4
ci/prow/e2e-agent-compact-ipv4-appliance-diskimage b0d099a link false /test e2e-agent-compact-ipv4-appliance-diskimage
ci/prow/e2e-agent-4control-ipv4 b0d099a link false /test e2e-agent-4control-ipv4
ci/prow/e2e-agent-compact-ipv6-minimaliso b0d099a link false /test e2e-agent-compact-ipv6-minimaliso
ci/prow/e2e-agent-5control-ipv4 b0d099a link false /test e2e-agent-5control-ipv4
ci/prow/e2e-agent-sno-ipv6 b0d099a link false /test e2e-agent-sno-ipv6
ci/prow/e2e-agent-compact-ipv4-iso-no-registry b0d099a link false /test e2e-agent-compact-ipv4-iso-no-registry
ci/prow/e2e-metal-ipi-ovn-ipv6 200625a link true /test e2e-metal-ipi-ovn-ipv6
ci/prow/integration-tests 200625a link true /test integration-tests

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.

3 participants