diff --git a/data/data/bootstrap/baremetal/files/etc/containers/systemd/ironic.container.template b/data/data/bootstrap/baremetal/files/etc/containers/systemd/ironic.container.template index 43e456f2eff..2546c50016f 100644 --- a/data/data/bootstrap/baremetal/files/etc/containers/systemd/ironic.container.template +++ b/data/data/bootstrap/baremetal/files/etc/containers/systemd/ironic.container.template @@ -22,6 +22,9 @@ Volume=ironic.volume:/shared:z Volume=/opt/openshift/tls/ironic/:/certs/vmedia/:z {{ end }} Volume=/opt/openshift/tls/ironic/:/certs/ironic/:z +{{ if .PlatformData.BareMetal.BMCVerifyCA }} +Volume=/opt/openshift/bmc-ca:/certs/ca/bmc:z +{{ end }} Environment="IRONIC_RAMDISK_SSH_KEY=${IRONIC_RAMDISK_SSH_KEY}" Environment="PROVISIONING_INTERFACE=${PROVISIONING_INTERFACE}" Environment="OS_CONDUCTOR__HEARTBEAT_TIMEOUT=120" diff --git a/data/data/bootstrap/bootstrap-in-place/files/opt/openshift/bootstrap-in-place/bootstrap-in-place-post-reboot.sh b/data/data/bootstrap/bootstrap-in-place/files/opt/openshift/bootstrap-in-place/bootstrap-in-place-post-reboot.sh index ea5f5e1fb84..c45ac4c061c 100755 --- a/data/data/bootstrap/bootstrap-in-place/files/opt/openshift/bootstrap-in-place/bootstrap-in-place-post-reboot.sh +++ b/data/data/bootstrap/bootstrap-in-place/files/opt/openshift/bootstrap-in-place/bootstrap-in-place-post-reboot.sh @@ -13,7 +13,7 @@ function wait_for_api { } # This is required since the progress service (https://github.com/openshift/installer/blob/dd9047c4c119e942331f702a4b7da85c60042da5/data/data/bootstrap/files/usr/local/bin/report-progress.sh#L22-L33), -# usually dedicated to creating the bootstrap ConfigMap, will fail to create this configmap in case of bootstrap-in-place single node deployment, +# usually dedicated to creating the bootstrap ConfigMap, will fail to create this configmap in case of bootstrap-in-place single node deployment, # due to the lack of a control plane when bootkube is complete function signal_bootstrap_complete { until oc get cm bootstrap -n kube-system &> /dev/null diff --git a/data/data/install.openshift.io_installconfigs.yaml b/data/data/install.openshift.io_installconfigs.yaml index f9aa81ea52d..bcc8ad6e9c7 100644 --- a/data/data/install.openshift.io_installconfigs.yaml +++ b/data/data/install.openshift.io_installconfigs.yaml @@ -5599,6 +5599,8 @@ spec: type: string maxItems: 2 type: array + bmcVerifyCA: + type: string bootstrapExternalStaticDNS: description: |- BootstrapExternalStaticDNS is the static network DNS of the bootstrap node. diff --git a/pkg/asset/ignition/bootstrap/baremetal/template.go b/pkg/asset/ignition/bootstrap/baremetal/template.go index a873ec91af8..01bf61e282d 100644 --- a/pkg/asset/ignition/bootstrap/baremetal/template.go +++ b/pkg/asset/ignition/bootstrap/baremetal/template.go @@ -89,6 +89,8 @@ type TemplateData struct { // AdditionalNTPServers holds a list of additional NTP servers to be used for provisioning AdditionalNTPServers []string + + BMCVerifyCA string } func externalURLs(apiVIPs []string, protocol string) (externalURLv4 string, externalURLv6 string) { @@ -126,6 +128,7 @@ func GetTemplateData(config *baremetal.Platform, networks []types.MachineNetwork templateData.ExternalStaticGateway = config.BootstrapExternalStaticGateway templateData.ExternalStaticDNS = config.BootstrapExternalStaticDNS templateData.ExternalMACAddress = config.ExternalMACAddress + templateData.BMCVerifyCA = config.BMCVerifyCA if len(config.AdditionalNTPServers) > 0 { templateData.AdditionalNTPServers = config.AdditionalNTPServers diff --git a/pkg/asset/ignition/bootstrap/common.go b/pkg/asset/ignition/bootstrap/common.go index b2abdd29275..4dc9ac94a83 100644 --- a/pkg/asset/ignition/bootstrap/common.go +++ b/pkg/asset/ignition/bootstrap/common.go @@ -171,6 +171,7 @@ func (a *Common) Dependencies() []asset.Asset { &tls.RootCA{}, &tls.ServiceAccountKeyPair{}, &tls.IronicTLSCert{}, + &tls.BMCVerifyCA{}, &releaseimage.Image{}, new(rhcos.Image), } @@ -672,6 +673,7 @@ func (a *Common) addParentFiles(dependencies asset.Parents) { &tls.ServiceAccountKeyPair{}, &tls.JournalCertKey{}, &tls.IronicTLSCert{}, + &tls.BMCVerifyCA{}, } { dependencies.Get(asset) diff --git a/pkg/asset/manifests/bmcverifycaconfigmap.go b/pkg/asset/manifests/bmcverifycaconfigmap.go new file mode 100644 index 00000000000..1e3b38f93b5 --- /dev/null +++ b/pkg/asset/manifests/bmcverifycaconfigmap.go @@ -0,0 +1,95 @@ +package manifests + +import ( + "context" + "path" + + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/yaml" + + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/tls" +) + +var ( + bmcVerifyCAConfigMapFileName = path.Join("manifests", "bmc-verify-ca-configmap.yaml") +) + +const ( + bmcVerifyCAConfigMapName = "bmc-verify-ca" + bmcVerifyCAConfigMapNamespace = "openshift-machine-api" + bmcVerifyCAConfigMapDataKey = "verify_ca.crt" +) + +// BMCVerifyCAConfigMap generates the bmc-verify-ca ConfigMap. +type BMCVerifyCAConfigMap struct { + ConfigMap *corev1.ConfigMap + File *asset.File +} + +var _ asset.WritableAsset = (*BMCVerifyCAConfigMap)(nil) + +// Name returns a human friendly name for the asset. +func (*BMCVerifyCAConfigMap) Name() string { + return "BMC Verify CA ConfigMap" +} + +// Dependencies returns all of the dependencies directly needed to generate +// the asset. +func (*BMCVerifyCAConfigMap) Dependencies() []asset.Asset { + return []asset.Asset{ + &tls.BMCVerifyCA{}, + } +} + +// Generate generates the BMC Verify CA ConfigMap. +func (bvc *BMCVerifyCAConfigMap) Generate(_ context.Context, dependencies asset.Parents) error { + bmcVerifyCA := &tls.BMCVerifyCA{} + dependencies.Get(bmcVerifyCA) + + // Only generate the ConfigMap if BMCVerifyCA has content + files := bmcVerifyCA.Files() + if len(files) == 0 { + return nil + } + + cm := &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: bmcVerifyCAConfigMapNamespace, + Name: bmcVerifyCAConfigMapName, + }, + Data: map[string]string{ + bmcVerifyCAConfigMapDataKey: string(files[0].Data), + }, + } + + cmData, err := yaml.Marshal(cm) + if err != nil { + return errors.Wrapf(err, "failed to create %s manifest", bvc.Name()) + } + bvc.ConfigMap = cm + bvc.File = &asset.File{ + Filename: bmcVerifyCAConfigMapFileName, + Data: cmData, + } + return nil +} + +// Files returns the files generated by the asset. +func (bvc *BMCVerifyCAConfigMap) Files() []*asset.File { + if bvc.File != nil { + return []*asset.File{bvc.File} + } + return []*asset.File{} +} + +// Load loads the already-rendered files back from disk. +func (bvc *BMCVerifyCAConfigMap) Load(f asset.FileFetcher) (bool, error) { + return false, nil +} diff --git a/pkg/asset/manifests/operators.go b/pkg/asset/manifests/operators.go index 74a36deb62c..da7abccc196 100644 --- a/pkg/asset/manifests/operators.go +++ b/pkg/asset/manifests/operators.go @@ -85,6 +85,7 @@ func (m *Manifests) Dependencies() []asset.Asset { &bootkube.MachineConfigServerCAConfigMap{}, &bootkube.MachineConfigServerTLSSecret{}, &bootkube.OpenshiftConfigSecretPullSecret{}, + &BMCVerifyCAConfigMap{}, } } @@ -101,8 +102,9 @@ func (m *Manifests) Generate(_ context.Context, dependencies asset.Parents) erro clusterCSIDriverConfig := &ClusterCSIDriverConfig{} imageDigestMirrorSet := &ImageDigestMirrorSet{} mcoCfgTemplate := &manifests.MCO{} + bmcVerifyCAConfigMap := &BMCVerifyCAConfigMap{} - dependencies.Get(installConfig, ingress, dns, network, infra, proxy, scheduler, imageContentSourcePolicy, imageDigestMirrorSet, clusterCSIDriverConfig, mcoCfgTemplate) + dependencies.Get(installConfig, ingress, dns, network, infra, proxy, scheduler, imageContentSourcePolicy, imageDigestMirrorSet, clusterCSIDriverConfig, mcoCfgTemplate, bmcVerifyCAConfigMap) redactedConfig, err := redactedInstallConfig(*installConfig.Config) if err != nil { @@ -140,6 +142,7 @@ func (m *Manifests) Generate(_ context.Context, dependencies asset.Parents) erro m.FileList = append(m.FileList, imageContentSourcePolicy.Files()...) m.FileList = append(m.FileList, clusterCSIDriverConfig.Files()...) m.FileList = append(m.FileList, imageDigestMirrorSet.Files()...) + m.FileList = append(m.FileList, bmcVerifyCAConfigMap.Files()...) asset.SortFiles(m.FileList) diff --git a/pkg/asset/tls/bmcverifyca.go b/pkg/asset/tls/bmcverifyca.go new file mode 100644 index 00000000000..0e336f07127 --- /dev/null +++ b/pkg/asset/tls/bmcverifyca.go @@ -0,0 +1,65 @@ +package tls + +import ( + "context" + + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/asset/installconfig" + "github.com/openshift/installer/pkg/types/baremetal" +) + +// BMCVerifyCA is the asset for the user-provided BMC verify CA certificate file. +// This CA certificate is used to verify BMC TLS certificates. +type BMCVerifyCA struct { + File *asset.File +} + +var _ asset.WritableAsset = (*BMCVerifyCA)(nil) + +// Name returns the human-friendly name of the asset. +func (*BMCVerifyCA) Name() string { + return "BMC Verify CA Certificate" +} + +// Dependencies returns the dependency of the asset. +func (*BMCVerifyCA) Dependencies() []asset.Asset { + return []asset.Asset{ + &installconfig.InstallConfig{}, + } +} + +// Generate generates the BMC verify CA file from the install config. +func (a *BMCVerifyCA) Generate(_ context.Context, dependencies asset.Parents) error { + installConfig := &installconfig.InstallConfig{} + dependencies.Get(installConfig) + + // Only generate the file for baremetal platform with BMCVerifyCA configured + if installConfig.Config.Platform.Name() != baremetal.Name { + return nil + } + + if installConfig.Config.Platform.BareMetal == nil || installConfig.Config.Platform.BareMetal.BMCVerifyCA == "" { + return nil + } + + // Create the file at rootDir/bmc-ca/verify_ca.crt (rootDir = /opt/openshift) + a.File = &asset.File{ + Filename: "bmc-ca/verify_ca.crt", + Data: []byte(installConfig.Config.Platform.BareMetal.BMCVerifyCA), + } + + return nil +} + +// Files returns the files generated by the asset. +func (a *BMCVerifyCA) Files() []*asset.File { + if a.File != nil { + return []*asset.File{a.File} + } + return []*asset.File{} +} + +// Load loads the already-generated files back from disk. +func (a *BMCVerifyCA) Load(f asset.FileFetcher) (bool, error) { + return false, nil +} diff --git a/pkg/types/baremetal/platform.go b/pkg/types/baremetal/platform.go index cd1dec376c0..8333dd0f769 100644 --- a/pkg/types/baremetal/platform.go +++ b/pkg/types/baremetal/platform.go @@ -247,4 +247,6 @@ type Platform struct { // to use for provisioning // +optional AdditionalNTPServers []string `json:"additionalNTPServers,omitempty"` + + BMCVerifyCA string `json:"bmcVerifyCA,omitempty"` }