Skip to content

Commit

Permalink
Merge pull request openshift#1654 from alvaroaleman/simplify-2
Browse files Browse the repository at this point in the history
Add a helper to create SA kubeconfigs
  • Loading branch information
openshift-ci[bot] authored Aug 5, 2022
2 parents 2fcc930 + 25fdd6b commit a5c0cce
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,7 @@ func (r *HostedControlPlaneReconciler) reconcileKubeAPIServer(ctx context.Contex
if hcp.Spec.Platform.Type == hyperv1.AWSPlatform {
podIdentityWebhookSecret := manifests.AWSPodIdentityWebhookKubeconfig(hcp.Namespace)
if _, err := createOrUpdate(ctx, r, podIdentityWebhookSecret, func() error {
return r.reconcileAWSPodIdentityWebhookKubeconfig(ctx, podIdentityWebhookSecret, hcp)
return pki.ReconcileServiceAccountKubeconfig(podIdentityWebhookSecret, rootCA, hcp, "openshift-authentication", "aws-pod-identity-webhook")
}); err != nil {
return fmt.Errorf("failecd to reconcile aws pod identity webhook kubeconfig secret: %w", err)
}
Expand Down Expand Up @@ -2059,9 +2059,14 @@ func (r *HostedControlPlaneReconciler) reconcileClusterNetworkOperator(ctx conte
func (r *HostedControlPlaneReconciler) reconcileIngressOperator(ctx context.Context, hcp *hyperv1.HostedControlPlane, releaseImage *releaseinfo.ReleaseImage, createOrUpdate upsert.CreateOrUpdateFN) error {
p := ingressoperator.NewParams(hcp, releaseImage.Version(), releaseImage.ComponentImages(), r.SetDefaultSecurityContext, hcp.Spec.Platform.Type)

rootCASecret := manifests.RootCASecret(hcp.Namespace)
if err := r.Client.Get(ctx, client.ObjectKeyFromObject(rootCASecret), rootCASecret); err != nil {
return err
}

kubeconfig := manifests.IngressOperatorKubeconfig(hcp.Namespace)
if _, err := createOrUpdate(ctx, r, kubeconfig, func() error {
return r.reconcileIngressOperatorKubeconfig(ctx, kubeconfig, hcp)
return pki.ReconcileServiceAccountKubeconfig(kubeconfig, rootCASecret, hcp, "openshift-ingress-operator", "ingress-operator")
}); err != nil {
return fmt.Errorf("failed to reconcile ingressoperator kubeconfig: %w", err)
}
Expand All @@ -2077,19 +2082,6 @@ func (r *HostedControlPlaneReconciler) reconcileIngressOperator(ctx context.Cont
return nil
}

func (r *HostedControlPlaneReconciler) reconcileIngressOperatorKubeconfig(ctx context.Context, s *corev1.Secret, hcp *hyperv1.HostedControlPlane) error {
rootCASecret := manifests.RootCASecret(hcp.Namespace)
if err := r.Client.Get(ctx, client.ObjectKeyFromObject(rootCASecret), rootCASecret); err != nil {
return err
}
if err := pki.ReconcileIngressOperatorClientCertSecret(s, rootCASecret, config.OwnerRefFrom(hcp)); err != nil {
return err
}

apiServerPort := util.APIPortWithDefault(hcp, config.DefaultAPIServerPort)
return kas.ReconcileIngressOperatorKubeconfigSecret(s, rootCASecret, config.OwnerRefFrom(hcp), apiServerPort)
}

func (r *HostedControlPlaneReconciler) reconcileOperatorLifecycleManager(ctx context.Context, hcp *hyperv1.HostedControlPlane, releaseImage *releaseinfo.ReleaseImage, packageServerAddress string, createOrUpdate upsert.CreateOrUpdateFN) error {
p := olm.NewOperatorLifecycleManagerParams(hcp, releaseImage.ComponentImages(), releaseImage.Version(), r.SetDefaultSecurityContext)

Expand Down Expand Up @@ -2682,19 +2674,6 @@ func (r *HostedControlPlaneReconciler) etcdStatefulSetCondition(ctx context.Cont

}

func (r *HostedControlPlaneReconciler) reconcileAWSPodIdentityWebhookKubeconfig(ctx context.Context, s *corev1.Secret, hcp *hyperv1.HostedControlPlane) error {
rootCASecret := manifests.RootCASecret(hcp.Namespace)
if err := r.Client.Get(ctx, client.ObjectKeyFromObject(rootCASecret), rootCASecret); err != nil {
return err
}
if err := pki.ReconcileAWSPodIdentityWebhookClientCertSecret(s, rootCASecret, config.OwnerRefFrom(hcp)); err != nil {
return err
}

apiServerPort := util.APIPortWithDefault(hcp, config.DefaultAPIServerPort)
return kas.ReconcileAWSPodIdentityWebhookKubeconfigSecret(s, rootCASecret, config.OwnerRefFrom(hcp), apiServerPort)
}

func (r *HostedControlPlaneReconciler) reconcileCloudControllerManager(ctx context.Context, hcp *hyperv1.HostedControlPlane, releaseImage *releaseinfo.ReleaseImage, createOrUpdate upsert.CreateOrUpdateFN) error {
switch hcp.Spec.Platform.Type {
case hyperv1.PowerVSPlatform:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"fmt"

corev1 "k8s.io/api/core/v1"
clientcmd "k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"

"github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/manifests"
"github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/pki"
Expand All @@ -19,26 +17,14 @@ const (

func ReconcileServiceKubeconfigSecret(secret, cert, ca *corev1.Secret, ownerRef config.OwnerRef, apiServerPort int32) error {
svcURL := InClusterKASURL(secret.Namespace, apiServerPort)
return reconcileKubeconfig(secret, cert, ca, svcURL, "", "service", ownerRef)
return pki.ReconcileKubeConfig(secret, cert, ca, svcURL, "", "service", ownerRef)
}

func ReconcileServiceCAPIKubeconfigSecret(secret, cert, ca *corev1.Secret, ownerRef config.OwnerRef, apiServerPort int32) error {
svcURL := InClusterKASURL(secret.Namespace, apiServerPort)
// The client used by CAPI machine controller expects the kubeconfig to have this key
// https://github.com/kubernetes-sigs/cluster-api/blob/5c85a0a01ee44ecf7c8a3c3fdc867a88af87d73c/util/secret/secret.go#L29-L33
return reconcileKubeconfig(secret, cert, ca, svcURL, "value", "capi", ownerRef)
}

func ReconcileIngressOperatorKubeconfigSecret(secret, ca *corev1.Secret, ownerRef config.OwnerRef, apiServerPort int32) error {
svcURL := InClusterKASURL(secret.Namespace, apiServerPort)
// The secret that holds the kubeconfig and the one that holds the certs are the same
return reconcileKubeconfig(secret, secret, ca, svcURL, "", "ingress-operator", ownerRef)
}

func ReconcileAWSPodIdentityWebhookKubeconfigSecret(secret, ca *corev1.Secret, ownerRef config.OwnerRef, apiServerPort int32) error {
svcURL := InClusterKASURL(secret.Namespace, apiServerPort)
// The secret that holds the kubeconfig and the one that holds the certs are the same
return reconcileKubeconfig(secret, secret, ca, svcURL, "", "aws-pod-identity-webhook", ownerRef)
return pki.ReconcileKubeConfig(secret, cert, ca, svcURL, "value", "capi", ownerRef)
}

func InClusterKASURL(namespace string, apiServerPort int32) string {
Expand All @@ -56,63 +42,13 @@ func InClusterKASReadyURL(namespace string, securePort *int32) string {

func ReconcileLocalhostKubeconfigSecret(secret, cert, ca *corev1.Secret, ownerRef config.OwnerRef, apiServerPort int32) error {
localhostURL := fmt.Sprintf("https://localhost:%d", apiServerListenPort)
return reconcileKubeconfig(secret, cert, ca, localhostURL, "", manifests.KubeconfigScopeLocal, ownerRef)
return pki.ReconcileKubeConfig(secret, cert, ca, localhostURL, "", manifests.KubeconfigScopeLocal, ownerRef)
}

func ReconcileExternalKubeconfigSecret(secret, cert, ca *corev1.Secret, ownerRef config.OwnerRef, externalURL, secretKey string) error {
return reconcileKubeconfig(secret, cert, ca, externalURL, secretKey, manifests.KubeconfigScopeExternal, ownerRef)
return pki.ReconcileKubeConfig(secret, cert, ca, externalURL, secretKey, manifests.KubeconfigScopeExternal, ownerRef)
}

func ReconcileBootstrapKubeconfigSecret(secret, cert, ca *corev1.Secret, ownerRef config.OwnerRef, externalURL string) error {
return reconcileKubeconfig(secret, cert, ca, externalURL, "", manifests.KubeconfigScopeBootstrap, ownerRef)
}

func reconcileKubeconfig(secret, cert, ca *corev1.Secret, url string, key string, scope manifests.KubeconfigScope, ownerRef config.OwnerRef) error {
ownerRef.ApplyTo(secret)
caBytes := ca.Data[pki.CASignerCertMapKey]
crtBytes, keyBytes := cert.Data[corev1.TLSCertKey], cert.Data[corev1.TLSPrivateKeyKey]
kubeCfgBytes, err := generateKubeConfig(url, crtBytes, keyBytes, caBytes)
if err != nil {
return fmt.Errorf("failed to generate kubeconfig: %w", err)
}
if secret.Data == nil {
secret.Data = map[string][]byte{}
}
if key == "" {
key = KubeconfigKey
}
if secret.Labels == nil {
secret.Labels = map[string]string{}
}
secret.Labels[manifests.KubeconfigScopeLabel] = string(scope)
secret.Data[key] = kubeCfgBytes
return nil
}

func generateKubeConfig(url string, crtBytes, keyBytes, caBytes []byte) ([]byte, error) {
kubeCfg := clientcmdapi.Config{
Kind: "Config",
APIVersion: "v1",
}
kubeCfg.Clusters = map[string]*clientcmdapi.Cluster{
"cluster": {
Server: url,
CertificateAuthorityData: caBytes,
},
}
kubeCfg.AuthInfos = map[string]*clientcmdapi.AuthInfo{
"admin": {
ClientCertificateData: crtBytes,
ClientKeyData: keyBytes,
},
}
kubeCfg.Contexts = map[string]*clientcmdapi.Context{
"admin": {
Cluster: "cluster",
AuthInfo: "admin",
Namespace: "default",
},
}
kubeCfg.CurrentContext = "admin"
return clientcmd.Write(kubeCfg)
return pki.ReconcileKubeConfig(secret, cert, ca, externalURL, "", manifests.KubeconfigScopeBootstrap, ownerRef)
}
70 changes: 65 additions & 5 deletions control-plane-operator/controllers/hostedcontrolplane/pki/kas.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import (
"net"

corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/tools/clientcmd"

hyperv1 "github.com/openshift/hypershift/api/v1alpha1"
"github.com/openshift/hypershift/control-plane-operator/controllers/hostedcontrolplane/manifests"
"github.com/openshift/hypershift/support/config"
"github.com/openshift/hypershift/support/util"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

const (
Expand Down Expand Up @@ -66,12 +70,14 @@ func ReconcileKASAdminClientCertSecret(secret, ca *corev1.Secret, ownerRef confi
return reconcileSignedCert(secret, ca, ownerRef, "system:admin", []string{"system:masters"}, X509UsageClientServerAuth)
}

func ReconcileIngressOperatorClientCertSecret(secret, ca *corev1.Secret, ownerRef config.OwnerRef) error {
return reconcileSignedCert(secret, ca, ownerRef, "system:serviceaccount:openshift-ingress-operator:ingress-operator", []string{"system:serviceaccounts"}, X509UsageClientServerAuth)
}
func ReconcileServiceAccountKubeconfig(secret, ca *corev1.Secret, hcp *hyperv1.HostedControlPlane, serviceAccountNamespace, serviceAccountName string) error {
cn := "system:serviceaccount:" + serviceAccountNamespace + ":" + serviceAccountName
if err := reconcileSignedCert(secret, ca, config.OwnerRef{}, cn, []string{"system:serviceaccounts"}, X509UsageClientServerAuth); err != nil {
return fmt.Errorf("failed to reconcile serviceaccount client cert: %w", err)
}
svcURL := inClusterKASURL(hcp.Namespace, util.APIPortWithDefault(hcp, config.DefaultAPIServerPort))

func ReconcileAWSPodIdentityWebhookClientCertSecret(secret, ca *corev1.Secret, ownerRef config.OwnerRef) error {
return reconcileSignedCert(secret, ca, ownerRef, "system:serviceaccount:openshift-authentication:aws-pod-identity-webhook", []string{"system:serviceaccounts"}, X509UsageClientServerAuth)
return ReconcileKubeConfig(secret, secret, ca, svcURL, "", manifests.KubeconfigScopeLocal, config.OwnerRef{})
}

func nextIP(ip net.IP) net.IP {
Expand All @@ -93,3 +99,57 @@ func firstIP(network *net.IPNet) net.IP {
func isNumericIP(s string) bool {
return net.ParseIP(s) != nil
}

func ReconcileKubeConfig(secret, cert, ca *corev1.Secret, url string, key string, scope manifests.KubeconfigScope, ownerRef config.OwnerRef) error {
ownerRef.ApplyTo(secret)
caBytes := ca.Data[CASignerCertMapKey]
crtBytes, keyBytes := cert.Data[corev1.TLSCertKey], cert.Data[corev1.TLSPrivateKeyKey]
kubeCfgBytes, err := generateKubeConfig(url, crtBytes, keyBytes, caBytes)
if err != nil {
return fmt.Errorf("failed to generate kubeconfig: %w", err)
}
if secret.Data == nil {
secret.Data = map[string][]byte{}
}
if key == "" {
key = util.KubeconfigKey
}
if secret.Labels == nil {
secret.Labels = map[string]string{}
}
secret.Labels[manifests.KubeconfigScopeLabel] = string(scope)
secret.Data[key] = kubeCfgBytes
return nil
}

func generateKubeConfig(url string, crtBytes, keyBytes, caBytes []byte) ([]byte, error) {
kubeCfg := clientcmdapi.Config{
Kind: "Config",
APIVersion: "v1",
}
kubeCfg.Clusters = map[string]*clientcmdapi.Cluster{
"cluster": {
Server: url,
CertificateAuthorityData: caBytes,
},
}
kubeCfg.AuthInfos = map[string]*clientcmdapi.AuthInfo{
"admin": {
ClientCertificateData: crtBytes,
ClientKeyData: keyBytes,
},
}
kubeCfg.Contexts = map[string]*clientcmdapi.Context{
"admin": {
Cluster: "cluster",
AuthInfo: "admin",
Namespace: "default",
},
}
kubeCfg.CurrentContext = "admin"
return clientcmd.Write(kubeCfg)
}

func inClusterKASURL(namespace string, apiServerPort int32) string {
return fmt.Sprintf("https://%s:%d", manifests.KubeAPIServerServiceName, apiServerPort)
}

0 comments on commit a5c0cce

Please sign in to comment.