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:
@@ -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}}
|
||||
@@ -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{},
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -48,6 +48,7 @@ var (
|
||||
&openshift.KubeadminPasswordSecret{},
|
||||
&openshift.RoleCloudCredsSecretReader{},
|
||||
&openshift.AzureCloudProviderSecret{},
|
||||
&bootkube.InternalReleaseImageTLSSecret{},
|
||||
}
|
||||
|
||||
// IgnitionConfigs are the ignition-configs targeted assets.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
95
pkg/asset/tls/iricertkey.go
Normal file
95
pkg/asset/tls/iricertkey.go
Normal 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)"
|
||||
}
|
||||
Reference in New Issue
Block a user