Skip to content

Commit e873c80

Browse files
committed
tls: add SignerKeyParams asset to decouple signer certs from InstallConfig
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`. It also broke the agent flow for configs that pass agent-specific validation but fail standard InstallConfig validation (e.g. vSphere without credentials). Introduce a SignerKeyParams WritableAsset with zero dependencies that reads install-config.yaml directly from disk in Load(), extracting only the PKI and FeatureSet fields without running validation. This avoids pulling standard InstallConfig validation into the agent flow, where OptionalInstallConfig handles validation with more lenient rules. When no install-config is present, Load() defaults to nil PKIConfig (RSA-2048). Assisted-by: Claude Code (Opus 4.6)
1 parent a0c070e commit e873c80

3 files changed

Lines changed: 91 additions & 18 deletions

File tree

pkg/asset/tls/adminkubeconfig.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import (
66
"crypto/x509/pkix"
77

88
"github.com/openshift/installer/pkg/asset"
9-
"github.com/openshift/installer/pkg/asset/installconfig"
10-
pkidefaults "github.com/openshift/installer/pkg/types/pki"
119
)
1210

1311
// AdminKubeConfigSignerCertKey is a key/cert pair that signs the admin kubeconfig client certs.
@@ -19,21 +17,21 @@ var _ asset.WritableAsset = (*AdminKubeConfigSignerCertKey)(nil)
1917

2018
// Dependencies returns the dependency of the root-ca, which is empty.
2119
func (c *AdminKubeConfigSignerCertKey) Dependencies() []asset.Asset {
22-
return []asset.Asset{&installconfig.InstallConfig{}}
20+
return []asset.Asset{&SignerKeyParams{}}
2321
}
2422

2523
// Generate generates the root-ca key and cert pair.
2624
func (c *AdminKubeConfigSignerCertKey) Generate(ctx context.Context, parents asset.Parents) error {
27-
installConfig := &installconfig.InstallConfig{}
28-
parents.Get(installConfig)
25+
signerKeyParams := &SignerKeyParams{}
26+
parents.Get(signerKeyParams)
2927
cfg := &CertCfg{
3028
Subject: pkix.Name{CommonName: "admin-kubeconfig-signer", OrganizationalUnit: []string{"openshift"}},
3129
// KeyUsages is set by GenerateSelfSignedCertificate based on the key algorithm.
3230
Validity: ValidityTenYears(),
3331
IsCA: true,
3432
}
3533

36-
return c.SelfSignedCertKey.Generate(ctx, cfg, "admin-kubeconfig-signer", pkidefaults.EffectiveSignerPKIConfig(installConfig.Config))
34+
return c.SelfSignedCertKey.Generate(ctx, cfg, "admin-kubeconfig-signer", signerKeyParams.PKIConfig)
3735
}
3836

3937
// Load reads the asset files from disk.

pkg/asset/tls/apiserver.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,21 +119,21 @@ var _ asset.WritableAsset = (*KubeAPIServerLocalhostSignerCertKey)(nil)
119119

120120
// Dependencies returns the dependency of the root-ca, which is empty.
121121
func (c *KubeAPIServerLocalhostSignerCertKey) Dependencies() []asset.Asset {
122-
return []asset.Asset{&installconfig.InstallConfig{}}
122+
return []asset.Asset{&SignerKeyParams{}}
123123
}
124124

125125
// Generate generates the root-ca key and cert pair.
126126
func (c *KubeAPIServerLocalhostSignerCertKey) Generate(ctx context.Context, parents asset.Parents) error {
127-
installConfig := &installconfig.InstallConfig{}
128-
parents.Get(installConfig)
127+
signerKeyParams := &SignerKeyParams{}
128+
parents.Get(signerKeyParams)
129129
cfg := &CertCfg{
130130
Subject: pkix.Name{CommonName: "kube-apiserver-localhost-signer", OrganizationalUnit: []string{"openshift"}},
131131
// KeyUsages is set by GenerateSelfSignedCertificate based on the key algorithm.
132132
Validity: ValidityTenYears(),
133133
IsCA: true,
134134
}
135135

136-
return c.SelfSignedCertKey.Generate(ctx, cfg, "kube-apiserver-localhost-signer", pkidefaults.EffectiveSignerPKIConfig(installConfig.Config))
136+
return c.SelfSignedCertKey.Generate(ctx, cfg, "kube-apiserver-localhost-signer", signerKeyParams.PKIConfig)
137137
}
138138

139139
// Load reads the asset files from disk.
@@ -225,21 +225,21 @@ var _ asset.WritableAsset = (*KubeAPIServerServiceNetworkSignerCertKey)(nil)
225225

226226
// Dependencies returns the dependency of the root-ca, which is empty.
227227
func (c *KubeAPIServerServiceNetworkSignerCertKey) Dependencies() []asset.Asset {
228-
return []asset.Asset{&installconfig.InstallConfig{}}
228+
return []asset.Asset{&SignerKeyParams{}}
229229
}
230230

231231
// Generate generates the root-ca key and cert pair.
232232
func (c *KubeAPIServerServiceNetworkSignerCertKey) Generate(ctx context.Context, parents asset.Parents) error {
233-
installConfig := &installconfig.InstallConfig{}
234-
parents.Get(installConfig)
233+
signerKeyParams := &SignerKeyParams{}
234+
parents.Get(signerKeyParams)
235235
cfg := &CertCfg{
236236
Subject: pkix.Name{CommonName: "kube-apiserver-service-network-signer", OrganizationalUnit: []string{"openshift"}},
237237
// KeyUsages is set by GenerateSelfSignedCertificate based on the key algorithm.
238238
Validity: ValidityTenYears(),
239239
IsCA: true,
240240
}
241241

242-
return c.SelfSignedCertKey.Generate(ctx, cfg, "kube-apiserver-service-network-signer", pkidefaults.EffectiveSignerPKIConfig(installConfig.Config))
242+
return c.SelfSignedCertKey.Generate(ctx, cfg, "kube-apiserver-service-network-signer", signerKeyParams.PKIConfig)
243243
}
244244

245245
// Load reads the asset files from disk.
@@ -340,21 +340,21 @@ var _ asset.WritableAsset = (*KubeAPIServerLBSignerCertKey)(nil)
340340

341341
// Dependencies returns the dependency of the root-ca, which is empty.
342342
func (c *KubeAPIServerLBSignerCertKey) Dependencies() []asset.Asset {
343-
return []asset.Asset{&installconfig.InstallConfig{}}
343+
return []asset.Asset{&SignerKeyParams{}}
344344
}
345345

346346
// Generate generates the root-ca key and cert pair.
347347
func (c *KubeAPIServerLBSignerCertKey) Generate(ctx context.Context, parents asset.Parents) error {
348-
installConfig := &installconfig.InstallConfig{}
349-
parents.Get(installConfig)
348+
signerKeyParams := &SignerKeyParams{}
349+
parents.Get(signerKeyParams)
350350
cfg := &CertCfg{
351351
Subject: pkix.Name{CommonName: "kube-apiserver-lb-signer", OrganizationalUnit: []string{"openshift"}},
352352
// KeyUsages is set by GenerateSelfSignedCertificate based on the key algorithm.
353353
Validity: ValidityTenYears(),
354354
IsCA: true,
355355
}
356356

357-
return c.SelfSignedCertKey.Generate(ctx, cfg, "kube-apiserver-lb-signer", pkidefaults.EffectiveSignerPKIConfig(installConfig.Config))
357+
return c.SelfSignedCertKey.Generate(ctx, cfg, "kube-apiserver-lb-signer", signerKeyParams.PKIConfig)
358358
}
359359

360360
// Load reads the asset files from disk.

pkg/asset/tls/signerkey_params.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package tls
2+
3+
import (
4+
"context"
5+
6+
"sigs.k8s.io/yaml"
7+
8+
"github.com/openshift/installer/pkg/asset"
9+
"github.com/openshift/installer/pkg/types"
10+
pkidefaults "github.com/openshift/installer/pkg/types/pki"
11+
)
12+
13+
// SignerKeyParams resolves the effective PKI configuration for signer
14+
// certificates. It has no asset dependencies and reads install-config.yaml
15+
// directly from disk so that signer certs can be generated without triggering
16+
// standard InstallConfig validation. When no install-config is present (e.g.
17+
// agent create certificates, node-joiner add-nodes), it defaults to nil
18+
// PKIConfig which maps to RSA-2048.
19+
type SignerKeyParams struct {
20+
PKIConfig *types.PKIConfig
21+
}
22+
23+
var _ asset.WritableAsset = (*SignerKeyParams)(nil)
24+
25+
// Name returns a human-friendly name for the asset.
26+
func (*SignerKeyParams) Name() string {
27+
return "Signer Key Parameters"
28+
}
29+
30+
// Dependencies returns no dependencies. See Load() for why this asset does
31+
// not depend on the standard InstallConfig asset.
32+
func (*SignerKeyParams) Dependencies() []asset.Asset {
33+
return []asset.Asset{}
34+
}
35+
36+
// Generate is a no-op. PKI config is resolved entirely in Load().
37+
func (s *SignerKeyParams) Generate(_ context.Context, _ asset.Parents) error {
38+
return nil
39+
}
40+
41+
// Files returns nil — this asset has no on-disk representation.
42+
func (*SignerKeyParams) Files() []*asset.File {
43+
return nil
44+
}
45+
46+
// Load reads the install-config.yaml directly from disk and extracts the PKI
47+
// configuration. This always returns (true, nil) — it never errors and never
48+
// triggers interactive prompts.
49+
//
50+
// We parse the install-config directly rather than depending on the
51+
// InstallConfig asset because store.load() recursively loads all dependencies
52+
// from disk, and InstallConfig.Load() runs full platform validation via
53+
// finish() -> ValidateInstallConfig(). In the agent flow, configs are validated
54+
// by OptionalInstallConfig with agent-specific rules that are more lenient
55+
// (e.g. vSphere without credentials is valid for agent installs). Adding
56+
// InstallConfig as a dependency here would pull standard validation into the
57+
// agent flow, rejecting configs that OptionalInstallConfig accepts.
58+
//
59+
// Since we only need the PKI and FeatureSet fields, we can safely unmarshal
60+
// without validation. Any actual validation errors will be caught by the
61+
// authoritative InstallConfig or OptionalInstallConfig asset elsewhere in the
62+
// pipeline.
63+
func (s *SignerKeyParams) Load(f asset.FileFetcher) (bool, error) {
64+
// Matches installConfigFilename in pkg/asset/installconfig/installconfig.go.
65+
file, err := f.FetchByName("install-config.yaml")
66+
if err != nil {
67+
return true, nil
68+
}
69+
config := &types.InstallConfig{}
70+
if err := yaml.Unmarshal(file.Data, config); err != nil {
71+
return true, nil
72+
}
73+
s.PKIConfig = pkidefaults.EffectiveSignerPKIConfig(config)
74+
return true, nil
75+
}

0 commit comments

Comments
 (0)