Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions data/data/install.openshift.io_installconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5084,6 +5084,82 @@ spec:
- rhel-9
- rhel-10
type: string
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.
properties:
signerCertificates:
description: |-
signerCertificates specifies key parameters for all installer-generated
certificate authority (CA) certificates.
When set, all signer certificates use the specified algorithm and parameters.
Comment thread
hasbro17 marked this conversation as resolved.
minProperties: 1
properties:
key:
description: key specifies the cryptographic parameters for the
certificate's key pair.
properties:
algorithm:
description: |-
algorithm specifies the key generation algorithm.
Valid values are "RSA" and "ECDSA".
enum:
- RSA
- ECDSA
type: string
ecdsa:
description: |-
ecdsa specifies ECDSA key parameters.
Required when algorithm is ECDSA, and forbidden otherwise.
properties:
curve:
description: |-
curve specifies the NIST elliptic curve for ECDSA keys.
Valid values are "P256", "P384", and "P521".
enum:
- P256
- P384
- P521
type: string
required:
- curve
type: object
rsa:
description: |-
rsa specifies RSA key parameters.
Required when algorithm is RSA, and forbidden otherwise.
properties:
keySize:
description: |-
keySize specifies the size of RSA keys in bits.
Valid values are multiples of 1024 from 2048 to 8192.
format: int32
maximum: 8192
minimum: 2048
multipleOf: 1024
type: integer
required:
- keySize
type: object
required:
- algorithm
type: object
x-kubernetes-validations:
- message: rsa is required when algorithm is RSA, and forbidden
otherwise
rule: 'has(self.algorithm) && self.algorithm == ''RSA'' ? has(self.rsa)
: !has(self.rsa)'
- message: ecdsa is required when algorithm is ECDSA, and forbidden
otherwise
rule: 'has(self.algorithm) && self.algorithm == ''ECDSA'' ? has(self.ecdsa)
: !has(self.ecdsa)'
type: object
required:
- signerCertificates
type: object
platform:
description: |-
Platform is the configuration for the specific platform upon which to
Expand Down
5 changes: 4 additions & 1 deletion pkg/asset/manifests/operators.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func (m *Manifests) Dependencies() []asset.Asset {
&bootkube.InternalReleaseImageTLSSecret{},
&bootkube.InternalReleaseImageRegistryAuthSecret{},
&BMCVerifyCAConfigMap{},
&PKIConfiguration{},
}
}

Expand All @@ -107,8 +108,9 @@ func (m *Manifests) Generate(_ context.Context, dependencies asset.Parents) erro
imageDigestMirrorSet := &ImageDigestMirrorSet{}
mcoCfgTemplate := &manifests.MCO{}
bmcVerifyCAConfigMap := &BMCVerifyCAConfigMap{}
pkiConfig := &PKIConfiguration{}

dependencies.Get(installConfig, ingress, dns, network, infra, proxy, scheduler, imageContentSourcePolicy, imageDigestMirrorSet, clusterCSIDriverConfig, mcoCfgTemplate, bmcVerifyCAConfigMap)
dependencies.Get(installConfig, ingress, dns, network, infra, proxy, scheduler, imageContentSourcePolicy, imageDigestMirrorSet, clusterCSIDriverConfig, mcoCfgTemplate, bmcVerifyCAConfigMap, pkiConfig)

