1
0
mirror of https://github.com/openshift/installer.git synced 2026-02-05 15:47:14 +01:00

Merge pull request #10147 from andfasano/iri-certs

AGENT-1389: create InternalReleaseImage registry TLS certificate
This commit is contained in:
openshift-merge-bot[bot]
2025-12-05 16:36:49 +00:00
committed by GitHub
8 changed files with 314 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
apiVersion: v1
kind: Secret
metadata:
name: internal-release-image-tls
namespace: openshift-machine-config-operator
annotations:
openshift.io/description: Secret containing the InternalReleaseImage registry TLS certificate and key
openshift.io/owning-component: Machine Config Operator
labels:
auth.openshift.io/managed-certificate-type: target
type: kubernetes.io/tls
data:
tls.crt: {{.IriTLSCert}}
tls.key: {{.IriTLSKey}}

View File

@@ -168,6 +168,7 @@ func (a *Common) Dependencies() []asset.Asset {
&tls.KubeletCSRSignerCertKey{},
&tls.KubeletServingCABundle{},
&tls.MCSCertKey{},
&tls.IRICertKey{},
&tls.RootCA{},
&tls.ServiceAccountKeyPair{},
&tls.IronicTLSCert{},
@@ -670,6 +671,7 @@ func (a *Common) addParentFiles(dependencies asset.Parents) {
&tls.KubeletCSRSignerCertKey{},
&tls.KubeletServingCABundle{},
&tls.MCSCertKey{},
&tls.IRICertKey{},
&tls.ServiceAccountKeyPair{},
&tls.JournalCertKey{},
&tls.IronicTLSCert{},

View File

@@ -16,6 +16,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/yaml"
"github.com/openshift/api/features"
"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/asset/rhcos"
@@ -76,6 +77,8 @@ func (m *Manifests) Dependencies() []asset.Asset {
&ImageDigestMirrorSet{},
&tls.RootCA{},
&tls.MCSCertKey{},
&tls.IRICertKey{},
&manifests.InternalReleaseImage{},
new(rhcos.Image),
&bootkube.CVOOverrides{},
@@ -85,6 +88,7 @@ func (m *Manifests) Dependencies() []asset.Asset {
&bootkube.MachineConfigServerCAConfigMap{},
&bootkube.MachineConfigServerTLSSecret{},
&bootkube.OpenshiftConfigSecretPullSecret{},
&bootkube.InternalReleaseImageTLSSecret{},
&BMCVerifyCAConfigMap{},
}
}
@@ -224,9 +228,42 @@ func (m *Manifests) generateBootKubeManifests(dependencies asset.Parents) []*ass
})
}
}
if installConfig.Config.EnabledFeatureGates().Enabled(features.FeatureGateNoRegistryClusterInstall) {
iri := &manifests.InternalReleaseImage{}
dependencies.Get(iri)
// Skip if InternalReleaseImage manifest wasn't found.
if len(iri.FileList) > 0 {
files = append(files, appendIRIcerts(dependencies))
}
}
return files
}
func appendIRIcerts(dependencies asset.Parents) *asset.File {
iriCertKey := &tls.IRICertKey{}
iriTLSSecret := &bootkube.InternalReleaseImageTLSSecret{}
dependencies.Get(iriCertKey, iriTLSSecret)
f := iriTLSSecret.Files()[0]
templateData := struct {
IriTLSCert string
IriTLSKey string
}{
IriTLSCert: base64.StdEncoding.EncodeToString(iriCertKey.Cert()),
IriTLSKey: base64.StdEncoding.EncodeToString(iriCertKey.Key()),
}
fileData := applyTemplateData(f.Data, templateData)
return &asset.File{
Filename: path.Join(manifestDir, strings.TrimSuffix(filepath.Base(f.Filename), ".template")),
Data: fileData,
}
}
func applyTemplateData(data []byte, templateData interface{}) []byte {
template := template.Must(template.New("template").Funcs(customTmplFuncs).Parse(string(data)))
buf := &bytes.Buffer{}

View File

@@ -124,6 +124,7 @@ func TestCreatedAssetsAreNotDirty(t *testing.T) {
"Cluster API Machine Manifests": true, // no files for the 'none' platform and ClusterAPIInstall feature gate not set
"Metadata": true, // read-only
"Kubeadmin Password": true, // read-only
"InternalReleaseImageTLSSecret": true, // no files when NoRegistryClusterInstall feature gate is not set
}
for _, a := range tc.targets {
name := a.Name()

View File

@@ -48,6 +48,7 @@ var (
&openshift.KubeadminPasswordSecret{},
&openshift.RoleCloudCredsSecretReader{},
&openshift.AzureCloudProviderSecret{},
&bootkube.InternalReleaseImageTLSSecret{},
}
// IgnitionConfigs are the ignition-configs targeted assets.

View File

@@ -0,0 +1,85 @@
package bootkube
import (
"context"
"os"
"path/filepath"
"github.com/openshift/api/features"
"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/asset/templates/content"
"github.com/openshift/installer/pkg/asset/templates/content/manifests"
)
const (
internalReleaseImageTLSSecretFileName = "internal-release-image-tls-secret.yaml.template"
)
var _ asset.WritableAsset = (*InternalReleaseImageTLSSecret)(nil)
// InternalReleaseImageTLSSecret is the constant to represent contents of machine_configservertlssecret.yaml.template file.
type InternalReleaseImageTLSSecret struct {
FileList []*asset.File
}
// Dependencies returns all of the dependencies directly needed by the asset.
func (t *InternalReleaseImageTLSSecret) Dependencies() []asset.Asset {
return []asset.Asset{
&installconfig.InstallConfig{},
&manifests.InternalReleaseImage{},
}
}
// Name returns the human-friendly name of the asset.
func (t *InternalReleaseImageTLSSecret) Name() string {
return "InternalReleaseImageTLSSecret"
}
// Generate generates the actual files by this asset.
func (t *InternalReleaseImageTLSSecret) Generate(_ context.Context, dependencies asset.Parents) error {
installConfig := &installconfig.InstallConfig{}
iri := &manifests.InternalReleaseImage{}
dependencies.Get(installConfig, iri)
if !installConfig.Config.EnabledFeatureGates().Enabled(features.FeatureGateNoRegistryClusterInstall) {
return nil
}
// Skip if InternalReleaseImage manifest wasn't found.
if len(iri.FileList) == 0 {
return nil
}
fileName := internalReleaseImageTLSSecretFileName
data, err := content.GetBootkubeTemplate(fileName)
if err != nil {
return err
}
t.FileList = []*asset.File{
{
Filename: filepath.Join(content.TemplateDir, fileName),
Data: data,
},
}
return nil
}
// Files returns the files generated by the asset.
func (t *InternalReleaseImageTLSSecret) Files() []*asset.File {
return t.FileList
}
// Load returns the asset from disk.
func (t *InternalReleaseImageTLSSecret) Load(f asset.FileFetcher) (bool, error) {
file, err := f.FetchByName(filepath.Join(content.TemplateDir, internalReleaseImageTLSSecretFileName))
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
t.FileList = []*asset.File{file}
return true, nil
}

View File

@@ -0,0 +1,79 @@
package manifests
import (
"context"
"path/filepath"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/yaml"
"github.com/openshift/installer/pkg/asset"
)
const (
internalReleaseImageKind = "InternalReleaseImage"
internalReleaseImageInstanceName = "cluster"
openshiftManifestDir = "openshift"
)
// InternalReleaseImage simply checks for the presence of the related manifest.
type InternalReleaseImage struct {
FileList []*asset.File
}
var (
_ asset.WritableAsset = (*InternalReleaseImage)(nil)
)
// Name returns a human friendly name for the operator.
func (iri *InternalReleaseImage) Name() string {
return "InternalReleaseImage manifest"
}
// Dependencies returns all of the dependencies required by the asset.
func (iri *InternalReleaseImage) Dependencies() []asset.Asset {
return []asset.Asset{}
}
// Generate is not required for InternalReleaseImage.
func (iri *InternalReleaseImage) Generate(_ context.Context, dependencies asset.Parents) error {
return nil
}
// Files returns the files generated by the asset.
func (iri *InternalReleaseImage) Files() []*asset.File {
return iri.FileList
}
// Load reads the asset files from disk.
func (iri *InternalReleaseImage) Load(f asset.FileFetcher) (found bool, err error) {
files := []*asset.File{}
yamlFiles, err := f.FetchByPattern(filepath.Join(openshiftManifestDir, "*.yaml"))
if err != nil {
return false, errors.Wrap(err, "failed to load *.yaml files")
}
files = append(files, yamlFiles...)
ymlFileList, err := f.FetchByPattern(filepath.Join(openshiftManifestDir, "*.yml"))
if err != nil {
return false, errors.Wrap(err, "failed to load *.yml files")
}
files = append(files, ymlFileList...)
for _, f := range files {
u := &unstructured.Unstructured{}
if err := yaml.Unmarshal(f.Data, u); err != nil {
logrus.Warnf("failed to unmarshal file %s: %v", f.Filename, err)
continue
}
if u.GetKind() == internalReleaseImageKind && u.GetName() == internalReleaseImageInstanceName {
iri.FileList = append(iri.FileList, f)
break
}
}
return len(iri.FileList) > 0, nil
}

View File

@@ -0,0 +1,95 @@
package tls
import (
"context"
"crypto/x509"
"crypto/x509/pkix"
"net"
features "github.com/openshift/api/features"
"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
"github.com/openshift/installer/pkg/asset/templates/content/manifests"
baremetaltypes "github.com/openshift/installer/pkg/types/baremetal"
nutanixtypes "github.com/openshift/installer/pkg/types/nutanix"
vspheretypes "github.com/openshift/installer/pkg/types/vsphere"
)
// IRICertKey is the asset that generates the InternalReleaseImage registry key/cert pair.
type IRICertKey struct {
SignedCertKey
}
var _ asset.Asset = (*IRICertKey)(nil)
// Dependencies returns the dependency of the the cert/key pair, which includes
// the parent CA, and install config if it depends on the install config for
// DNS names, etc.
func (a *IRICertKey) Dependencies() []asset.Asset {
return []asset.Asset{
&RootCA{},
&installconfig.InstallConfig{},
&manifests.InternalReleaseImage{},
}
}
// Generate generates the cert/key pair based on its dependencies.
func (a *IRICertKey) Generate(ctx context.Context, dependencies asset.Parents) error {
ca := &RootCA{}
installConfig := &installconfig.InstallConfig{}
iri := &manifests.InternalReleaseImage{}
dependencies.Get(ca, installConfig, iri)
if !installConfig.Config.EnabledFeatureGates().Enabled(features.FeatureGateNoRegistryClusterInstall) {
return nil
}
// Skip if InternalReleaseImage manifest wasn't found.
if len(iri.FileList) == 0 {
return nil
}
apiInt := internalAPIAddress(installConfig.Config)
cfg := &CertCfg{
Subject: pkix.Name{CommonName: "system:internal-release-image"},
ExtKeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
Validity: ValidityTenYears(),
}
var vips []string
switch installConfig.Config.Platform.Name() {
case baremetaltypes.Name:
vips = installConfig.Config.BareMetal.APIVIPs
case nutanixtypes.Name:
vips = installConfig.Config.Nutanix.APIVIPs
case vspheretypes.Name:
vips = installConfig.Config.VSphere.APIVIPs
}
cfg.IPAddresses = []net.IP{}
cfg.DNSNames = []string{
"localhost",
apiInt,
}
localIPs := []string{
"127.0.0.1",
"::1",
}
for _, vip := range vips {
cfg.IPAddresses = append(cfg.IPAddresses, net.ParseIP(vip))
cfg.DNSNames = append(cfg.DNSNames, vip)
}
for _, i := range localIPs {
if ip := net.ParseIP(i); ip != nil {
cfg.IPAddresses = append(cfg.IPAddresses, ip)
}
}
return a.SignedCertKey.Generate(ctx, cfg, ca, "internal-release-image", DoNotAppendParent)
}
// Name returns the human-friendly name of the asset.
func (a *IRICertKey) Name() string {
return "Certificate (InternalReleaseImage)"
}