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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ require (
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/gorm v1.24.5 // indirect
k8s.io/apiserver v0.36.0 // indirect
k8s.io/apiserver v0.36.0
k8s.io/cli-runtime v0.36.0 // indirect
k8s.io/cluster-bootstrap v0.35.5 // indirect
k8s.io/component-base v0.36.0 // indirect
Expand Down
59 changes: 43 additions & 16 deletions pkg/asset/imagebased/configimage/ingressoperatorsigner.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/asset/tls"
libcrypto "github.com/openshift/library-go/pkg/crypto"
libpki "github.com/openshift/library-go/pkg/pki"
)

// Name returns the human-friendly name of the asset.
Expand All @@ -37,35 +39,49 @@ var _ asset.Asset = (*IngressOperatorSignerCertKey)(nil)

// Dependencies returns the dependency of the the cert/key pair.
func (a *IngressOperatorSignerCertKey) Dependencies() []asset.Asset {
return []asset.Asset{&installconfig.InstallConfig{}}
return []asset.Asset{
&installconfig.InstallConfig{},
&tls.SignerKeyParams{},
}
}

// Generate generates the cert/key pair based on its dependencies.
func (a *IngressOperatorSignerCertKey) Generate(ctx context.Context, dependencies asset.Parents) error {
signerName := fmt.Sprintf("%s@%d", "ingress-operator", time.Now().Unix())

installConfig := &installconfig.InstallConfig{}
dependencies.Get(installConfig)

cfg := &tls.CertCfg{
Subject: pkix.Name{CommonName: signerName},
KeyUsages: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
Validity: tls.ValidityOneYear(installConfig) * 2,
IsCA: true,
pkiCfg := &tls.SignerKeyParams{}
dependencies.Get(installConfig, pkiCfg)

if !pkiCfg.ConfigurablePKIEnabled {
cfg := &tls.CertCfg{
Subject: pkix.Name{CommonName: signerName},
KeyUsages: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
Validity: tls.ValidityOneYear(installConfig) * 2,
IsCA: true,
}
key, crt, err := generateSelfSignedCertificate(cfg)
if err != nil {
return err
}
a.KeyRaw, err = tls.PrivateKeyToPem(key)
if err != nil {
return fmt.Errorf("failed to encode private key to PEM: %w", err)
}
a.CertRaw = tls.CertToPem(crt)
return nil
}

key, crt, err := generateSelfSignedCertificate(cfg)
keyGen, err := resolveSignerKeyGen(pkiCfg, "installer.ingress-operator-signer")
if err != nil {
return err
}

a.KeyRaw, err = tls.PrivateKeyToPem(key)
if err != nil {
return fmt.Errorf("failed to encode private key to PEM: %w", err)
cfg := &tls.CertCfg{
Subject: pkix.Name{CommonName: signerName},
Validity: tls.ValidityOneYear(installConfig) * 2,
IsCA: true,
}
a.CertRaw = tls.CertToPem(crt)

return nil
return a.SelfSignedCertKey.Generate(ctx, cfg, "ingress-operator-signer", keyGen)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// IngressOperatorCABundle is the asset the generates the ingress-operator-signer-ca-bundle,
Expand Down Expand Up @@ -175,3 +191,14 @@ func generateSubjectKeyID(pub crypto.PublicKey) ([]byte, error) {
hash := sha1.Sum(publicKeyBytes) //nolint: gosec
return hash[:], nil
}

// resolveSignerKeyGen resolves the KeyPairGenerator for a signer certificate
// from the SignerKeyParams's profile.
func resolveSignerKeyGen(pkiCfg *tls.SignerKeyParams, certName string) (libcrypto.KeyPairGenerator, error) {
provider := libpki.NewStaticPKIProfileProvider(&pkiCfg.Profile)
resolved, err := libpki.ResolveCertificateConfig(provider, libpki.CertificateTypeSigner, certName)
if err != nil {
return nil, fmt.Errorf("failed to resolve PKI config for signer certificate %q: %w", certName, err)
}
return resolved.Key, nil
}
41 changes: 11 additions & 30 deletions pkg/asset/manifests/pki.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ import (
"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"
"github.com/openshift/installer/pkg/types"
pkidefaults "github.com/openshift/installer/pkg/types/pki"
"github.com/openshift/installer/pkg/asset/tls"
libpki "github.com/openshift/library-go/pkg/pki"
)

var pkiCfgFilename = path.Join(manifestDir, "cluster-pki-02-config.yaml")
Expand All @@ -34,32 +32,32 @@ func (*PKIConfiguration) Name() string {
// the asset.
func (*PKIConfiguration) Dependencies() []asset.Asset {
return []asset.Asset{
&installconfig.InstallConfig{},
&tls.SignerKeyParams{},
}
}

// 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)
signerKeyParams := &tls.SignerKeyParams{}
dependencies.Get(signerKeyParams)

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

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

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

// When ConfigurablePKIEnabled is true but the profile equals the default,
// it means no user customization was provided.
defaultProfile := libpki.DefaultPKIProfile()
if signerKeyParams.Profile != defaultProfile {
certMgmt = configv1alpha1.PKICertificateManagement{
Mode: configv1alpha1.PKICertificateManagementModeCustom,
Custom: configv1alpha1.CustomPKIPolicy{
PKIProfile: profile,
PKIProfile: signerKeyParams.Profile,
},
}
}
Expand Down Expand Up @@ -101,20 +99,3 @@ func (p *PKIConfiguration) Files() []*asset.File {
func (p *PKIConfiguration) Load(f asset.FileFetcher) (bool, error) {
return false, nil
}

// convertToAPICertConfig converts the installer CertificateConfig
// to the openshift/api configv1alpha1.CertificateConfig for use in the PKI CR manifest.
func convertToAPICertConfig(certConf types.CertificateConfig) configv1alpha1.CertificateConfig {
out := configv1alpha1.CertificateConfig{
Key: configv1alpha1.KeyConfig{
Algorithm: configv1alpha1.KeyAlgorithm(certConf.Key.Algorithm),
},
}
if certConf.Key.RSA != nil {
out.Key.RSA = configv1alpha1.RSAKeyConfig{KeySize: certConf.Key.RSA.KeySize}
}
if certConf.Key.ECDSA != nil {
out.Key.ECDSA = configv1alpha1.ECDSAKeyConfig{Curve: configv1alpha1.ECDSACurve(certConf.Key.ECDSA.Curve)}
}
return out
}
82 changes: 50 additions & 32 deletions pkg/asset/manifests/pki_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@ import (
"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"
"github.com/openshift/installer/pkg/asset/tls"
libpki "github.com/openshift/library-go/pkg/pki"
)

func TestPKIConfigurationGenerate(t *testing.T) {
cases := []struct {
testCases := []struct {
name string
installConfig *types.InstallConfig
signerKeyParams *tls.SignerKeyParams
expectEmpty bool
expectMode configv1alpha1.PKICertificateManagementMode
expectSignerAlgo configv1alpha1.KeyAlgorithm
Expand All @@ -29,31 +28,38 @@ func TestPKIConfigurationGenerate(t *testing.T) {
}{
{
name: "feature gate disabled - no manifest generated",
installConfig: &types.InstallConfig{
FeatureSet: configv1.Default,
signerKeyParams: &tls.SignerKeyParams{
ConfigurablePKIEnabled: false,
},
expectEmpty: true,
},
{
name: "feature gate enabled, pki nil - mode Default",
installConfig: &types.InstallConfig{
FeatureSet: configv1.TechPreviewNoUpgrade,
signerKeyParams: &tls.SignerKeyParams{
Profile: libpki.DefaultPKIProfile(),
ConfigurablePKIEnabled: true,
},
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},
signerKeyParams: &tls.SignerKeyParams{
Profile: configv1alpha1.PKIProfile{
Defaults: configv1alpha1.DefaultCertificateConfig{
Key: configv1alpha1.KeyConfig{
Algorithm: configv1alpha1.KeyAlgorithmRSA,
RSA: configv1alpha1.RSAKeyConfig{KeySize: 4096},
},
},
SignerCertificates: configv1alpha1.CertificateConfig{
Key: configv1alpha1.KeyConfig{
Algorithm: configv1alpha1.KeyAlgorithmRSA,
RSA: configv1alpha1.RSAKeyConfig{KeySize: 4096},
},
},
},
ConfigurablePKIEnabled: true,
},
expectEmpty: false,
expectMode: configv1alpha1.PKICertificateManagementModeCustom,
Expand All @@ -64,16 +70,22 @@ func TestPKIConfigurationGenerate(t *testing.T) {
},
{
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},
signerKeyParams: &tls.SignerKeyParams{
Profile: configv1alpha1.PKIProfile{
Defaults: configv1alpha1.DefaultCertificateConfig{
Key: configv1alpha1.KeyConfig{
Algorithm: configv1alpha1.KeyAlgorithmRSA,
RSA: configv1alpha1.RSAKeyConfig{KeySize: 4096},
},
},
SignerCertificates: configv1alpha1.CertificateConfig{
Key: configv1alpha1.KeyConfig{
Algorithm: configv1alpha1.KeyAlgorithmECDSA,
ECDSA: configv1alpha1.ECDSAKeyConfig{Curve: configv1alpha1.ECDSACurveP384},
},
},
},
ConfigurablePKIEnabled: true,
},
expectEmpty: false,
expectMode: configv1alpha1.PKICertificateManagementModeCustom,
Expand All @@ -84,16 +96,22 @@ func TestPKIConfigurationGenerate(t *testing.T) {
},
{
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},
signerKeyParams: &tls.SignerKeyParams{
Profile: configv1alpha1.PKIProfile{
Defaults: configv1alpha1.DefaultCertificateConfig{
Key: configv1alpha1.KeyConfig{
Algorithm: configv1alpha1.KeyAlgorithmRSA,
RSA: configv1alpha1.RSAKeyConfig{KeySize: 4096},
},
},
SignerCertificates: configv1alpha1.CertificateConfig{
Key: configv1alpha1.KeyConfig{
Algorithm: configv1alpha1.KeyAlgorithmRSA,
RSA: configv1alpha1.RSAKeyConfig{KeySize: 2048},
},
},
},
ConfigurablePKIEnabled: true,
},
expectEmpty: false,
expectMode: configv1alpha1.PKICertificateManagementModeCustom,
Expand All @@ -104,10 +122,10 @@ func TestPKIConfigurationGenerate(t *testing.T) {
},
}

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

pkiAsset := &PKIConfiguration{}
err := pkiAsset.Generate(context.Background(), parents)
Expand Down
Loading