redactedConfig, err := redactedInstallConfig(*installConfig.Config)
if err != nil {
Expand Down Expand Up @@ -147,6 +149,7 @@ func (m *Manifests) Generate(_ context.Context, dependencies asset.Parents) erro
m.FileList = append(m.FileList, clusterCSIDriverConfig.Files()...)
m.FileList = append(m.FileList, imageDigestMirrorSet.Files()...)
m.FileList = append(m.FileList, bmcVerifyCAConfigMap.Files()...)
m.FileList = append(m.FileList, pkiConfig.Files()...)

asset.SortFiles(m.FileList)

Expand Down
102 changes: 102 additions & 0 deletions pkg/asset/manifests/pki.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package manifests

import (
"context"
"path"

"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"

configv1alpha1 "github.com/openshift/api/config/v1alpha1"
features "github.com/openshift/api/features"
"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
pkidefaults "github.com/openshift/installer/pkg/types/pki"
)

var pkiCfgFilename = path.Join(manifestDir, "cluster-pki-02-config.yaml")

// PKIConfiguration generates the PKI custom resource manifest.
type PKIConfiguration struct {
FileList []*asset.File
}

var _ asset.WritableAsset = (*PKIConfiguration)(nil)

// Name returns a human friendly name for the asset.
func (*PKIConfiguration) Name() string {
return "PKI Config"
}

// Dependencies returns all of the dependencies directly needed to generate
// the asset.
func (*PKIConfiguration) Dependencies() []asset.Asset {
return []asset.Asset{
&installconfig.InstallConfig{},
}
}

// Generate generates the PKI custom resource manifest.
// The manifest is only generated when the ConfigurablePKI feature gate is enabled.
func (p *PKIConfiguration) Generate(_ context.Context, dependencies asset.Parents) error {
installConfig := &installconfig.InstallConfig{}
dependencies.Get(installConfig)

if !installConfig.Config.Enabled(features.FeatureGateConfigurablePKI) {
return nil
}

certMgmt := configv1alpha1.PKICertificateManagement{
Mode: configv1alpha1.PKICertificateManagementModeDefault,
}

if installConfig.Config.PKI != nil {
profile := pkidefaults.DefaultPKIProfile()
profile.SignerCertificates = pkidefaults.CertificateConfigToUpstream(installConfig.Config.PKI.SignerCertificates)

certMgmt = configv1alpha1.PKICertificateManagement{
Mode: configv1alpha1.PKICertificateManagementModeCustom,
Custom: configv1alpha1.CustomPKIPolicy{
PKIProfile: profile,
},
}
}

config := &configv1alpha1.PKI{
TypeMeta: metav1.TypeMeta{
APIVersion: configv1alpha1.SchemeGroupVersion.String(),
Kind: "PKI",
},
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
},
Spec: configv1alpha1.PKISpec{
CertificateManagement: certMgmt,
},
}

configData, err := yaml.Marshal(config)
if err != nil {
return errors.Wrapf(err, "failed to marshal PKI config")
}

p.FileList = []*asset.File{
{
Filename: pkiCfgFilename,
Data: configData,
},
}

return nil
}

// Files returns the files generated by the asset.
func (p *PKIConfiguration) Files() []*asset.File {
return p.FileList
}

// Load returns false since this asset is not written to disk by the installer.
func (p *PKIConfiguration) Load(f asset.FileFetcher) (bool, error) {
return false, nil
}
164 changes: 164 additions & 0 deletions pkg/asset/manifests/pki_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package manifests

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"sigs.k8s.io/yaml"

configv1 "github.com/openshift/api/config/v1"
configv1alpha1 "github.com/openshift/api/config/v1alpha1"
"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/types"
)

func TestPKIConfigurationGenerate(t *testing.T) {
cases := []struct {
name string
installConfig *types.InstallConfig
expectEmpty bool
expectMode configv1alpha1.PKICertificateManagementMode
expectSignerAlgo configv1alpha1.KeyAlgorithm
expectSignerRSA int32
expectSignerCurve configv1alpha1.ECDSACurve
expectDefaultsAlgo configv1alpha1.KeyAlgorithm
expectDefaultsRSA int32
expectDefaultsCurve configv1alpha1.ECDSACurve
}{
{
name: "feature gate disabled - no manifest generated",
installConfig: &types.InstallConfig{
FeatureSet: configv1.Default,
},
expectEmpty: true,
},
{
name: "feature gate enabled, pki nil - mode Default",
installConfig: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
},
expectEmpty: false,
expectMode: configv1alpha1.PKICertificateManagementModeDefault,
},
{
name: "feature gate enabled, pki RSA-4096",
installConfig: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
PKI: &types.PKIConfig{
SignerCertificates: types.CertificateConfig{
Key: types.KeyConfig{
Algorithm: types.KeyAlgorithmRSA,
RSA: types.RSAKeyConfig{KeySize: 4096},
},
},
},
},
expectEmpty: false,
expectMode: configv1alpha1.PKICertificateManagementModeCustom,
expectSignerAlgo: configv1alpha1.KeyAlgorithmRSA,
expectSignerRSA: 4096,
expectDefaultsAlgo: configv1alpha1.KeyAlgorithmRSA,
expectDefaultsRSA: 4096,
},
{
name: "feature gate enabled, pki ECDSA P-384",
installConfig: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
PKI: &types.PKIConfig{
SignerCertificates: types.CertificateConfig{
Key: types.KeyConfig{
Algorithm: types.KeyAlgorithmECDSA,
ECDSA: types.ECDSAKeyConfig{Curve: types.ECDSACurveP384},
},
},
},
},
expectEmpty: false,
expectMode: configv1alpha1.PKICertificateManagementModeCustom,
expectSignerAlgo: configv1alpha1.KeyAlgorithmECDSA,
expectSignerCurve: configv1alpha1.ECDSACurveP384,
expectDefaultsAlgo: configv1alpha1.KeyAlgorithmRSA,
expectDefaultsRSA: 4096,
},
{
name: "feature gate enabled, pki RSA-2048 explicit",
installConfig: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
PKI: &types.PKIConfig{
SignerCertificates: types.CertificateConfig{
Key: types.KeyConfig{
Algorithm: types.KeyAlgorithmRSA,
RSA: types.RSAKeyConfig{KeySize: 2048},
},
},
},
},
expectEmpty: false,
expectMode: configv1alpha1.PKICertificateManagementModeCustom,
expectSignerAlgo: configv1alpha1.KeyAlgorithmRSA,
expectSignerRSA: 2048,
expectDefaultsAlgo: configv1alpha1.KeyAlgorithmRSA,
expectDefaultsRSA: 4096,
},
}

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
parents := asset.Parents{}
parents.Add(installconfig.MakeAsset(tc.installConfig))

