Skip to content

Commit 36464d7

Browse files
committed
include a shard-base context in kubeconfigs
On-behalf-of: @SAP [email protected]
1 parent 65e4f13 commit 36464d7

File tree

2 files changed

+91
-54
lines changed

2 files changed

+91
-54
lines changed

internal/controller/kubeconfig_controller.go

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23-
"net/url"
2423
"time"
2524

2625
certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
@@ -74,41 +73,37 @@ func (r *KubeconfigReconciler) Reconcile(ctx context.Context, req ctrl.Request)
7473
}
7574

7675
var (
77-
clientCertIssuer, serverCA, serverURL, serverName string
76+
rootShard *operatorv1alpha1.RootShard
77+
shard *operatorv1alpha1.Shard
78+
clientCertIssuer string
79+
serverCA string
7880
)
7981

8082
switch {
8183
case kc.Spec.Target.RootShardRef != nil:
82-
var rootShard operatorv1alpha1.RootShard
83-
if err := r.Get(ctx, types.NamespacedName{Name: kc.Spec.Target.RootShardRef.Name, Namespace: req.Namespace}, &rootShard); err != nil {
84+
if err := r.Get(ctx, types.NamespacedName{Name: kc.Spec.Target.RootShardRef.Name, Namespace: req.Namespace}, rootShard); err != nil {
8485
return ctrl.Result{}, fmt.Errorf("failed to get RootShard: %w", err)
8586
}
8687

87-
clientCertIssuer = resources.GetRootShardCAName(&rootShard, operatorv1alpha1.ClientCA)
88-
serverCA = resources.GetRootShardCAName(&rootShard, operatorv1alpha1.ServerCA)
89-
serverURL = resources.GetRootShardBaseURL(&rootShard)
90-
serverName = rootShard.Name
88+
clientCertIssuer = resources.GetRootShardCAName(rootShard, operatorv1alpha1.ClientCA)
89+
serverCA = resources.GetRootShardCAName(rootShard, operatorv1alpha1.ServerCA)
9190

9291
case kc.Spec.Target.ShardRef != nil:
93-
var shard operatorv1alpha1.Shard
94-
if err := r.Get(ctx, types.NamespacedName{Name: kc.Spec.Target.ShardRef.Name, Namespace: req.Namespace}, &shard); err != nil {
92+
if err := r.Get(ctx, types.NamespacedName{Name: kc.Spec.Target.ShardRef.Name, Namespace: req.Namespace}, shard); err != nil {
9593
return ctrl.Result{}, fmt.Errorf("failed to get Shard: %w", err)
9694
}
9795

9896
ref := shard.Spec.RootShard.Reference
9997
if ref == nil || ref.Name == "" {
10098
return ctrl.Result{}, errors.New("the Shard does not reference a (valid) RootShard")
10199
}
102-
var rootShard operatorv1alpha1.RootShard
103-
if err := r.Get(ctx, types.NamespacedName{Name: ref.Name, Namespace: req.Namespace}, &rootShard); err != nil {
100+
if err := r.Get(ctx, types.NamespacedName{Name: ref.Name, Namespace: req.Namespace}, rootShard); err != nil {
104101
return ctrl.Result{}, fmt.Errorf("failed to get RootShard: %w", err)
105102
}
106103

107104
// The client CA is shared among all shards and owned by the root shard.
108-
clientCertIssuer = resources.GetRootShardCAName(&rootShard, operatorv1alpha1.ClientCA)
109-
serverCA = resources.GetRootShardCAName(&rootShard, operatorv1alpha1.ServerCA)
110-
serverURL = resources.GetShardBaseURL(&shard)
111-
serverName = shard.Name
105+
clientCertIssuer = resources.GetRootShardCAName(rootShard, operatorv1alpha1.ClientCA)
106+
serverCA = resources.GetRootShardCAName(rootShard, operatorv1alpha1.ServerCA)
112107

113108
case kc.Spec.Target.FrontProxyRef != nil:
114109
var frontProxy operatorv1alpha1.FrontProxy
@@ -120,15 +115,12 @@ func (r *KubeconfigReconciler) Reconcile(ctx context.Context, req ctrl.Request)
120115
if ref == nil || ref.Name == "" {
121116
return ctrl.Result{}, errors.New("the FrontProxy does not reference a (valid) RootShard")
122117
}
123-
var rootShard operatorv1alpha1.RootShard
124-
if err := r.Get(ctx, types.NamespacedName{Name: frontProxy.Spec.RootShard.Reference.Name, Namespace: req.Namespace}, &rootShard); err != nil {
118+
if err := r.Get(ctx, types.NamespacedName{Name: frontProxy.Spec.RootShard.Reference.Name, Namespace: req.Namespace}, rootShard); err != nil {
125119
return ctrl.Result{}, fmt.Errorf("failed to get RootShard: %w", err)
126120
}
127121

128-
clientCertIssuer = resources.GetRootShardCAName(&rootShard, operatorv1alpha1.FrontProxyClientCA)
129-
serverCA = resources.GetRootShardCAName(&rootShard, operatorv1alpha1.ServerCA)
130-
serverURL = fmt.Sprintf("https://%s:6443", rootShard.Spec.External.Hostname)
131-
serverName = rootShard.Spec.External.Hostname
122+
clientCertIssuer = resources.GetRootShardCAName(rootShard, operatorv1alpha1.FrontProxyClientCA)
123+
serverCA = resources.GetRootShardCAName(rootShard, operatorv1alpha1.ServerCA)
132124

133125
default:
134126
return ctrl.Result{}, fmt.Errorf("no valid target for kubeconfig found")
@@ -156,14 +148,12 @@ func (r *KubeconfigReconciler) Reconcile(ctx context.Context, req ctrl.Request)
156148
return ctrl.Result{RequeueAfter: time.Second * 5}, nil
157149
}
158150

159-
rootWSURL, err := url.JoinPath(serverURL, "clusters", "root")
151+
reconciler, err := kubeconfig.KubeconfigSecretReconciler(&kc, rootShard, shard, serverCASecret, clientCertSecret)
160152
if err != nil {
161153
return ctrl.Result{}, err
162154
}
163155

164-
if err := k8creconciling.ReconcileSecrets(ctx, []k8creconciling.NamedSecretReconcilerFactory{
165-
kubeconfig.KubeconfigSecretReconciler(&kc, serverCASecret, clientCertSecret, serverName, rootWSURL),
166-
}, req.Namespace, r.Client); err != nil {
156+
if err := k8creconciling.ReconcileSecrets(ctx, []k8creconciling.NamedSecretReconcilerFactory{reconciler}, req.Namespace, r.Client); err != nil {
167157
return ctrl.Result{}, err
168158
}
169159

internal/resources/kubeconfig/secret.go

Lines changed: 75 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,49 +18,96 @@ package kubeconfig
1818

1919
import (
2020
"fmt"
21+
"net/url"
2122

2223
"k8c.io/reconciler/pkg/reconciling"
2324

2425
corev1 "k8s.io/api/core/v1"
2526
"k8s.io/client-go/tools/clientcmd"
2627
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
2728

29+
"github.com/kcp-dev/kcp-operator/internal/resources"
2830
operatorv1alpha1 "github.com/kcp-dev/kcp-operator/sdk/apis/operator/v1alpha1"
2931
)
3032

31-
func KubeconfigSecretReconciler(kubeconfig *operatorv1alpha1.Kubeconfig, caSecret, certSecret *corev1.Secret, serverName, serverURL string) reconciling.NamedSecretReconcilerFactory {
32-
return func() (string, reconciling.SecretReconciler) {
33-
return kubeconfig.Spec.SecretRef.Name, func(secret *corev1.Secret) (*corev1.Secret, error) {
34-
var config *clientcmdapi.Config
33+
func KubeconfigSecretReconciler(
34+
kubeconfig *operatorv1alpha1.Kubeconfig,
35+
rootShard *operatorv1alpha1.RootShard,
36+
shard *operatorv1alpha1.Shard,
37+
caSecret, certSecret *corev1.Secret,
38+
) (reconciling.NamedSecretReconcilerFactory, error) {
39+
config := &clientcmdapi.Config{
40+
Clusters: map[string]*clientcmdapi.Cluster{},
41+
Contexts: map[string]*clientcmdapi.Context{},
42+
AuthInfos: map[string]*clientcmdapi.AuthInfo{
43+
kubeconfig.Spec.Username: {
44+
ClientCertificateData: certSecret.Data["tls.crt"],
45+
ClientKeyData: certSecret.Data["tls.key"],
46+
},
47+
},
48+
}
3549

36-
if secret.Data == nil {
37-
secret.Data = make(map[string][]byte)
38-
}
50+
addCluster := func(name, url string) {
51+
config.Clusters[name] = &clientcmdapi.Cluster{
52+
Server: url,
53+
CertificateAuthorityData: caSecret.Data["tls.crt"],
54+
}
55+
config.Contexts[name] = &clientcmdapi.Context{
56+
Cluster: name,
57+
AuthInfo: kubeconfig.Spec.Username,
58+
}
59+
}
3960

40-
config = &clientcmdapi.Config{}
61+
switch {
62+
case kubeconfig.Spec.Target.RootShardRef != nil:
63+
if rootShard == nil {
64+
panic("RootShard must be provided when kubeconfig targets one.")
65+
}
4166

42-
config.Clusters = map[string]*clientcmdapi.Cluster{
43-
serverName: {
44-
Server: serverURL,
45-
CertificateAuthorityData: caSecret.Data["tls.crt"],
46-
},
47-
}
67+
serverURL := resources.GetRootShardBaseURL(rootShard)
68+
defaultURL, err := url.JoinPath(serverURL, "clusters", "root")
69+
if err != nil {
70+
return nil, err
71+
}
4872

49-
contextName := fmt.Sprintf("%s:%s", serverName, kubeconfig.Spec.Username)
73+
addCluster("default", defaultURL)
74+
addCluster("shard-base", serverURL)
75+
config.CurrentContext = "default"
5076

51-
config.Contexts = map[string]*clientcmdapi.Context{
52-
contextName: {
53-
Cluster: serverName,
54-
AuthInfo: kubeconfig.Spec.Username,
55-
},
56-
}
57-
config.AuthInfos = map[string]*clientcmdapi.AuthInfo{
58-
kubeconfig.Spec.Username: {
59-
ClientCertificateData: certSecret.Data["tls.crt"],
60-
ClientKeyData: certSecret.Data["tls.key"],
61-
},
77+
case kubeconfig.Spec.Target.ShardRef != nil:
78+
if shard == nil {
79+
panic("Shard must be provided when kubeconfig targets one.")
80+
}
81+
82+
serverURL := resources.GetShardBaseURL(shard)
83+
84+
addCluster("default", serverURL)
85+
addCluster("shard-base", serverURL)
86+
config.CurrentContext = "default"
87+
88+
case kubeconfig.Spec.Target.FrontProxyRef != nil:
89+
if rootShard == nil {
90+
panic("RootShard must be provided when kubeconfig targets a FrontProxy.")
91+
}
92+
93+
serverURL := fmt.Sprintf("https://%s:6443", rootShard.Spec.External.Hostname)
94+
defaultURL, err := url.JoinPath(serverURL, "clusters", "root")
95+
if err != nil {
96+
return nil, err
97+
}
98+
99+
addCluster("default", defaultURL)
100+
config.CurrentContext = "default"
101+
102+
default:
103+
panic("Called reconciler for an invalid kubeconfig, this should not have happened.")
104+
}
105+
106+
return func() (string, reconciling.SecretReconciler) {
107+
return kubeconfig.Spec.SecretRef.Name, func(secret *corev1.Secret) (*corev1.Secret, error) {
108+
if secret.Data == nil {
109+
secret.Data = make(map[string][]byte)
62110
}
63-
config.CurrentContext = contextName
64111

65112
data, err := clientcmd.Write(*config)
66113
if err != nil {
@@ -71,5 +118,5 @@ func KubeconfigSecretReconciler(kubeconfig *operatorv1alpha1.Kubeconfig, caSecre
71118

72119
return secret, nil
73120
}
74-
}
121+
}, nil
75122
}

0 commit comments

Comments
 (0)