1
0
mirror of https://github.com/openshift/installer.git synced 2026-02-05 06:46:36 +01:00
Files
installer/pkg/asset/manifests/openshift.go
Thuan Vo d67b14e479 CORS-4055: migrate credential provider check to AWS SDK v2
This commit is an incremental step to migrate AWS API calls
to AWS SDK v2. This focuses on handlers that retrieve the source
or provider of credentials, for example, via shared credential file
and via environment variables.

Note: these logics are to determine whether the credential provider
is static, which is safe to transfer to the cluster as-is in Mint and
Passthrough credentialsMode.
2026-01-27 12:03:27 -08:00

341 lines
12 KiB
Go

package manifests
import (
"context"
"encoding/base64"
"fmt"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/gophercloud/utils/v2/openstack/clientconfig"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/yaml"
"github.com/openshift/installer/pkg/asset"
"github.com/openshift/installer/pkg/asset/installconfig"
installconfigaws "github.com/openshift/installer/pkg/asset/installconfig/aws"
"github.com/openshift/installer/pkg/asset/installconfig/gcp"
"github.com/openshift/installer/pkg/asset/installconfig/ibmcloud"
"github.com/openshift/installer/pkg/asset/installconfig/ovirt"
"github.com/openshift/installer/pkg/asset/machines"
osmachine "github.com/openshift/installer/pkg/asset/machines/openstack"
openstackmanifests "github.com/openshift/installer/pkg/asset/manifests/openstack"
"github.com/openshift/installer/pkg/asset/openshiftinstall"
"github.com/openshift/installer/pkg/asset/password"
"github.com/openshift/installer/pkg/asset/rhcos"
"github.com/openshift/installer/pkg/asset/templates/content/openshift"
"github.com/openshift/installer/pkg/types"
awstypes "github.com/openshift/installer/pkg/types/aws"
azuretypes "github.com/openshift/installer/pkg/types/azure"
baremetaltypes "github.com/openshift/installer/pkg/types/baremetal"
gcptypes "github.com/openshift/installer/pkg/types/gcp"
ibmcloudtypes "github.com/openshift/installer/pkg/types/ibmcloud"
openstacktypes "github.com/openshift/installer/pkg/types/openstack"
ovirttypes "github.com/openshift/installer/pkg/types/ovirt"
powervctypes "github.com/openshift/installer/pkg/types/powervc"
vspheretypes "github.com/openshift/installer/pkg/types/vsphere"
)
const (
openshiftManifestDir = "openshift"
)
var (
_ asset.WritableAsset = (*Openshift)(nil)
)
// Openshift generates the dependent resource manifests for openShift (as against bootkube)
type Openshift struct {
FileList []*asset.File
}
// Name returns a human friendly name for the operator
func (o *Openshift) Name() string {
return "Openshift Manifests"
}
// Dependencies returns all of the dependencies directly needed by the
// Openshift asset
func (o *Openshift) Dependencies() []asset.Asset {
return []asset.Asset{
&installconfig.InstallConfig{},
&installconfig.ClusterID{},
&password.KubeadminPassword{},
&openshiftinstall.Config{},
&FeatureGate{},
&openshift.CloudCredsSecret{},
&openshift.KubeadminPasswordSecret{},
&openshift.RoleCloudCredsSecretReader{},
&openshift.BaremetalConfig{},
new(rhcos.Image),
&openshift.AzureCloudProviderSecret{},
}
}
// Generate generates the respective operator config.yml files
//
//nolint:gocyclo
func (o *Openshift) Generate(ctx context.Context, dependencies asset.Parents) error {
installConfig := &installconfig.InstallConfig{}
clusterID := &installconfig.ClusterID{}
kubeadminPassword := &password.KubeadminPassword{}
openshiftInstall := &openshiftinstall.Config{}
featureGate := &FeatureGate{}
dependencies.Get(installConfig, kubeadminPassword, clusterID, openshiftInstall, featureGate)
var cloudCreds cloudCredsSecretData
platform := installConfig.Config.Platform.Name()
switch platform {
case awstypes.Name:
awsconfig, err := installconfigaws.GetConfigWithOptions(ctx, config.WithRegion(installConfig.AWS.Region))
if err != nil {
return err
}
creds, err := awsconfig.Credentials.Retrieve(ctx)
if err != nil {
return fmt.Errorf("failed to retrieve aws credentials: %w", err)
}
if !installconfigaws.IsStaticCredentials(creds) {
switch {
case installConfig.Config.CredentialsMode == "":
return errors.Errorf("AWS credentials provided by %s are not valid for default credentials mode", creds.Source)
case installConfig.Config.CredentialsMode != types.ManualCredentialsMode:
return errors.Errorf("AWS credentials provided by %s are not valid for %s credentials mode", creds.Source, installConfig.Config.CredentialsMode)
}
}
cloudCreds = cloudCredsSecretData{
AWS: &AwsCredsSecretData{
Base64encodeAccessKeyID: base64.StdEncoding.EncodeToString([]byte(creds.AccessKeyID)),
Base64encodeSecretAccessKey: base64.StdEncoding.EncodeToString([]byte(creds.SecretAccessKey)),
},
}
case azuretypes.Name:
resourceGroupName := installConfig.Config.Azure.ClusterResourceGroupName(clusterID.InfraID)
session, err := installConfig.Azure.Session()
if err != nil {
return err
}
creds := session.Credentials
cloudCreds = cloudCredsSecretData{
Azure: &AzureCredsSecretData{
Base64encodeSubscriptionID: base64.StdEncoding.EncodeToString([]byte(creds.SubscriptionID)),
Base64encodeClientID: base64.StdEncoding.EncodeToString([]byte(creds.ClientID)),
Base64encodeClientSecret: base64.StdEncoding.EncodeToString([]byte(creds.ClientSecret)),
Base64encodeTenantID: base64.StdEncoding.EncodeToString([]byte(creds.TenantID)),
Base64encodeResourcePrefix: base64.StdEncoding.EncodeToString([]byte(clusterID.InfraID)),
Base64encodeResourceGroup: base64.StdEncoding.EncodeToString([]byte(resourceGroupName)),
Base64encodeRegion: base64.StdEncoding.EncodeToString([]byte(installConfig.Config.Azure.Region)),
},
}
case gcptypes.Name:
session, err := gcp.GetSession(ctx)
if err != nil {
return err
}
creds := session.Credentials.JSON
cloudCreds = cloudCredsSecretData{
GCP: &GCPCredsSecretData{
Base64encodeServiceAccount: base64.StdEncoding.EncodeToString(creds),
},
}
case ibmcloudtypes.Name:
client, err := ibmcloud.NewClient(installConfig.Config.Platform.IBMCloud.ServiceEndpoints)
if err != nil {
return err
}
cloudCreds = cloudCredsSecretData{
IBMCloud: &IBMCloudCredsSecretData{
Base64encodeAPIKey: base64.StdEncoding.EncodeToString([]byte(client.GetAPIKey())),
},
}
case openstacktypes.Name, powervctypes.Name:
opts := new(clientconfig.ClientOpts)
opts.Cloud = installConfig.Config.Platform.OpenStack.Cloud
cloud, err := clientconfig.GetCloudFromYAML(opts)
if err != nil {
return err
}
var caCert []byte
if cloud.CACertFile != "" {
var err error
caCert, err = os.ReadFile(cloud.CACertFile)
if err != nil {
return err
}
// We need to replace the local cacert path with one that is used in OpenShift
cloud.CACertFile = "/etc/kubernetes/static-pod-resources/configmaps/cloud-config/ca-bundle.pem"
}
// Application credentials are easily rotated in the event of a leak and should be preferred. Encourage their use.
authTypes := sets.New(clientconfig.AuthPassword, clientconfig.AuthV2Password, clientconfig.AuthV3Password)
if cloud.AuthInfo != nil && authTypes.Has(cloud.AuthType) {
logrus.Warnf(
"clouds.yaml file is using %q type auth. Consider using the %q auth type instead to rotate credentials more easily.",
cloud.AuthType,
clientconfig.AuthV3ApplicationCredential,
)
}
clouds := make(map[string]map[string]*clientconfig.Cloud)
clouds["clouds"] = map[string]*clientconfig.Cloud{
osmachine.CloudName: cloud,
}
marshalled, err := yaml.Marshal(clouds)
if err != nil {
return err
}
cloudProviderConf, err := openstackmanifests.CloudProviderConfigSecret(cloud)
if err != nil {
return err
}
credsEncoded := base64.StdEncoding.EncodeToString(marshalled)
cloudProviderConfEncoded := base64.StdEncoding.EncodeToString(cloudProviderConf)
caCertEncoded := base64.StdEncoding.EncodeToString(caCert)
cloudCreds = cloudCredsSecretData{
OpenStack: &OpenStackCredsSecretData{
Base64encodeCloudsYAML: credsEncoded,
Base64encodeCloudsConf: cloudProviderConfEncoded,
Base64encodeCACert: caCertEncoded,
},
}
case vspheretypes.Name:
vsphereCredList := make([]*VSphereCredsSecretData, 0)
for _, vCenter := range installConfig.Config.VSphere.VCenters {
vsphereCred := VSphereCredsSecretData{
VCenter: vCenter.Server,
Base64encodeUsername: base64.StdEncoding.EncodeToString([]byte(vCenter.Username)),
Base64encodePassword: base64.StdEncoding.EncodeToString([]byte(vCenter.Password)),
}
vsphereCredList = append(vsphereCredList, &vsphereCred)
}
cloudCreds = cloudCredsSecretData{
VSphere: &vsphereCredList,
}
case ovirttypes.Name:
conf, err := ovirt.NewConfig()
if err != nil {
return err
}
if len(conf.CABundle) == 0 && len(conf.CAFile) > 0 {
content, err := os.ReadFile(conf.CAFile)
if err != nil {
return errors.Wrapf(err, "failed to read the cert file: %s", conf.CAFile)
}
conf.CABundle = strings.TrimSpace(string(content))
}
cloudCreds = cloudCredsSecretData{
Ovirt: &OvirtCredsSecretData{
Base64encodeURL: base64.StdEncoding.EncodeToString([]byte(conf.URL)),
Base64encodeUsername: base64.StdEncoding.EncodeToString([]byte(conf.Username)),
Base64encodePassword: base64.StdEncoding.EncodeToString([]byte(conf.Password)),
Base64encodeInsecure: base64.StdEncoding.EncodeToString([]byte(strconv.FormatBool(conf.Insecure))),
Base64encodeCABundle: base64.StdEncoding.EncodeToString([]byte(conf.CABundle)),
},
}
}
templateData := &openshiftTemplateData{
CloudCreds: cloudCreds,
Base64EncodedKubeadminPwHash: base64.StdEncoding.EncodeToString(kubeadminPassword.PasswordHash),
}
cloudCredsSecret := &openshift.CloudCredsSecret{}
kubeadminPasswordSecret := &openshift.KubeadminPasswordSecret{}
roleCloudCredsSecretReader := &openshift.RoleCloudCredsSecretReader{}
baremetalConfig := &openshift.BaremetalConfig{}
rhcosImage := new(rhcos.Image)
dependencies.Get(
cloudCredsSecret,
kubeadminPasswordSecret,
roleCloudCredsSecretReader,
baremetalConfig,
rhcosImage)
assetData := map[string][]byte{
"99_kubeadmin-password-secret.yaml": applyTemplateData(kubeadminPasswordSecret.Files()[0].Data, templateData),
}
switch platform {
case awstypes.Name, openstacktypes.Name, powervctypes.Name, vspheretypes.Name, azuretypes.Name, gcptypes.Name, ibmcloudtypes.Name, ovirttypes.Name:
if installConfig.Config.CredentialsMode != types.ManualCredentialsMode {
assetData["99_cloud-creds-secret.yaml"] = applyTemplateData(cloudCredsSecret.Files()[0].Data, templateData)
}
assetData["99_role-cloud-creds-secret-reader.yaml"] = applyTemplateData(roleCloudCredsSecretReader.Files()[0].Data, templateData)
case baremetaltypes.Name:
bmTemplateData := baremetalTemplateData{
Baremetal: installConfig.Config.Platform.BareMetal,
ProvisioningOSDownloadURL: rhcosImage.ControlPlane,
}
assetData["99_baremetal-provisioning-config.yaml"] = applyTemplateData(baremetalConfig.Files()[0].Data, bmTemplateData)
}
o.FileList = []*asset.File{}
for name, data := range assetData {
if len(data) == 0 {
continue
}
o.FileList = append(o.FileList, &asset.File{
Filename: path.Join(openshiftManifestDir, name),
Data: data,
})
}
o.FileList = append(o.FileList, openshiftInstall.Files()...)
o.FileList = append(o.FileList, featureGate.Files()...)
asset.SortFiles(o.FileList)
return nil
}
// Files returns the files generated by the asset.
func (o *Openshift) Files() []*asset.File {
return o.FileList
}
// Load returns the openshift asset from disk.
func (o *Openshift) Load(f asset.FileFetcher) (bool, error) {
yamlFileList, err := f.FetchByPattern(filepath.Join(openshiftManifestDir, "*.yaml"))
if err != nil {
return false, errors.Wrap(err, "failed to load *.yaml files")
}
ymlFileList, err := f.FetchByPattern(filepath.Join(openshiftManifestDir, "*.yml"))
if err != nil {
return false, errors.Wrap(err, "failed to load *.yml files")
}
jsonFileList, err := f.FetchByPattern(filepath.Join(openshiftManifestDir, "*.json"))
if err != nil {
return false, errors.Wrap(err, "failed to load *.json files")
}
fileList := append(yamlFileList, ymlFileList...)
fileList = append(fileList, jsonFileList...)
for _, file := range fileList {
if machines.IsMachineManifest(file) {
continue
}
o.FileList = append(o.FileList, file)
}
asset.SortFiles(o.FileList)
return len(o.FileList) > 0, nil
}