pkiAsset := &PKIConfiguration{}
err := pkiAsset.Generate(context.Background(), parents)
if !assert.NoError(t, err) {
return
}

if tc.expectEmpty {
assert.Empty(t, pkiAsset.Files())
return
}

if !assert.Len(t, pkiAsset.Files(), 1) {
return
}
assert.Equal(t, "manifests/cluster-pki-02-config.yaml", pkiAsset.Files()[0].Filename)

// Unmarshal and verify the CR structure
var pkiCR configv1alpha1.PKI
err = yaml.Unmarshal(pkiAsset.Files()[0].Data, &pkiCR)
if !assert.NoError(t, err) {
return
}

assert.Equal(t, "config.openshift.io/v1alpha1", pkiCR.APIVersion)
assert.Equal(t, "PKI", pkiCR.Kind)
assert.Equal(t, "cluster", pkiCR.Name)
assert.Equal(t, tc.expectMode, pkiCR.Spec.CertificateManagement.Mode)

if tc.expectMode != configv1alpha1.PKICertificateManagementModeCustom {
return
}

profile := pkiCR.Spec.CertificateManagement.Custom.PKIProfile

// Verify defaults
assert.Equal(t, tc.expectDefaultsAlgo, profile.Defaults.Key.Algorithm)
if tc.expectDefaultsAlgo == configv1alpha1.KeyAlgorithmECDSA {
assert.Equal(t, tc.expectDefaultsCurve, profile.Defaults.Key.ECDSA.Curve)
} else {
assert.Equal(t, tc.expectDefaultsRSA, profile.Defaults.Key.RSA.KeySize)
}

// Verify signerCertificates
assert.Equal(t, tc.expectSignerAlgo, profile.SignerCertificates.Key.Algorithm)
if tc.expectSignerAlgo == configv1alpha1.KeyAlgorithmRSA {
assert.Equal(t, tc.expectSignerRSA, profile.SignerCertificates.Key.RSA.KeySize)
}
if tc.expectSignerAlgo == configv1alpha1.KeyAlgorithmECDSA {
assert.Equal(t, tc.expectSignerCurve, profile.SignerCertificates.Key.ECDSA.Curve)
}
})
}
}
6 changes: 6 additions & 0 deletions pkg/explain/printer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@ the cluster.
Valid Values: "rhel-9","rhel-10"
OSImageStream is the global OS Image Stream to be used for all machines in the cluster.

pki <object>
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.

platform <object> -required-
Platform is the configuration for the specific platform upon which to
perform the installation.
Expand Down
1 change: 1 addition & 0 deletions pkg/types/defaults/installconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,5 @@ func SetInstallConfigDefaults(c *types.InstallConfig) {
if c.AdditionalTrustBundlePolicy == "" {
c.AdditionalTrustBundlePolicy = types.PolicyProxyOnly
}

}
Loading