Skip to content
Merged
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
17 changes: 2 additions & 15 deletions pkg/controller/argocdregister/argocdregister_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func (r *ArgoCDRegisterController) reconcileCluster(cd *hivev1.ClusterDeployment
return reconcile.Result{}, nil
}

kubeConfigSecretName := cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef.Name
kubeConfigSecretName := cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef.Name // HIVE-2485 ✓
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment intentional?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I wanted to leave a paper trail for posterity since this is a whack-a-mole effort by nature. At worst it's harmless cruft, but ideally if someone comes along later and needs to whack more moles, they will have a useful way to search for these breadcrumbs.

If you think they're more crufty than potentially useful, I can scrub them out in a fup.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't have to scrub them per-se, but maybe label them something other than a ticket that's inaccessible to many? Or - how about we include a note where AdminKubeconfigSecretRef is defined, and all someone has to do is Find usages on that constant to see where we need to change/debug? And if that constant is just fetched and not used, we can include a note there as well. Essentially decouple the ticket and its specific use-case from here's-where-we-actually-use-kubeconfig-to-connect-to-the-cluster.

argoCDServerConfigBytes, err := r.generateArgoCDServerConfig(kubeConfigSecretName, cd.Namespace, argoCDNamespace, cdLog)
if err != nil {
return reconcile.Result{}, err
Expand Down Expand Up @@ -320,7 +320,7 @@ func (r *ArgoCDRegisterController) loadArgoCDServiceAccountToken(argoCDNamespace
}

func (r *ArgoCDRegisterController) generateArgoCDServerConfig(kubeconfigSecretName, kubeConfigSecretNamespace, argoCDNamespace string, cdLog log.FieldLogger) ([]byte, error) {
kubeconfig, err := r.loadSecretData(kubeconfigSecretName, kubeConfigSecretNamespace, adminKubeConfigKey)
kubeconfig, err := controllerutils.LoadSecretData(r.Client, kubeconfigSecretName, kubeConfigSecretNamespace, adminKubeConfigKey)
if err != nil {
cdLog.WithError(err).Error("unable to load cluster admin kubeconfig")
return nil, err
Expand Down Expand Up @@ -375,19 +375,6 @@ func tlsClientConfigBuilderFunc(kubeConfig clientcmd.ClientConfig, cdLog log.Fie
return tlsClientConfig, nil
}

func (r *ArgoCDRegisterController) loadSecretData(secretName, namespace, dataKey string) (string, error) {
s := &corev1.Secret{}
err := r.Get(context.TODO(), types.NamespacedName{Name: secretName, Namespace: namespace}, s)
if err != nil {
return "", err
}
retStr, ok := s.Data[dataKey]
if !ok {
return "", fmt.Errorf("secret %s did not contain key %s", secretName, dataKey)
}
return string(retStr), nil
}

// getPredictableSecretName generates a unique secret name by hashing the server API URL,
// which is required as all cluster secrets land in the argocd namespace.
// This code matches what is presently done in ArgoCD (util/db/cluster.go). However the actual
Expand Down
30 changes: 9 additions & 21 deletions pkg/controller/awsprivatelink/awsprivatelink_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/flowcontrol"
"k8s.io/client-go/util/retry"
"k8s.io/client-go/util/workqueue"
Expand Down Expand Up @@ -301,7 +299,13 @@ func (r *ReconcileAWSPrivateLink) Reconcile(ctx context.Context, request reconci
return reconcile.Result{}, nil
}

return r.reconcilePrivateLink(cd, &hivev1.ClusterMetadata{InfraID: *cp.Spec.InfraID, AdminKubeconfigSecretRef: *cp.Spec.AdminKubeconfigSecretRef}, logger)
return r.reconcilePrivateLink(
cd,
&hivev1.ClusterMetadata{
InfraID: *cp.Spec.InfraID,
AdminKubeconfigSecretRef: *cp.Spec.AdminKubeconfigSecretRef, // HIVE-2585: via ClusterMetadata
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have perms to view this issue but just wanted to ensure this comment is intentional

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have perms to view this issue

You do now. But that does put rather an ick on the posterity argument. Then again, hopefully someone whacking moles in this area later would be given access 🤷

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

D'oh, the comment has a typo here.

Suggested change
AdminKubeconfigSecretRef: *cp.Spec.AdminKubeconfigSecretRef, // HIVE-2585: via ClusterMetadata
AdminKubeconfigSecretRef: *cp.Spec.AdminKubeconfigSecretRef, // HIVE-2485: via ClusterMetadata

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't catch it earlier but yeah, this is a typo - 2485 not 2585

},
logger)
}

// shouldSync returns if we should sync the desired ClusterDeployment. If it returns false, it also returns
Expand Down Expand Up @@ -533,7 +537,7 @@ func (r *ReconcileAWSPrivateLink) reconcilePrivateLink(cd *hivev1.ClusterDeploym

// Figure out the API address for cluster.
apiDomain, err := initialURL(r.Client,
client.ObjectKey{Namespace: cd.Namespace, Name: clusterMetadata.AdminKubeconfigSecretRef.Name})
client.ObjectKey{Namespace: cd.Namespace, Name: clusterMetadata.AdminKubeconfigSecretRef.Name}) // HIVE-2485 ✓
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This too

if err != nil {
logger.WithError(err).Error("could not get API URL from kubeconfig")

Expand Down Expand Up @@ -1303,7 +1307,7 @@ func initialURL(c client.Client, key client.ObjectKey) (string, error) {
); err != nil {
return "", err
}
cfg, err := restConfigFromSecret(kubeconfigSecret)
cfg, err := controllerutils.RestConfigFromSecret(kubeconfigSecret, true)
if err != nil {
return "", errors.Wrap(err, "failed to load the kubeconfig")
}
Expand All @@ -1315,22 +1319,6 @@ func initialURL(c client.Client, key client.ObjectKey) (string, error) {
return strings.TrimSuffix(u.Hostname(), "."), nil
}

func restConfigFromSecret(kubeconfigSecret *corev1.Secret) (*rest.Config, error) {
kubeconfigData := kubeconfigSecret.Data[constants.RawKubeconfigSecretKey]
if len(kubeconfigData) == 0 {
kubeconfigData = kubeconfigSecret.Data[constants.KubeconfigSecretKey]
}
if len(kubeconfigData) == 0 {
return nil, errors.New("kubeconfig secret does not contain necessary data")
}
config, err := clientcmd.Load(kubeconfigData)
if err != nil {
return nil, err
}
kubeConfig := clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{})
return kubeConfig.ClientConfig()
}

// awsErrCodeEquals returns true if the error matches all these conditions:
// - err is of type awserr.Error
// - Error.Code() equals code
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/awsprivatelink/cleanup.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (r *ReconcileAWSPrivateLink) cleanupPreviousProvisionAttempt(cd *hivev1.Clu
}
metadata := &hivev1.ClusterMetadata{
InfraID: *cp.Spec.PrevInfraID,
AdminKubeconfigSecretRef: cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef,
AdminKubeconfigSecretRef: cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef, // HIVE-2485: via ClusterMetadata
}

if err := r.cleanupPrivateLink(cd, metadata, logger); err != nil {
Expand Down Expand Up @@ -138,7 +138,7 @@ func (r *ReconcileAWSPrivateLink) cleanupHostedZone(awsClient awsclient.Client,

if hzID == "" { // since we don't have the hz ID, we try to discover it to prevent leaks
apiDomain, err := initialURL(r.Client,
client.ObjectKey{Namespace: cd.Namespace, Name: metadata.AdminKubeconfigSecretRef.Name})
client.ObjectKey{Namespace: cd.Namespace, Name: metadata.AdminKubeconfigSecretRef.Name}) // HIVE-2485 ✓
if apierrors.IsNotFound(err) {
logger.Info("no hostedZoneID in status and admin kubeconfig does not exist, skipping hosted zone cleanup")
return nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/clusterclaim/clusterclaim_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ func (r *ReconcileClusterClaim) applyHiveClaimOwnerRole(claim *hivev1.ClusterCla
APIGroups: []string{corev1.GroupName},
Resources: []string{"secrets"},
ResourceNames: []string{
cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef.Name,
cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef.Name, // HIVE-2485: n/a
cd.Spec.ClusterMetadata.AdminPasswordSecretRef.Name,
},
Verbs: []string{"get"},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,14 @@ func (r *ReconcileClusterDeployment) addAdditionalKubeconfigCAs(cd *hivev1.Clust
cdLog log.FieldLogger) error {

adminKubeconfigSecret := &corev1.Secret{}
if err := r.Get(context.Background(), types.NamespacedName{Namespace: cd.Namespace, Name: cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef.Name}, adminKubeconfigSecret); err != nil {
if err := r.Get(
context.Background(),
types.NamespacedName{
Namespace: cd.Namespace,
// HIVE-2485: No need to scrub here
Name: cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef.Name,
},
adminKubeconfigSecret); err != nil {
cdLog.WithError(err).Error("failed to get admin kubeconfig secret")
return err
}
Expand Down Expand Up @@ -658,6 +665,7 @@ func (r *ReconcileClusterDeployment) reconcile(request reconcile.Request, cd *hi
}

// Add cluster deployment as additional owner reference to admin secrets
// HIVE-2485: No need to scrub here
if err := r.addOwnershipToSecret(cd, cdLog, cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef.Name); err != nil {
return reconcile.Result{}, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/clusterdeployment/clusterinstalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (r *ReconcileClusterDeployment) reconcileExistingInstallingClusterInstall(c
if met := ci.Spec.ClusterMetadata; met != nil &&
met.InfraID != "" &&
met.ClusterID != "" &&
met.AdminKubeconfigSecretRef.Name != "" &&
met.AdminKubeconfigSecretRef.Name != "" && // HIVE-2485: via ClusterMetadata
met.AdminPasswordSecretRef != nil &&
met.AdminPasswordSecretRef.Name != "" {
if !reflect.DeepEqual(cd.Spec.ClusterMetadata, ci.Spec.ClusterMetadata) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/clusterdeployment/clusterprovisions.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ func (r *ReconcileClusterDeployment) reconcileExistingProvision(cd *hivev1.Clust
clusterMetadata.ClusterID = *provision.Spec.ClusterID
}
if provision.Spec.AdminKubeconfigSecretRef != nil {
clusterMetadata.AdminKubeconfigSecretRef = *provision.Spec.AdminKubeconfigSecretRef
clusterMetadata.AdminKubeconfigSecretRef = *provision.Spec.AdminKubeconfigSecretRef // HIVE-2485: via ClusterMetadata
}
if provision.Spec.AdminPasswordSecretRef != nil {
clusterMetadata.AdminPasswordSecretRef = provision.Spec.AdminPasswordSecretRef
Expand Down
59 changes: 56 additions & 3 deletions pkg/controller/utils/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,76 @@ package utils

import (
"context"
"errors"
"fmt"

"github.com/openshift/hive/pkg/constants"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/clientcmd/api"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// LoadSecretData loads a given secret key and returns it's data as a string.
// LoadSecretData loads a given secret key and returns its data as a string.
func LoadSecretData(c client.Client, secretName, namespace, dataKey string) (string, error) {
s := &corev1.Secret{}
err := c.Get(context.TODO(), types.NamespacedName{Name: secretName, Namespace: namespace}, s)
if err != nil {
return "", err
}
retStr, ok := s.Data[dataKey]
retBytes, ok := s.Data[dataKey]
if !ok {
return "", fmt.Errorf("secret %s did not contain key %s", secretName, dataKey)
}
return string(retStr), nil
switch dataKey {
case constants.KubeconfigSecretKey, constants.RawKubeconfigSecretKey:
if _, err := validateKubeconfig(retBytes); err != nil {
return "", err
}
}
return string(retBytes), nil
}

// RestConfigFromSecret accepts a Secret containing `kubeconfig` and/or `raw-kubeconfig` keys
// and returns a rest.Config loaded therefrom.
// If tryRaw is true, we will look for `raw-kubeconfig` first and use it if present, falling
// back to `kubeconfig` otherwise.
// The error return is non-nil if:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The error return is non-nil if:
// The error returned is non-nil if:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was intentionally a noun ("the error return variable"?) but I can change it in a fup if it bugs ya :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh - either makes sense to me so ignore

// - The Secret's Data does not contain the [raw-]kubeconfig key(s)
// - The kubeconfig data cannot be Load()ed
// - The kubeconfig is insecure
func RestConfigFromSecret(kubeconfigSecret *corev1.Secret, tryRaw bool) (*rest.Config, error) {
var kubeconfigData []byte
if tryRaw {
kubeconfigData = kubeconfigSecret.Data[constants.RawKubeconfigSecretKey]
}
if len(kubeconfigData) == 0 {
kubeconfigData = kubeconfigSecret.Data[constants.KubeconfigSecretKey]
}
if len(kubeconfigData) == 0 {
return nil, errors.New("kubeconfig secret does not contain necessary data")
}
config, err := validateKubeconfig(kubeconfigData)
if err != nil {
return nil, err
}
kubeConfig := clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{})
return kubeConfig.ClientConfig()
}

// validateKubeconfig ensures the kubeconfig represented by kc does not use insecure paths.
// HIVE-2485
func validateKubeconfig(kc []byte) (*api.Config, error) {
config, err := clientcmd.Load(kc)
if err != nil {
return nil, err
}
for k, ai := range config.AuthInfos {
if ai.Exec != nil {
return nil, fmt.Errorf("insecure exec in AuthInfos[%s]", k)
}
}
return config, nil
}
3 changes: 2 additions & 1 deletion pkg/remoteclient/kubeconfig.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package remoteclient

import (
"github.com/openshift/hive/pkg/controller/utils"
"github.com/openshift/hive/pkg/util/scheme"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/discovery"
Expand Down Expand Up @@ -81,5 +82,5 @@ func (b *kubeconfigBuilder) UseSecondaryAPIURL() Builder {
}

func (b *kubeconfigBuilder) RESTConfig() (*rest.Config, error) {
return restConfigFromSecret(b.secret)
return utils.RestConfigFromSecret(b.secret, false)
}
18 changes: 2 additions & 16 deletions pkg/remoteclient/remoteclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ import (
kubeclient "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"

hivev1 "github.com/openshift/hive/apis/hive/v1"
"github.com/openshift/hive/pkg/constants"
"github.com/openshift/hive/pkg/controller/utils"
"github.com/openshift/hive/pkg/util/scheme"
)
Expand Down Expand Up @@ -291,23 +289,11 @@ func unadulteratedRESTConfig(c client.Client, cd *hivev1.ClusterDeployment) (*re
kubeconfigSecret := &corev1.Secret{}
if err := c.Get(
context.Background(),
// HIVE-2485 ✓
client.ObjectKey{Namespace: cd.Namespace, Name: cd.Spec.ClusterMetadata.AdminKubeconfigSecretRef.Name},
kubeconfigSecret,
); err != nil {
return nil, errors.Wrap(err, "could not get admin kubeconfig secret")
}
return restConfigFromSecret(kubeconfigSecret)
}

func restConfigFromSecret(kubeconfigSecret *corev1.Secret) (*rest.Config, error) {
kubeconfigData, ok := kubeconfigSecret.Data[constants.KubeconfigSecretKey]
if !ok {
return nil, errors.Errorf("kubeconfig secret does not contain %q data", constants.KubeconfigSecretKey)
}
config, err := clientcmd.Load(kubeconfigData)
if err != nil {
return nil, err
}
kubeConfig := clientcmd.NewDefaultClientConfig(*config, &clientcmd.ConfigOverrides{})
return kubeConfig.ClientConfig()
return utils.RestConfigFromSecret(kubeconfigSecret, false)
}