From de5e8c78526e570fe1cb4e98b13a33871772213e Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Tue, 4 Jun 2024 00:28:41 +0530 Subject: [PATCH 01/14] Bootstrapping bundle init Signed-off-by: PrimalPimmy --- .../reconcilers/spire-bootstrap/reconciler.go | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 controllers/pkg/reconcilers/spire-bootstrap/reconciler.go diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go new file mode 100644 index 00000000..0dc87047 --- /dev/null +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -0,0 +1,184 @@ +package bootstrapsecret + +import ( + "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "math/big" + "time" + + "github.com/nephio-project/nephio/controllers/pkg/cluster" + reconcilerinterface "github.com/nephio-project/nephio/controllers/pkg/reconcilers/reconciler-interface" + "github.com/nephio-project/nephio/controllers/pkg/resource" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +func init() { + reconcilerinterface.Register("bootstrapsecrets", &reconciler{}) +} + +const ( + clusterNameKey = "nephio.org/cluster-name" + remoteNamespaceKey = "nephio.org/remote-namespace" + syncApp = "tobeinstalledonremotecluster" + bootstrapApp = "bootstrap" +) + +//+kubebuilder:rbac:groups="*",resources=secrets,verbs=get;list;watch +//+kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters,verbs=get;list;watch +//+kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters/status,verbs=get + +// SetupWithManager sets up the controller with the Manager. +func (r *reconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, c any) (map[schema.GroupVersionKind]chan event.GenericEvent, error) { + r.Client = mgr.GetClient() + + return nil, ctrl.NewControllerManagedBy(mgr). + Named("BootstrapSecretController"). + For(&corev1.Secret{}). + Complete(r) +} + +type reconciler struct { + client.Client +} + +func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := log.FromContext(ctx) + + cr := &corev1.Secret{} + if err := r.Get(ctx, req.NamespacedName, cr); err != nil { + if resource.IgnoreNotFound(err) != nil { + msg := "cannot get resource" + log.Error(err, msg) + return ctrl.Result{}, errors.Wrap(resource.IgnoreNotFound(err), msg) + } + return reconcile.Result{}, nil + } + + if resource.WasDeleted(cr) { + return reconcile.Result{}, nil + } + + if cr.GetAnnotations()[nephioAppKey] == syncApp && + cr.GetAnnotations()[clusterNameKey] != "" && + cr.GetAnnotations()[clusterNameKey] != "mgmt" { + log.Info("reconcile secret") + + clusterName := cr.GetAnnotations()[clusterNameKey] + clusterNames := strings.Split(clusterName, ",") + + for _, clusterName := range clusterNames { + secrets := &corev1.SecretList{} + if err := r.List(ctx, secrets); err != nil { + msg := "cannot list secrets" + log.Error(err, msg) + return ctrl.Result{}, errors.Wrap(err, msg) + } + found := false + for _, secret := range secrets.Items { + if strings.Contains(secret.GetName(), clusterName) { + secret := secret + clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) + if ok { + found = true + clusterClient, ready, err := clusterClient.GetClusterClient(ctx) + if err != nil { + msg := "cannot get clusterClient" + log.Error(err, msg) + return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) + } + if !ready { + log.Info("cluster not ready") + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } + + remoteNamespace := cr.Namespace + if rns, ok := cr.GetAnnotations()[remoteNamespaceKey]; ok { + remoteNamespace = rns + } + ns := &corev1.Namespace{} + if err = clusterClient.Get(ctx, types.NamespacedName{Name: remoteNamespace}, ns); err != nil { + if resource.IgnoreNotFound(err) != nil { + msg := fmt.Sprintf("cannot get namespace: %s", remoteNamespace) + log.Error(err, msg) + return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) + } + msg := fmt.Sprintf("namespace: %s, does not exist, retry...", remoteNamespace) + log.Info(msg) + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } + + bootstrapCrt, err := generateBootstrapCrt() + if err != nil { + msg := "cannot generate bootstrap.crt" + log.Error(err, msg) + return ctrl.Result{}, errors.Wrap(err, msg) + } + + newSecret := &corev1.Secret{ + ObjectMeta: cr.ObjectMeta, + Data: map[string][]byte{ + "bootstrap.crt": bootstrapCrt, + }, + } + newSecret.Namespace = remoteNamespace + newSecret.ResourceVersion = "" + newSecret.UID = "" + + if err := clusterClient.Apply(ctx, newSecret); err != nil { + msg := fmt.Sprintf("cannot apply secret to cluster %s", clusterName) + log.Error(err, msg) + return ctrl.Result{}, errors.Wrap(err, msg) + } + } + } + if found { + break + } + } + if !found { + log.Info("cluster client not found, retry...") + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } + } + } + return ctrl.Result{}, nil +} + +func generateBootstrapCrt() ([]byte, error) { + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, err + } + + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Nephio"}, + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + return nil, err + } + + certOut := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + return certOut, nil +} From efe3e1cf7a8702bf2e0042cce66d6252fd2b4b2e Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Fri, 7 Jun 2024 00:39:49 +0530 Subject: [PATCH 02/14] minor fix Signed-off-by: PrimalPimmy --- controllers/pkg/reconcilers/spire-bootstrap/reconciler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 0dc87047..ab868c1e 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -27,7 +27,7 @@ import ( ) func init() { - reconcilerinterface.Register("bootstrapsecrets", &reconciler{}) + reconcilerinterface.Register("spire-bootstrapsecrets", &reconciler{}) } const ( From a1054da902e6d6fc8d4dbe65e891962d7945b4af Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Thu, 20 Jun 2024 23:52:09 +0530 Subject: [PATCH 03/14] Cluster reconciler Signed-off-by: PrimalPimmy --- .../reconcilers/spire-bootstrap/reconciler.go | 178 ++++-------------- operators/nephio-controller-manager/main.go | 9 + 2 files changed, 44 insertions(+), 143 deletions(-) diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index ab868c1e..7f18688d 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -1,24 +1,29 @@ +/* +Copyright 2023 The Nephio Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package bootstrapsecret import ( "context" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "math/big" - "time" - - "github.com/nephio-project/nephio/controllers/pkg/cluster" + reconcilerinterface "github.com/nephio-project/nephio/controllers/pkg/reconcilers/reconciler-interface" - "github.com/nephio-project/nephio/controllers/pkg/resource" - "github.com/pkg/errors" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/cluster-api/api/v1beta1" + capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" @@ -27,17 +32,9 @@ import ( ) func init() { - reconcilerinterface.Register("spire-bootstrapsecrets", &reconciler{}) + reconcilerinterface.Register("bootstrap-spire", &reconciler{}) } -const ( - clusterNameKey = "nephio.org/cluster-name" - remoteNamespaceKey = "nephio.org/remote-namespace" - syncApp = "tobeinstalledonremotecluster" - bootstrapApp = "bootstrap" -) - -//+kubebuilder:rbac:groups="*",resources=secrets,verbs=get;list;watch //+kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters,verbs=get;list;watch //+kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters/status,verbs=get @@ -46,8 +43,8 @@ func (r *reconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, c a r.Client = mgr.GetClient() return nil, ctrl.NewControllerManagedBy(mgr). - Named("BootstrapSecretController"). - For(&corev1.Secret{}). + Named("BootstrapSpireController"). + For(&capiv1beta1.Cluster{}). Complete(r) } @@ -55,130 +52,25 @@ type reconciler struct { client.Client } +// r.List --> gets us cluster name list + func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := log.FromContext(ctx) - cr := &corev1.Secret{} - if err := r.Get(ctx, req.NamespacedName, cr); err != nil { - if resource.IgnoreNotFound(err) != nil { - msg := "cannot get resource" - log.Error(err, msg) - return ctrl.Result{}, errors.Wrap(resource.IgnoreNotFound(err), msg) - } - return reconcile.Result{}, nil - } - - if resource.WasDeleted(cr) { - return reconcile.Result{}, nil - } - - if cr.GetAnnotations()[nephioAppKey] == syncApp && - cr.GetAnnotations()[clusterNameKey] != "" && - cr.GetAnnotations()[clusterNameKey] != "mgmt" { - log.Info("reconcile secret") - - clusterName := cr.GetAnnotations()[clusterNameKey] - clusterNames := strings.Split(clusterName, ",") - - for _, clusterName := range clusterNames { - secrets := &corev1.SecretList{} - if err := r.List(ctx, secrets); err != nil { - msg := "cannot list secrets" - log.Error(err, msg) - return ctrl.Result{}, errors.Wrap(err, msg) - } - found := false - for _, secret := range secrets.Items { - if strings.Contains(secret.GetName(), clusterName) { - secret := secret - clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) - if ok { - found = true - clusterClient, ready, err := clusterClient.GetClusterClient(ctx) - if err != nil { - msg := "cannot get clusterClient" - log.Error(err, msg) - return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) - } - if !ready { - log.Info("cluster not ready") - return ctrl.Result{RequeueAfter: 10 * time.Second}, nil - } - - remoteNamespace := cr.Namespace - if rns, ok := cr.GetAnnotations()[remoteNamespaceKey]; ok { - remoteNamespace = rns - } - ns := &corev1.Namespace{} - if err = clusterClient.Get(ctx, types.NamespacedName{Name: remoteNamespace}, ns); err != nil { - if resource.IgnoreNotFound(err) != nil { - msg := fmt.Sprintf("cannot get namespace: %s", remoteNamespace) - log.Error(err, msg) - return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) - } - msg := fmt.Sprintf("namespace: %s, does not exist, retry...", remoteNamespace) - log.Info(msg) - return ctrl.Result{RequeueAfter: 10 * time.Second}, nil - } - - bootstrapCrt, err := generateBootstrapCrt() - if err != nil { - msg := "cannot generate bootstrap.crt" - log.Error(err, msg) - return ctrl.Result{}, errors.Wrap(err, msg) - } - - newSecret := &corev1.Secret{ - ObjectMeta: cr.ObjectMeta, - Data: map[string][]byte{ - "bootstrap.crt": bootstrapCrt, - }, - } - newSecret.Namespace = remoteNamespace - newSecret.ResourceVersion = "" - newSecret.UID = "" - - if err := clusterClient.Apply(ctx, newSecret); err != nil { - msg := fmt.Sprintf("cannot apply secret to cluster %s", clusterName) - log.Error(err, msg) - return ctrl.Result{}, errors.Wrap(err, msg) - } - } - } - if found { - break - } - } - if !found { - log.Info("cluster client not found, retry...") - return ctrl.Result{RequeueAfter: 10 * time.Second}, nil - } - } - } - return ctrl.Result{}, nil -} - -func generateBootstrapCrt() ([]byte, error) { - priv, err := rsa.GenerateKey(rand.Reader, 2048) + // Fetch the Cluster instance + cluster := &v1beta1.ClusterClass{} + err := r.Get(ctx, req.NamespacedName, cluster) if err != nil { - return nil, err + if client.IgnoreNotFound(err) != nil { + log.Error(err, "unable to fetch Cluster") + } + return reconcile.Result{}, client.IgnoreNotFound(err) } - template := x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - Organization: []string{"Nephio"}, - }, - NotBefore: time.Now(), - NotAfter: time.Now().Add(365 * 24 * time.Hour), - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - } + // Add your reconciliation logic here + log.Info("Reconciling Cluster", "cluster", cluster.Name) - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) - if err != nil { - return nil, err - } + // Example: Update the status if necessary - certOut := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) - return certOut, nil + return reconcile.Result{}, nil } diff --git a/operators/nephio-controller-manager/main.go b/operators/nephio-controller-manager/main.go index 559f6fff..9d77d130 100644 --- a/operators/nephio-controller-manager/main.go +++ b/operators/nephio-controller-manager/main.go @@ -43,6 +43,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" + capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" //+kubebuilder:scaffold:imports @@ -56,6 +57,7 @@ import ( //_ "github.com/nephio-project/nephio/controllers/pkg/reconcilers/ipam-specializer" _ "github.com/nephio-project/nephio/controllers/pkg/reconcilers/repository" + _ "github.com/nephio-project/nephio/controllers/pkg/reconcilers/spire-bootstrap" _ "github.com/nephio-project/nephio/controllers/pkg/reconcilers/token" //_ "github.com/nephio-project/nephio/controllers/pkg/reconcilers/vlan-specializer" ) @@ -108,6 +110,13 @@ func main() { os.Exit(1) } + err = capiv1beta1.AddToScheme(scheme) + if err != nil { + setupLog.Error(err, "cannot initializer schema with Cluster API(s)") + // klog.Errorf("error initializing scheme with Porch APIs: %s", err.Error()) + os.Exit(1) + } + managerOptions := ctrl.Options{ Scheme: scheme, MetricsBindAddress: metricsAddr, From d14b9d707cb9f0f7eeee1abf05394f9f3f99b282 Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Fri, 21 Jun 2024 00:22:39 +0530 Subject: [PATCH 04/14] Cluster reconciler Signed-off-by: PrimalPimmy --- .../pkg/reconcilers/spire-bootstrap/reconciler.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 7f18688d..94bcbe81 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -22,7 +22,6 @@ import ( reconcilerinterface "github.com/nephio-project/nephio/controllers/pkg/reconcilers/reconciler-interface" "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/cluster-api/api/v1beta1" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -58,8 +57,16 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu log := log.FromContext(ctx) // Fetch the Cluster instance - cluster := &v1beta1.ClusterClass{} - err := r.Get(ctx, req.NamespacedName, cluster) + + // List all Cluster instances + clusterList := &capiv1beta1.ClusterList{} + err := r.List(ctx, clusterList) + if err != nil { + log.Error(err, "unable to list Clusters") + return reconcile.Result{}, err + } + cluster := &capiv1beta1.Cluster{} + err = r.Get(ctx, req.NamespacedName, cluster) if err != nil { if client.IgnoreNotFound(err) != nil { log.Error(err, "unable to fetch Cluster") From e4f6ee9048ebe032e13308333e8c0b8f1fc62a9c Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Fri, 21 Jun 2024 03:15:30 +0530 Subject: [PATCH 05/14] sending bundle to remote cluster Signed-off-by: PrimalPimmy --- .../reconcilers/spire-bootstrap/reconciler.go | 105 ++++++++++++++++-- 1 file changed, 96 insertions(+), 9 deletions(-) diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 94bcbe81..5473fc09 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -18,10 +18,18 @@ package bootstrapsecret import ( "context" + "fmt" + "strings" + "time" reconcilerinterface "github.com/nephio-project/nephio/controllers/pkg/reconcilers/reconciler-interface" + "github.com/nephio-project/nephio/controllers/pkg/resource" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "github.com/nephio-project/nephio/controllers/pkg/cluster" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -34,6 +42,14 @@ func init() { reconcilerinterface.Register("bootstrap-spire", &reconciler{}) } +// const ( +// clusterNameKey = "nephio.org/cluster-name" +// nephioAppKey = "nephio.org/app" +// remoteNamespaceKey = "nephio.org/remote-namespace" +// syncApp = "tobeinstalledonremotecluster" +// bootstrapApp = "bootstrap" +// ) + //+kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters,verbs=get;list;watch //+kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters/status,verbs=get @@ -59,14 +75,15 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu // Fetch the Cluster instance // List all Cluster instances - clusterList := &capiv1beta1.ClusterList{} - err := r.List(ctx, clusterList) - if err != nil { - log.Error(err, "unable to list Clusters") - return reconcile.Result{}, err - } - cluster := &capiv1beta1.Cluster{} - err = r.Get(ctx, req.NamespacedName, cluster) + // clusterList := &capiv1beta1.ClusterList{} + // err := r.List(ctx, clusterList) + // if err != nil { + // log.Error(err, "unable to list Clusters") + // return reconcile.Result{}, err + // } + + cl := &capiv1beta1.Cluster{} + err := r.Get(ctx, req.NamespacedName, cl) if err != nil { if client.IgnoreNotFound(err) != nil { log.Error(err, "unable to fetch Cluster") @@ -75,7 +92,77 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } // Add your reconciliation logic here - log.Info("Reconciling Cluster", "cluster", cluster.Name) + log.Info("Reconciling Cluster", "cluster", cl.Name) + + // Fetch the ConfigMap from the current cluster + configMapName := types.NamespacedName{Name: "spire-bundle", Namespace: "spire"} + configMap := &corev1.ConfigMap{} + err = r.Get(ctx, configMapName, configMap) + if err != nil { + log.Error(err, "unable to fetch ConfigMap") + return reconcile.Result{}, err + } + + secrets := &corev1.SecretList{} + if err := r.List(ctx, secrets); err != nil { + msg := "cannot list secrets" + log.Error(err, msg) + return ctrl.Result{}, errors.Wrap(err, msg) + } + + found := false + for _, secret := range secrets.Items { + if strings.Contains(secret.GetName(), cl.Name) { + secret := secret // required to prevent gosec warning: G601 (CWE-118): Implicit memory aliasing in for loop + clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) + if ok { + found = true + clusterClient, ready, err := clusterClient.GetClusterClient(ctx) + if err != nil { + msg := "cannot get clusterClient" + log.Error(err, msg) + return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) + } + if !ready { + log.Info("cluster not ready") + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } + + remoteNamespace := configMap.Namespace + // if rns, ok := configMap.GetAnnotations()[remoteNamespaceKey]; ok { + // remoteNamespace = rns + // } + // check if the remote namespace exists, if not retry + ns := &corev1.Namespace{} + if err = clusterClient.Get(ctx, types.NamespacedName{Name: remoteNamespace}, ns); err != nil { + if resource.IgnoreNotFound(err) != nil { + msg := fmt.Sprintf("cannot get namespace: %s", remoteNamespace) + log.Error(err, msg) + return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) + } + msg := fmt.Sprintf("namespace: %s, does not exist, retry...", remoteNamespace) + log.Info(msg) + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } + + newcr := configMap.DeepCopy() + + newcr.ResourceVersion = "" + newcr.UID = "" + newcr.Namespace = remoteNamespace + log.Info("secret info", "secret", newcr.Annotations) + if err := clusterClient.Apply(ctx, newcr); err != nil { + msg := fmt.Sprintf("cannot apply secret to cluster %s", cl.Name) + log.Error(err, msg) + return ctrl.Result{}, errors.Wrap(err, msg) + } + } + } + if found { + // speeds up the loop + break + } + } // Example: Update the status if necessary From feb9279ac242ac4496c0f5fd3ac0adfc2946c6c2 Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Fri, 28 Jun 2024 07:00:03 +0530 Subject: [PATCH 06/14] Test Signed-off-by: PrimalPimmy --- controllers/pkg/go.mod | 43 +++--- controllers/pkg/go.sum | 122 ++++++++++-------- .../reconcilers/spire-bootstrap/reconciler.go | 6 + 3 files changed, 92 insertions(+), 79 deletions(-) diff --git a/controllers/pkg/go.mod b/controllers/pkg/go.mod index f98872d1..c059f632 100644 --- a/controllers/pkg/go.mod +++ b/controllers/pkg/go.mod @@ -18,8 +18,7 @@ require ( github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230608012444-ee7c8cf378e9 github.com/GoogleContainerTools/kpt/porch/controllers v0.0.0-20230608012444-ee7c8cf378e9 github.com/go-logr/logr v1.2.4 - github.com/google/go-cmp v0.5.9 - github.com/henderiw-nephio/network v0.0.0-20230626193806-04743403261e + github.com/google/go-cmp v0.6.0 github.com/nephio-project/api v1.0.1-0.20231127124455-cf14bd57b08d github.com/nephio-project/nephio/krm-functions/configinject-fn v0.0.0-00010101000000-000000000000 github.com/nephio-project/nephio/krm-functions/ipam-fn v0.0.0-00010101000000-000000000000 @@ -27,10 +26,9 @@ require ( github.com/nephio-project/nephio/krm-functions/vlan-fn v0.0.0-00010101000000-000000000000 github.com/nephio-project/nephio/testing/mockeryutils v0.0.0-20240112001535-96b08ff4acb3 github.com/nokia/k8s-ipam v0.0.4-0.20230628092530-8a292aec80a4 - github.com/openconfig/ygot v0.28.3 github.com/pkg/errors v0.9.1 - github.com/srl-labs/ygotsrl/v22 v22.11.1 - github.com/stretchr/testify v1.8.4 + // github.com/srl-labs/ygotsrl/v22 v22.11.1 + github.com/stretchr/testify v1.9.0 k8s.io/api v0.27.3 k8s.io/apimachinery v0.27.3 k8s.io/client-go v0.27.2 @@ -41,8 +39,11 @@ require ( sigs.k8s.io/yaml v1.3.0 ) +require github.com/spiffe/go-spiffe/v2 v2.3.0 + require ( github.com/GoogleContainerTools/kpt-functions-sdk/go/api v0.0.0-20230427202446-3255accc518d // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -53,52 +54,50 @@ require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-fed/httpsig v1.1.0 // indirect + github.com/go-jose/go-jose/v4 v4.0.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic v0.6.9 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/hansthienpondt/nipam v0.0.5 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kentik/patricia v1.2.0 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/openconfig/gnmi v0.9.1 // indirect - github.com/openconfig/goyang v1.4.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.15.1 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/xlab/treeprint v1.2.0 // indirect + github.com/zeebo/errs v1.3.0 // indirect go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 // indirect - golang.org/x/crypto v0.9.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect - google.golang.org/grpc v1.55.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/grpc v1.64.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/controllers/pkg/go.sum b/controllers/pkg/go.sum index 9f220987..ee03916d 100644 --- a/controllers/pkg/go.sum +++ b/controllers/pkg/go.sum @@ -13,6 +13,8 @@ github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230608012444-ee7c8cf378e9 github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230608012444-ee7c8cf378e9/go.mod h1:xQ4kNXVytubqrhwIqABBO/Ya4/v7m6VehpKEv43gCtE= github.com/GoogleContainerTools/kpt/porch/controllers v0.0.0-20230608012444-ee7c8cf378e9 h1:7YG8JQaIfn/9SVtBqY9MF4cVO6K/u1wMQnoHr1VGFXQ= github.com/GoogleContainerTools/kpt/porch/controllers v0.0.0-20230608012444-ee7c8cf378e9/go.mod h1:u73DWUyHPj896LCaDXwxjbA1g8atK5V5k5IT3Fj+5eQ= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -20,7 +22,6 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -45,6 +46,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= @@ -55,10 +57,13 @@ github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxI github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= +github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= +github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= @@ -66,16 +71,14 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -88,8 +91,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -98,24 +101,22 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/protobuf v3.11.4+incompatible/go.mod h1:lUQ9D1ePzbH2PrIS7ob/bjm9HXyH5WHB0Akwh7URreM= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hansthienpondt/nipam v0.0.5 h1:83Mdwdgx3l9tvio8u8ufan97MWx49n38IJwgSBgATEc= github.com/hansthienpondt/nipam v0.0.5/go.mod h1:dJI5FdzV6iaQyaOH4htGqJNs6wGieJeX3lhPj1Ah19U= github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/henderiw-nephio/network v0.0.0-20230626193806-04743403261e h1:/1ot/S2PsOCPXCgKMmsv0n0mniZ+VkdSgZK7nlPmZRg= -github.com/henderiw-nephio/network v0.0.0-20230626193806-04743403261e/go.mod h1:0UZ99qGMJxitNGUyNbz4Lo/BH3gYfRh8j4JZGa8ywwo= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -124,6 +125,7 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0 h1:VzM3TYHDgqPkettiP6I6q2jOeQFL4nrJM+UcAc4f6Fs= +github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0/go.mod h1:nqCI7aelBJU61wiBeeZWJ6oi4bJy5nrjkM6lWIMA4j0= github.com/kentik/patricia v1.2.0 h1:WZcp8V8GQhsya0bMZuXktEH/Wz+aBlhiMle4tExkj6M= github.com/kentik/patricia v1.2.0/go.mod h1:6jY40ESetsbfi04/S12iJlsiS6DYL2B2W+WAcqoDHtw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -131,12 +133,11 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= @@ -158,17 +159,9 @@ github.com/nokia/k8s-ipam v0.0.4-0.20230628092530-8a292aec80a4 h1:4v0n24tsumwuz1 github.com/nokia/k8s-ipam v0.0.4-0.20230628092530-8a292aec80a4/go.mod h1:ZVMmhD6jllAAO3YGIZFXUQbKRtEiIYgZ772bn/1GVz4= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= -github.com/openconfig/gnmi v0.0.0-20200414194230-1597cc0f2600/go.mod h1:M/EcuapNQgvzxo1DDXHK4tx3QpYM/uG4l591v33jG2A= -github.com/openconfig/gnmi v0.9.1 h1:hVOdLTaRjdy68oCGJbkf2vrmnUoQ5xbINqBOAMix4xM= -github.com/openconfig/gnmi v0.9.1/go.mod h1:Y9os75GmSkhHw2wX8sMsxfI7qRGAEcDh8NTa5a8vj6E= -github.com/openconfig/goyang v0.0.0-20200115183954-d0a48929f0ea/go.mod h1:dhXaV0JgHJzdrHi2l+w0fZrwArtXL7jEFoiqLEdmkvU= -github.com/openconfig/goyang v1.4.0 h1:/7T1Wk0r/8Bxcdh1LhWsnAKl+QuUV6Pfl4AyH63r9bA= -github.com/openconfig/goyang v1.4.0/go.mod h1:vX61x01Q46AzbZUzG617vWqh/cB+aisc+RrNkXRd3W8= -github.com/openconfig/ygot v0.6.0/go.mod h1:o30svNf7O0xK+R35tlx95odkDmZWS9JyWWQSmIhqwAs= -github.com/openconfig/ygot v0.28.3 h1:r1GSxzamx+HaO0/MdMTmSlOtX7us6arG+fDMWvRVGI0= -github.com/openconfig/ygot v0.28.3/go.mod h1:MB1WlgmH/547+unI5oVy7dQ46Tx+pCA05bJB2Gr9iXY= -github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -185,25 +178,28 @@ github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+Pymzi github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/srl-labs/ygotsrl/v22 v22.11.1 h1:Dxb7q7IB8xZc0XOZC53ZPBATxA8dJ+oJMC+2FYToId8= -github.com/srl-labs/ygotsrl/v22 v22.11.1/go.mod h1:VuNY6D0aYZvR9UeGSWOzgATBsis3ynw84TwiYuhS+pc= +github.com/spiffe/go-spiffe/v2 v2.3.0 h1:g2jYNb/PDMB8I7mBGL2Zuq/Ur6hUhoroxGQFyD6tTj8= +github.com/spiffe/go-spiffe/v2 v2.3.0/go.mod h1:Oxsaio7DBgSNqhAO9i/9tLClaVlfRok7zvJnTV8ZyIY= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= @@ -211,56 +207,63 @@ github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= +github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 h1:nJAwRlGWZZDOD+6wni9KVUNHMpHko/OnRwsrCYeAzPo= go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35/go.mod h1:TQvodOM+hJTioNQJilmLXu08JNb8i+ccq418+KWu1/Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -271,19 +274,23 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -294,7 +301,9 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -303,25 +312,24 @@ gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -334,8 +342,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 5473fc09..6167ff3a 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -24,6 +24,7 @@ import ( reconcilerinterface "github.com/nephio-project/nephio/controllers/pkg/reconcilers/reconciler-interface" "github.com/nephio-project/nephio/controllers/pkg/resource" + "github.com/spiffe/go-spiffe/v2/workloadapi" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" @@ -168,3 +169,8 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return reconcile.Result{}, nil } + +func fetchJWTSVID() (string, error) { + _, err := workloadapi.New(context.Background(), workloadapi.WithAddr("unix:///run/spire/sockets/agent.sock")) + return "", err +} From 79c9f30dbd593a467849469966a9bcf67e58eb8b Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Fri, 28 Jun 2024 07:45:35 +0530 Subject: [PATCH 07/14] Spire auth inside reconciler Signed-off-by: PrimalPimmy --- .../reconcilers/spire-bootstrap/reconciler.go | 213 ++++++++++++------ 1 file changed, 145 insertions(+), 68 deletions(-) diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 6167ff3a..011747fd 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -19,17 +19,19 @@ package bootstrapsecret import ( "context" "fmt" - "strings" + "io" + "net/http" + "os" "time" reconcilerinterface "github.com/nephio-project/nephio/controllers/pkg/reconcilers/reconciler-interface" - "github.com/nephio-project/nephio/controllers/pkg/resource" + "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig" + "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" "github.com/spiffe/go-spiffe/v2/workloadapi" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - "github.com/nephio-project/nephio/controllers/pkg/cluster" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" @@ -40,7 +42,7 @@ import ( ) func init() { - reconcilerinterface.Register("bootstrap-spire", &reconciler{}) + reconcilerinterface.Register("WorkloadIdentity", &reconciler{}) } // const ( @@ -104,73 +106,148 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return reconcile.Result{}, err } - secrets := &corev1.SecretList{} - if err := r.List(ctx, secrets); err != nil { - msg := "cannot list secrets" - log.Error(err, msg) - return ctrl.Result{}, errors.Wrap(err, msg) - } + // secrets := &corev1.SecretList{} + // if err := r.List(ctx, secrets); err != nil { + // msg := "cannot list secrets" + // log.Error(err, msg) + // return ctrl.Result{}, errors.Wrap(err, msg) + // } - found := false - for _, secret := range secrets.Items { - if strings.Contains(secret.GetName(), cl.Name) { - secret := secret // required to prevent gosec warning: G601 (CWE-118): Implicit memory aliasing in for loop - clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) - if ok { - found = true - clusterClient, ready, err := clusterClient.GetClusterClient(ctx) - if err != nil { - msg := "cannot get clusterClient" - log.Error(err, msg) - return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) - } - if !ready { - log.Info("cluster not ready") - return ctrl.Result{RequeueAfter: 10 * time.Second}, nil - } - - remoteNamespace := configMap.Namespace - // if rns, ok := configMap.GetAnnotations()[remoteNamespaceKey]; ok { - // remoteNamespace = rns - // } - // check if the remote namespace exists, if not retry - ns := &corev1.Namespace{} - if err = clusterClient.Get(ctx, types.NamespacedName{Name: remoteNamespace}, ns); err != nil { - if resource.IgnoreNotFound(err) != nil { - msg := fmt.Sprintf("cannot get namespace: %s", remoteNamespace) - log.Error(err, msg) - return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) - } - msg := fmt.Sprintf("namespace: %s, does not exist, retry...", remoteNamespace) - log.Info(msg) - return ctrl.Result{RequeueAfter: 10 * time.Second}, nil - } - - newcr := configMap.DeepCopy() - - newcr.ResourceVersion = "" - newcr.UID = "" - newcr.Namespace = remoteNamespace - log.Info("secret info", "secret", newcr.Annotations) - if err := clusterClient.Apply(ctx, newcr); err != nil { - msg := fmt.Sprintf("cannot apply secret to cluster %s", cl.Name) - log.Error(err, msg) - return ctrl.Result{}, errors.Wrap(err, msg) - } - } - } - if found { - // speeds up the loop - break - } - } + // found := false + // for _, secret := range secrets.Items { + // if strings.Contains(secret.GetName(), cl.Name) { + // secret := secret // required to prevent gosec warning: G601 (CWE-118): Implicit memory aliasing in for loop + // clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) + // if ok { + // found = true + // clusterClient, ready, err := clusterClient.GetClusterClient(ctx) + // if err != nil { + // msg := "cannot get clusterClient" + // log.Error(err, msg) + // return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) + // } + // if !ready { + // log.Info("cluster not ready") + // return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + // } + + // remoteNamespace := configMap.Namespace + // // if rns, ok := configMap.GetAnnotations()[remoteNamespaceKey]; ok { + // // remoteNamespace = rns + // // } + // // check if the remote namespace exists, if not retry + // ns := &corev1.Namespace{} + // if err = clusterClient.Get(ctx, types.NamespacedName{Name: remoteNamespace}, ns); err != nil { + // if resource.IgnoreNotFound(err) != nil { + // msg := fmt.Sprintf("cannot get namespace: %s", remoteNamespace) + // log.Error(err, msg) + // return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) + // } + // msg := fmt.Sprintf("namespace: %s, does not exist, retry...", remoteNamespace) + // log.Info(msg) + // return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + // } + + // newcr := configMap.DeepCopy() + + // newcr.ResourceVersion = "" + // newcr.UID = "" + // newcr.Namespace = remoteNamespace + // log.Info("secret info", "secret", newcr.Annotations) + // if err := clusterClient.Apply(ctx, newcr); err != nil { + // msg := fmt.Sprintf("cannot apply secret to cluster %s", cl.Name) + // log.Error(err, msg) + // return ctrl.Result{}, errors.Wrap(err, msg) + // } + // } + // } + // if found { + // // speeds up the loop + // break + // } + // } + + // // Example: Update the status if necessary - // Example: Update the status if necessary + err = run(ctx) + if err != nil { + log.Error(err, "Spire auth didnt work") + } return reconcile.Result{}, nil } -func fetchJWTSVID() (string, error) { - _, err := workloadapi.New(context.Background(), workloadapi.WithAddr("unix:///run/spire/sockets/agent.sock")) - return "", err +const ( + serverURL = "spire-server:8081" + socketPath = "unix:///spiffe-workload-api/agent.sock" +) + +func run(ctx context.Context) error { + // Time out the example after 30 seconds. This prevents the example from hanging if the workloads are not properly registered with SPIRE. + ctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + + // Create client options to setup expected socket path, + // as default sources will use value from environment variable `SPIFFE_ENDPOINT_SOCKET` + clientOptions := workloadapi.WithClientOptions(workloadapi.WithAddr(socketPath)) + + // Create X509 source to fetch bundle certificate used to verify presented certificate from server + x509Source, err := workloadapi.NewX509Source(ctx, clientOptions) + if err != nil { + return fmt.Errorf("unable to create X509Source: %w", err) + } + defer x509Source.Close() + + // Create a `tls.Config` with configuration to allow TLS communication, and verify that presented certificate from server has SPIFFE ID `spiffe://example.org/server` + serverID := spiffeid.RequireFromString("spiffe://example.org/server") + tlsConfig := tlsconfig.TLSClientConfig(x509Source, tlsconfig.AuthorizeID(serverID)) + + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: tlsConfig, + }, + } + + req, err := http.NewRequest("GET", serverURL, nil) + if err != nil { + return fmt.Errorf("unable to create request: %w", err) + } + + // As default example is using server's ID, + // It doesn't have to be an SPIFFE ID as long it follows JWT SVIDs the guidelines (https://github.com/spiffe/spiffe/blob/main/standards/JWT-SVID.md#32-audience) + audience := serverID.String() + args := os.Args + if len(args) >= 2 { + audience = args[1] + } + + // Create a JWTSource to fetch SVIDs + jwtSource, err := workloadapi.NewJWTSource(ctx, clientOptions) + if err != nil { + return fmt.Errorf("unable to create JWTSource: %w", err) + } + defer jwtSource.Close() + + // Fetch JWT SVID and add it to `Authorization` header, + // It is possible to fetch JWT SVID using `workloadapi.FetchJWTSVID` + svid, err := jwtSource.FetchJWTSVID(ctx, jwtsvid.Params{ + Audience: audience, + }) + if err != nil { + return fmt.Errorf("unable to fetch SVID: %w", err) + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", svid.Marshal())) + + res, err := client.Do(req) + if err != nil { + return fmt.Errorf("unable to issue request to %q: %w", serverURL, err) + } + defer res.Body.Close() + + body, err := io.ReadAll(res.Body) + if err != nil { + return fmt.Errorf("error reading response body: %w", err) + } + log.Log.Info("%s", body) + return nil } From 34a4957f01bbe71066fd0fab5eaf1888eb9e3b4d Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Thu, 4 Jul 2024 08:17:43 +0530 Subject: [PATCH 08/14] Vault authentication and fetching kubeconfig Signed-off-by: PrimalPimmy --- controllers/pkg/go.mod | 27 +- controllers/pkg/go.sum | 52 ++++ .../reconcilers/spire-bootstrap/reconciler.go | 231 ++++++++++++------ 3 files changed, 233 insertions(+), 77 deletions(-) diff --git a/controllers/pkg/go.mod b/controllers/pkg/go.mod index c059f632..d3842945 100644 --- a/controllers/pkg/go.mod +++ b/controllers/pkg/go.mod @@ -41,6 +41,22 @@ require ( require github.com/spiffe/go-spiffe/v2 v2.3.0 +require ( + github.com/cenkalti/backoff/v3 v3.0.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.6 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect +) + require ( github.com/GoogleContainerTools/kpt-functions-sdk/go/api v0.0.0-20230427202446-3255accc518d // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -66,6 +82,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/hansthienpondt/nipam v0.0.5 // indirect github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/vault/api v1.14.0 github.com/imdario/mergo v0.3.16 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -86,12 +103,12 @@ require ( github.com/xlab/treeprint v1.2.0 // indirect github.com/zeebo/errs v1.3.0 // indirect go4.org/netipx v0.0.0-20230303233057-f1b76eb4bb35 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.23.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/net v0.25.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/term v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect golang.org/x/time v0.3.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/controllers/pkg/go.sum b/controllers/pkg/go.sum index ee03916d..38ab02ad 100644 --- a/controllers/pkg/go.sum +++ b/controllers/pkg/go.sum @@ -17,11 +17,15 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= @@ -49,6 +53,7 @@ github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCv github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -114,9 +119,32 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hansthienpondt/nipam v0.0.5 h1:83Mdwdgx3l9tvio8u8ufan97MWx49n38IJwgSBgATEc= github.com/hansthienpondt/nipam v0.0.5/go.mod h1:dJI5FdzV6iaQyaOH4htGqJNs6wGieJeX3lhPj1Ah19U= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.6 h1:TwRYfx2z2C4cLbXmT8I5PgP/xmuqASDyiVuGYfs9GZM= +github.com/hashicorp/go-retryablehttp v0.7.6/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/vault/api v1.14.0 h1:Ah3CFLixD5jmjusOgm8grfN9M0d+Y8fVR2SW0K6pJLU= +github.com/hashicorp/vault/api v1.14.0/go.mod h1:pV9YLxBGSz+cItFDd8Ii4G17waWOQ32zVjMWHe/cOqk= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -140,8 +168,17 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -167,6 +204,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -179,6 +217,9 @@ github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPH github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -229,6 +270,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -253,6 +296,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= @@ -264,6 +309,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -279,10 +325,14 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -291,6 +341,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 011747fd..1cab7162 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -17,21 +17,23 @@ limitations under the License. package bootstrapsecret import ( + "bytes" "context" + "encoding/json" "fmt" - "io" - "net/http" - "os" - "time" + "io/ioutil" + "strings" reconcilerinterface "github.com/nephio-project/nephio/controllers/pkg/reconcilers/reconciler-interface" - "github.com/spiffe/go-spiffe/v2/spiffeid" - "github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig" - "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" "github.com/spiffe/go-spiffe/v2/workloadapi" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + vault "github.com/hashicorp/vault/api" + "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" + + "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" @@ -42,16 +44,19 @@ import ( ) func init() { - reconcilerinterface.Register("WorkloadIdentity", &reconciler{}) + reconcilerinterface.Register("workloadidentity", &reconciler{}) } -// const ( -// clusterNameKey = "nephio.org/cluster-name" -// nephioAppKey = "nephio.org/app" -// remoteNamespaceKey = "nephio.org/remote-namespace" -// syncApp = "tobeinstalledonremotecluster" -// bootstrapApp = "bootstrap" -// ) +type LoginPayload struct { + Role string `json:"role"` + JWT string `json:"jwt"` +} + +type AuthResponse struct { + Auth struct { + ClientToken string `json:"client_token"` + } `json:"auth"` +} //+kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters,verbs=get;list;watch //+kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters/status,verbs=get @@ -106,12 +111,12 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return reconcile.Result{}, err } - // secrets := &corev1.SecretList{} - // if err := r.List(ctx, secrets); err != nil { - // msg := "cannot list secrets" - // log.Error(err, msg) - // return ctrl.Result{}, errors.Wrap(err, msg) - // } + secrets := &corev1.SecretList{} + if err := r.List(ctx, secrets); err != nil { + msg := "cannot list secrets" + log.Error(err, msg) + return ctrl.Result{}, errors.Wrap(err, msg) + } // found := false // for _, secret := range secrets.Items { @@ -167,87 +172,169 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu // } // } - // // Example: Update the status if necessary + vaultAddr := "http://10.146.0.21:8200" - err = run(ctx) + jwtSVID, err := getJWT(ctx) if err != nil { - log.Error(err, "Spire auth didnt work") + log.Error(err, "Unable to get jwtSVID") } - return reconcile.Result{}, nil -} - -const ( - serverURL = "spire-server:8081" - socketPath = "unix:///spiffe-workload-api/agent.sock" -) - -func run(ctx context.Context) error { - // Time out the example after 30 seconds. This prevents the example from hanging if the workloads are not properly registered with SPIRE. - ctx, cancel := context.WithTimeout(ctx, 30*time.Second) - defer cancel() + clientToken, err := authenticateToVault(vaultAddr, jwtSVID.Marshal(), "dev") + if err != nil { + log.Error(err, "Error authenticating to Vault:") + } - // Create client options to setup expected socket path, - // as default sources will use value from environment variable `SPIFFE_ENDPOINT_SOCKET` - clientOptions := workloadapi.WithClientOptions(workloadapi.WithAddr(socketPath)) + fmt.Printf("Successfully authenticated to Vault. Client token: %s\n", clientToken) - // Create X509 source to fetch bundle certificate used to verify presented certificate from server - x509Source, err := workloadapi.NewX509Source(ctx, clientOptions) + config := vault.DefaultConfig() + config.Address = vaultAddr + client, err := vault.NewClient(config) if err != nil { - return fmt.Errorf("unable to create X509Source: %w", err) + log.Error(err, "Unable to create Vault client:") } - defer x509Source.Close() - // Create a `tls.Config` with configuration to allow TLS communication, and verify that presented certificate from server has SPIFFE ID `spiffe://example.org/server` - serverID := spiffeid.RequireFromString("spiffe://example.org/server") - tlsConfig := tlsconfig.TLSClientConfig(x509Source, tlsconfig.AuthorizeID(serverID)) + client.SetToken(clientToken) - client := &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: tlsConfig, - }, + for _, secret := range secrets.Items { + if strings.Contains(secret.GetName(), cl.Name) { + secret := secret + storeKubeconfig(secret, client, "secret/my-super-secret", cl.Name) + // clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) + } } - req, err := http.NewRequest("GET", serverURL, nil) + // secret, err := getSecret(client, "secret/my-super-secret") + + kubeconfig, err := fetchKubeconfig(client, "secret/my-super-secret", cl.Name) if err != nil { - return fmt.Errorf("unable to create request: %w", err) + log.Error(err, "Error retrieving secret:") } - // As default example is using server's ID, - // It doesn't have to be an SPIFFE ID as long it follows JWT SVIDs the guidelines (https://github.com/spiffe/spiffe/blob/main/standards/JWT-SVID.md#32-audience) - audience := serverID.String() - args := os.Args - if len(args) >= 2 { - audience = args[1] - } + fmt.Printf("Secret retrieved: %v\n", kubeconfig) - // Create a JWTSource to fetch SVIDs + return reconcile.Result{}, nil +} + +func getJWT(ctx context.Context) (*jwtsvid.SVID, error) { + socketPath := "unix:///spiffe-workload-api/agent.sock" + log := log.FromContext(ctx) + clientOptions := workloadapi.WithClientOptions(workloadapi.WithAddr(socketPath)) jwtSource, err := workloadapi.NewJWTSource(ctx, clientOptions) if err != nil { - return fmt.Errorf("unable to create JWTSource: %w", err) + log.Info("Unable to create JWTSource: %v", err) } defer jwtSource.Close() - // Fetch JWT SVID and add it to `Authorization` header, - // It is possible to fetch JWT SVID using `workloadapi.FetchJWTSVID` - svid, err := jwtSource.FetchJWTSVID(ctx, jwtsvid.Params{ + audience := "TESTING" + spiffeID := spiffeid.RequireFromString("spiffe://example.org/nephio") + + jwtSVID, err := jwtSource.FetchJWTSVID(ctx, jwtsvid.Params{ Audience: audience, + Subject: spiffeID, }) if err != nil { - return fmt.Errorf("unable to fetch SVID: %w", err) + log.Info("Unable to fetch JWT-SVID: %v", err) + } + + fmt.Printf("Fetched JWT-SVID: %v\n", jwtSVID.Marshal()) + if err != nil { + log.Error(err, "Spire auth didnt work") + } + + return jwtSVID, err +} + +func authenticateToVault(vaultAddr, jwt, role string) (string, error) { + // Create a Vault client + config := vault.DefaultConfig() + config.Address = vaultAddr + client, err := vault.NewClient(config) + if err != nil { + return "", fmt.Errorf("unable to create Vault client: %w", err) + } + + payload := LoginPayload{ + Role: role, + JWT: jwt, + } + payloadBytes, err := json.Marshal(payload) + if err != nil { + return "", fmt.Errorf("unable to marshal payload: %w", err) + } + + // Perform the login request + req := client.NewRequest("POST", "/v1/auth/jwt/login") + req.Body = bytes.NewBuffer(payloadBytes) + + resp, err := client.RawRequest(req) + if err != nil { + return "", fmt.Errorf("unable to perform login request: %w", err) } - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", svid.Marshal())) + defer resp.Body.Close() - res, err := client.Do(req) + body, err := ioutil.ReadAll(resp.Body) if err != nil { - return fmt.Errorf("unable to issue request to %q: %w", serverURL, err) + return "", fmt.Errorf("unable to read response body: %w", err) + } + + var authResp AuthResponse + if err := json.Unmarshal(body, &authResp); err != nil { + return "", fmt.Errorf("unable to decode response: %w", err) + } + + return authResp.Auth.ClientToken, nil +} + +func getSecret(client *vault.Client, secretPath string) (map[string]interface{}, error) { + secret, err := client.Logical().Read(secretPath) + if err != nil { + return nil, fmt.Errorf("unable to read secret: %w", err) + } + + if secret == nil { + return nil, fmt.Errorf("secret not found at path: %s", secretPath) } - defer res.Body.Close() - body, err := io.ReadAll(res.Body) + return secret.Data, nil +} + +func storeKubeconfig(kubeconfigData corev1.Secret, client *vault.Client, secretPath, clusterName string) error { + // Read the Kubeconfig file + + fmt.Println("Base64 encoded secret data:", kubeconfigData.Data) + + // Prepare the data to store + data := map[string]interface{}{ + "data": map[string]interface{}{ + clusterName: kubeconfigData.Data, + }, + } + + // Store the data in Vault + _, err := client.Logical().Write(secretPath, data) if err != nil { - return fmt.Errorf("error reading response body: %w", err) + return fmt.Errorf("unable to write secret to Vault: %w", err) } - log.Log.Info("%s", body) + return nil } + +func fetchKubeconfig(client *vault.Client, secretPath, clusterName string) (string, error) { + // Read the secret + secret, err := client.Logical().Read(secretPath) + if err != nil { + return "", fmt.Errorf("unable to read secret: %w", err) + } + + if secret == nil { + return "", fmt.Errorf("secret not found at path: %s", secretPath) + } + + // Extract the Kubeconfig data + kubeconfig, ok := secret.Data["data"].(map[string]interface{})[clusterName].(string) + if !ok { + return "", fmt.Errorf("kubeconfig for cluster %s not found", clusterName) + } + + return kubeconfig, nil +} From 687409dffc1843a4a97fc76d392bbba6e17d48bf Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Tue, 9 Jul 2024 14:57:55 +0530 Subject: [PATCH 09/14] Some testing Signed-off-by: PrimalPimmy --- controllers/pkg/reconcilers/spire-bootstrap/reconciler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 1cab7162..d1a93093 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -331,7 +331,7 @@ func fetchKubeconfig(client *vault.Client, secretPath, clusterName string) (stri } // Extract the Kubeconfig data - kubeconfig, ok := secret.Data["data"].(map[string]interface{})[clusterName].(string) + kubeconfig, ok := secret.Data["test"].(string) if !ok { return "", fmt.Errorf("kubeconfig for cluster %s not found", clusterName) } From dd2e75ad551115a6d76baaebbefd682a3e1a96a2 Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Tue, 9 Jul 2024 18:13:58 +0530 Subject: [PATCH 10/14] Mid testing Signed-off-by: PrimalPimmy Mid testing Signed-off-by: PrimalPimmy Mid testing Signed-off-by: PrimalPimmy Mid testing-2 Signed-off-by: PrimalPimmy Mid testing-2 Signed-off-by: PrimalPimmy Mid testing-2 Signed-off-by: PrimalPimmy Mid testing-3 Signed-off-by: PrimalPimmy Mid testing-3 Signed-off-by: PrimalPimmy Mid testing-3 Signed-off-by: PrimalPimmy --- controllers/pkg/go.sum | 20 +- .../reconcilers/spire-bootstrap/reconciler.go | 258 +++++++++++++----- 2 files changed, 198 insertions(+), 80 deletions(-) diff --git a/controllers/pkg/go.sum b/controllers/pkg/go.sum index 38ab02ad..7fa1772f 100644 --- a/controllers/pkg/go.sum +++ b/controllers/pkg/go.sum @@ -54,6 +54,8 @@ github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -77,6 +79,8 @@ github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -124,6 +128,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -169,7 +175,11 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -268,8 +278,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -294,8 +302,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -323,14 +329,10 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -339,8 +341,6 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index d1a93093..0dad404f 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -19,15 +19,21 @@ package bootstrapsecret import ( "bytes" "context" + "encoding/base64" "encoding/json" "fmt" "io/ioutil" "strings" + "time" + "github.com/nephio-project/nephio/controllers/pkg/cluster" reconcilerinterface "github.com/nephio-project/nephio/controllers/pkg/reconcilers/reconciler-interface" + "github.com/nephio-project/nephio/controllers/pkg/resource" "github.com/spiffe/go-spiffe/v2/workloadapi" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" vault "github.com/hashicorp/vault/api" "github.com/spiffe/go-spiffe/v2/spiffeid" @@ -35,6 +41,9 @@ import ( "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -118,60 +127,6 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return ctrl.Result{}, errors.Wrap(err, msg) } - // found := false - // for _, secret := range secrets.Items { - // if strings.Contains(secret.GetName(), cl.Name) { - // secret := secret // required to prevent gosec warning: G601 (CWE-118): Implicit memory aliasing in for loop - // clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) - // if ok { - // found = true - // clusterClient, ready, err := clusterClient.GetClusterClient(ctx) - // if err != nil { - // msg := "cannot get clusterClient" - // log.Error(err, msg) - // return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) - // } - // if !ready { - // log.Info("cluster not ready") - // return ctrl.Result{RequeueAfter: 10 * time.Second}, nil - // } - - // remoteNamespace := configMap.Namespace - // // if rns, ok := configMap.GetAnnotations()[remoteNamespaceKey]; ok { - // // remoteNamespace = rns - // // } - // // check if the remote namespace exists, if not retry - // ns := &corev1.Namespace{} - // if err = clusterClient.Get(ctx, types.NamespacedName{Name: remoteNamespace}, ns); err != nil { - // if resource.IgnoreNotFound(err) != nil { - // msg := fmt.Sprintf("cannot get namespace: %s", remoteNamespace) - // log.Error(err, msg) - // return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) - // } - // msg := fmt.Sprintf("namespace: %s, does not exist, retry...", remoteNamespace) - // log.Info(msg) - // return ctrl.Result{RequeueAfter: 10 * time.Second}, nil - // } - - // newcr := configMap.DeepCopy() - - // newcr.ResourceVersion = "" - // newcr.UID = "" - // newcr.Namespace = remoteNamespace - // log.Info("secret info", "secret", newcr.Annotations) - // if err := clusterClient.Apply(ctx, newcr); err != nil { - // msg := fmt.Sprintf("cannot apply secret to cluster %s", cl.Name) - // log.Error(err, msg) - // return ctrl.Result{}, errors.Wrap(err, msg) - // } - // } - // } - // if found { - // // speeds up the loop - // break - // } - // } - vaultAddr := "http://10.146.0.21:8200" jwtSVID, err := getJWT(ctx) @@ -210,11 +165,93 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu log.Error(err, "Error retrieving secret:") } - fmt.Printf("Secret retrieved: %v\n", kubeconfig) + decodedKubeConfig, err := base64.StdEncoding.DecodeString(kubeconfig) + if err != nil { + fmt.Println("Error decoding base64:", err) + } + + fmt.Printf("Secret retrieved: %v\n", decodedKubeConfig) + + Client, err := createK8sClientFromKubeconfig(decodedKubeConfig) + + createK8sResources(Client) + if err != nil { + fmt.Println("Error creating K8s", err) + } + + found := false + for _, secret := range secrets.Items { + if strings.Contains(secret.GetName(), cl.Name) { + secret := secret // required to prevent gosec warning: G601 (CWE-118): Implicit memory aliasing in for loop + clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) + if ok { + found = true + clusterClient, ready, err := clusterClient.GetClusterClient(ctx) + if err != nil { + msg := "cannot get clusterClient" + log.Error(err, msg) + return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) + } + if !ready { + log.Info("cluster not ready") + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } + + remoteNamespace := configMap.Namespace + // if rns, ok := configMap.GetAnnotations()[remoteNamespaceKey]; ok { + // remoteNamespace = rns + // } + // check if the remote namespace exists, if not retry + ns := &corev1.Namespace{} + if err = clusterClient.Get(ctx, types.NamespacedName{Name: remoteNamespace}, ns); err != nil { + if resource.IgnoreNotFound(err) != nil { + msg := fmt.Sprintf("cannot get namespace: %s", remoteNamespace) + log.Error(err, msg) + return ctrl.Result{RequeueAfter: 30 * time.Second}, errors.Wrap(err, msg) + } + msg := fmt.Sprintf("namespace: %s, does not exist, retry...", remoteNamespace) + log.Info(msg) + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } + + newcr := configMap.DeepCopy() + + newcr.ResourceVersion = "" + newcr.UID = "" + newcr.Namespace = remoteNamespace + log.Info("secret info", "secret", newcr.Annotations) + if err := clusterClient.Apply(ctx, newcr); err != nil { + msg := fmt.Sprintf("cannot apply secret to cluster %s", cl.Name) + log.Error(err, msg) + return ctrl.Result{}, errors.Wrap(err, msg) + } + } + } + if found { + // speeds up the loop + break + } + } return reconcile.Result{}, nil } +func createK8sClientFromKubeconfig(kubeconfigData []byte) (*kubernetes.Clientset, error) { + // Load the kubeconfig from the decoded data + config, err := clientcmd.RESTConfigFromKubeConfig(kubeconfigData) + if err != nil { + return nil, fmt.Errorf("failed to load kubeconfig: %v", err) + } + + // Create the Kubernetes clientset + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, fmt.Errorf("failed to create Kubernetes clientset: %v", err) + } + + return clientset, nil +} + func getJWT(ctx context.Context) (*jwtsvid.SVID, error) { socketPath := "unix:///spiffe-workload-api/agent.sock" log := log.FromContext(ctx) @@ -285,24 +322,9 @@ func authenticateToVault(vaultAddr, jwt, role string) (string, error) { return authResp.Auth.ClientToken, nil } -func getSecret(client *vault.Client, secretPath string) (map[string]interface{}, error) { - secret, err := client.Logical().Read(secretPath) - if err != nil { - return nil, fmt.Errorf("unable to read secret: %w", err) - } - - if secret == nil { - return nil, fmt.Errorf("secret not found at path: %s", secretPath) - } - - return secret.Data, nil -} - func storeKubeconfig(kubeconfigData corev1.Secret, client *vault.Client, secretPath, clusterName string) error { // Read the Kubeconfig file - fmt.Println("Base64 encoded secret data:", kubeconfigData.Data) - // Prepare the data to store data := map[string]interface{}{ "data": map[string]interface{}{ @@ -338,3 +360,99 @@ func fetchKubeconfig(client *vault.Client, secretPath, clusterName string) (stri return kubeconfig, nil } + +func createK8sResources(clientset *kubernetes.Clientset) error { + // Create ServiceAccount + sa := &v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "spire-kubeconfig", + Namespace: "spire", + }, + } + _, err := clientset.CoreV1().ServiceAccounts("spire").Create(context.TODO(), sa, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("failed to create ServiceAccount: %v", err) + } + + // Create ClusterRole + cr := &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod-reader", + }, + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{""}, + Resources: []string{"pods", "nodes"}, + Verbs: []string{"get"}, + }, + }, + } + _, err = clientset.RbacV1().ClusterRoles().Create(context.TODO(), cr, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("failed to create ClusterRole: %v", err) + } + + // Create ClusterRoleBinding for system:auth-delegator + crbAuthDelegator := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "spire-agent-tokenreview-binding", + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + Name: "spire-kubeconfig", + Namespace: "spire", + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "system:auth-delegator", + }, + } + _, err = clientset.RbacV1().ClusterRoleBindings().Create(context.TODO(), crbAuthDelegator, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("failed to create ClusterRoleBinding (auth-delegator): %v", err) + } + + // Create ClusterRoleBinding for pod-reader + crbPodReader := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "spire-agent-pod-reader-binding", + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + Name: "spire-kubeconfig", + Namespace: "spire", + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "pod-reader", + }, + } + _, err = clientset.RbacV1().ClusterRoleBindings().Create(context.TODO(), crbPodReader, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("failed to create ClusterRoleBinding (pod-reader): %v", err) + } + + // Create Secret + secret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "agent-sa-secret", + Namespace: "spire", + Annotations: map[string]string{ + "kubernetes.io/service-account.name": "spire-kubeconfig", + }, + }, + Type: v1.SecretTypeServiceAccountToken, + } + _, err = clientset.CoreV1().Secrets("spire").Create(context.TODO(), secret, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("failed to create Secret: %v", err) + } + + return nil +} From e1fe02dccab9333e115ffa0a9385b741a79fc797 Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Fri, 12 Jul 2024 09:22:32 +0530 Subject: [PATCH 11/14] Refactoring Signed-off-by: PrimalPimmy Kubeconfig test Signed-off-by: PrimalPimmy Removed found Signed-off-by: PrimalPimmy log testing Signed-off-by: PrimalPimmy log testing Signed-off-by: PrimalPimmy log testing Signed-off-by: PrimalPimmy --- .../reconcilers/spire-bootstrap/reconciler.go | 162 +++--------------- controllers/pkg/resource/workloadapi.go | 42 +++++ controllers/pkg/vault-client/vault.go | 119 +++++++++++++ 3 files changed, 189 insertions(+), 134 deletions(-) create mode 100644 controllers/pkg/resource/workloadapi.go create mode 100644 controllers/pkg/vault-client/vault.go diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 0dad404f..9248e85b 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -14,33 +14,27 @@ See the License for the specific language governing permissions and limitations under the License. */ -package bootstrapsecret +package spirebootstrap import ( - "bytes" "context" "encoding/base64" - "encoding/json" "fmt" - "io/ioutil" "strings" "time" "github.com/nephio-project/nephio/controllers/pkg/cluster" reconcilerinterface "github.com/nephio-project/nephio/controllers/pkg/reconcilers/reconciler-interface" "github.com/nephio-project/nephio/controllers/pkg/resource" - "github.com/spiffe/go-spiffe/v2/workloadapi" + vaultClient "github.com/nephio-project/nephio/controllers/pkg/vault-client" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" vault "github.com/hashicorp/vault/api" - "github.com/spiffe/go-spiffe/v2/spiffeid" - "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" "github.com/pkg/errors" - corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -110,36 +104,47 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu // Add your reconciliation logic here log.Info("Reconciling Cluster", "cluster", cl.Name) + fmt.Println("TESTTT !!!!!!!!!") // Fetch the ConfigMap from the current cluster configMapName := types.NamespacedName{Name: "spire-bundle", Namespace: "spire"} - configMap := &corev1.ConfigMap{} + configMap := &v1.ConfigMap{} err = r.Get(ctx, configMapName, configMap) if err != nil { log.Error(err, "unable to fetch ConfigMap") return reconcile.Result{}, err } - secrets := &corev1.SecretList{} + fmt.Println("TESTTT @@@@@@") + + secrets := &v1.SecretList{} if err := r.List(ctx, secrets); err != nil { msg := "cannot list secrets" log.Error(err, msg) return ctrl.Result{}, errors.Wrap(err, msg) } + fmt.Println("TESTTT 3333333") + vaultAddr := "http://10.146.0.21:8200" - jwtSVID, err := getJWT(ctx) + jwtSVID, err := resource.GetJWT(ctx) if err != nil { log.Error(err, "Unable to get jwtSVID") } - clientToken, err := authenticateToVault(vaultAddr, jwtSVID.Marshal(), "dev") + fmt.Println("TESTTT 4444444") + + clientToken, err := vaultClient.AuthenticateToVault(vaultAddr, jwtSVID.Marshal(), "dev") if err != nil { log.Error(err, "Error authenticating to Vault:") } - fmt.Printf("Successfully authenticated to Vault. Client token: %s\n", clientToken) + fmt.Println("TESTTT 5555555") + + log.Info("Successfully authenticated to Vault.", "Client token:", clientToken) + + fmt.Println(clientToken) config := vault.DefaultConfig() config.Address = vaultAddr @@ -153,14 +158,14 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu for _, secret := range secrets.Items { if strings.Contains(secret.GetName(), cl.Name) { secret := secret - storeKubeconfig(secret, client, "secret/my-super-secret", cl.Name) + vaultClient.StoreKubeconfig(secret, client, "secret/my-super-secret", cl.Name) // clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) } } // secret, err := getSecret(client, "secret/my-super-secret") - kubeconfig, err := fetchKubeconfig(client, "secret/my-super-secret", cl.Name) + kubeconfig, err := vaultClient.FetchKubeconfig(client, "secret/my-super-secret", cl.Name) if err != nil { log.Error(err, "Error retrieving secret:") } @@ -170,22 +175,21 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu fmt.Println("Error decoding base64:", err) } - fmt.Printf("Secret retrieved: %v\n", decodedKubeConfig) + log.Info("Secret retrieved:", "Secret", decodedKubeConfig) Client, err := createK8sClientFromKubeconfig(decodedKubeConfig) - createK8sResources(Client) + createK8sSATokenResources(Client) + if err != nil { fmt.Println("Error creating K8s", err) } - found := false for _, secret := range secrets.Items { if strings.Contains(secret.GetName(), cl.Name) { secret := secret // required to prevent gosec warning: G601 (CWE-118): Implicit memory aliasing in for loop clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) if ok { - found = true clusterClient, ready, err := clusterClient.GetClusterClient(ctx) if err != nil { msg := "cannot get clusterClient" @@ -202,7 +206,7 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu // remoteNamespace = rns // } // check if the remote namespace exists, if not retry - ns := &corev1.Namespace{} + ns := &v1.Namespace{} if err = clusterClient.Get(ctx, types.NamespacedName{Name: remoteNamespace}, ns); err != nil { if resource.IgnoreNotFound(err) != nil { msg := fmt.Sprintf("cannot get namespace: %s", remoteNamespace) @@ -227,15 +231,13 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } } } - if found { - // speeds up the loop - break - } + } return reconcile.Result{}, nil } +// unused for now func createK8sClientFromKubeconfig(kubeconfigData []byte) (*kubernetes.Clientset, error) { // Load the kubeconfig from the decoded data config, err := clientcmd.RESTConfigFromKubeConfig(kubeconfigData) @@ -252,116 +254,8 @@ func createK8sClientFromKubeconfig(kubeconfigData []byte) (*kubernetes.Clientset return clientset, nil } -func getJWT(ctx context.Context) (*jwtsvid.SVID, error) { - socketPath := "unix:///spiffe-workload-api/agent.sock" - log := log.FromContext(ctx) - clientOptions := workloadapi.WithClientOptions(workloadapi.WithAddr(socketPath)) - jwtSource, err := workloadapi.NewJWTSource(ctx, clientOptions) - if err != nil { - log.Info("Unable to create JWTSource: %v", err) - } - defer jwtSource.Close() - - audience := "TESTING" - spiffeID := spiffeid.RequireFromString("spiffe://example.org/nephio") - - jwtSVID, err := jwtSource.FetchJWTSVID(ctx, jwtsvid.Params{ - Audience: audience, - Subject: spiffeID, - }) - if err != nil { - log.Info("Unable to fetch JWT-SVID: %v", err) - } - - fmt.Printf("Fetched JWT-SVID: %v\n", jwtSVID.Marshal()) - if err != nil { - log.Error(err, "Spire auth didnt work") - } - - return jwtSVID, err -} - -func authenticateToVault(vaultAddr, jwt, role string) (string, error) { - // Create a Vault client - config := vault.DefaultConfig() - config.Address = vaultAddr - client, err := vault.NewClient(config) - if err != nil { - return "", fmt.Errorf("unable to create Vault client: %w", err) - } - - payload := LoginPayload{ - Role: role, - JWT: jwt, - } - payloadBytes, err := json.Marshal(payload) - if err != nil { - return "", fmt.Errorf("unable to marshal payload: %w", err) - } - - // Perform the login request - req := client.NewRequest("POST", "/v1/auth/jwt/login") - req.Body = bytes.NewBuffer(payloadBytes) - - resp, err := client.RawRequest(req) - if err != nil { - return "", fmt.Errorf("unable to perform login request: %w", err) - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "", fmt.Errorf("unable to read response body: %w", err) - } - - var authResp AuthResponse - if err := json.Unmarshal(body, &authResp); err != nil { - return "", fmt.Errorf("unable to decode response: %w", err) - } - - return authResp.Auth.ClientToken, nil -} - -func storeKubeconfig(kubeconfigData corev1.Secret, client *vault.Client, secretPath, clusterName string) error { - // Read the Kubeconfig file - - // Prepare the data to store - data := map[string]interface{}{ - "data": map[string]interface{}{ - clusterName: kubeconfigData.Data, - }, - } - - // Store the data in Vault - _, err := client.Logical().Write(secretPath, data) - if err != nil { - return fmt.Errorf("unable to write secret to Vault: %w", err) - } - - return nil -} - -func fetchKubeconfig(client *vault.Client, secretPath, clusterName string) (string, error) { - // Read the secret - secret, err := client.Logical().Read(secretPath) - if err != nil { - return "", fmt.Errorf("unable to read secret: %w", err) - } - - if secret == nil { - return "", fmt.Errorf("secret not found at path: %s", secretPath) - } - - // Extract the Kubeconfig data - kubeconfig, ok := secret.Data["test"].(string) - if !ok { - return "", fmt.Errorf("kubeconfig for cluster %s not found", clusterName) - } - - return kubeconfig, nil -} - -func createK8sResources(clientset *kubernetes.Clientset) error { +// unused for now +func createK8sSATokenResources(clientset *kubernetes.Clientset) error { // Create ServiceAccount sa := &v1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ diff --git a/controllers/pkg/resource/workloadapi.go b/controllers/pkg/resource/workloadapi.go new file mode 100644 index 00000000..45054cc8 --- /dev/null +++ b/controllers/pkg/resource/workloadapi.go @@ -0,0 +1,42 @@ +package resource + +import ( + "context" + "fmt" + + "github.com/spiffe/go-spiffe/v2/workloadapi" + + "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" + + "sigs.k8s.io/controller-runtime/pkg/log" +) + +func GetJWT(ctx context.Context) (*jwtsvid.SVID, error) { + socketPath := "unix:///spiffe-workload-api/agent.sock" + log := log.FromContext(ctx) + clientOptions := workloadapi.WithClientOptions(workloadapi.WithAddr(socketPath)) + jwtSource, err := workloadapi.NewJWTSource(ctx, clientOptions) + if err != nil { + log.Info("Unable to create JWTSource: %v", err) + } + defer jwtSource.Close() + + audience := "TESTING" + spiffeID := spiffeid.RequireFromString("spiffe://example.org/nephio") + + jwtSVID, err := jwtSource.FetchJWTSVID(ctx, jwtsvid.Params{ + Audience: audience, + Subject: spiffeID, + }) + if err != nil { + log.Info("Unable to fetch JWT-SVID: %v", err) + } + + fmt.Printf("Fetched JWT-SVID: %v\n", jwtSVID.Marshal()) + if err != nil { + log.Error(err, "Spire auth didnt work") + } + + return jwtSVID, err +} diff --git a/controllers/pkg/vault-client/vault.go b/controllers/pkg/vault-client/vault.go new file mode 100644 index 00000000..3f9aa7ed --- /dev/null +++ b/controllers/pkg/vault-client/vault.go @@ -0,0 +1,119 @@ +/* +Copyright 2023 The Nephio Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vaultClient + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + + vault "github.com/hashicorp/vault/api" + + corev1 "k8s.io/api/core/v1" +) + +type LoginPayload struct { + Role string `json:"role"` + JWT string `json:"jwt"` +} + +type AuthResponse struct { + Auth struct { + ClientToken string `json:"client_token"` + } `json:"auth"` +} + +func AuthenticateToVault(vaultAddr, jwt, role string) (string, error) { + // Create a Vault client + config := vault.DefaultConfig() + config.Address = vaultAddr + client, err := vault.NewClient(config) + if err != nil { + return "", fmt.Errorf("unable to create Vault client: %w", err) + } + + payload := LoginPayload{ + Role: role, + JWT: jwt, + } + payloadBytes, err := json.Marshal(payload) + if err != nil { + return "", fmt.Errorf("unable to marshal payload: %w", err) + } + + // Perform the login request + req := client.NewRequest("POST", "/v1/auth/jwt/login") + req.Body = bytes.NewBuffer(payloadBytes) + + resp, err := client.RawRequest(req) + if err != nil { + return "", fmt.Errorf("unable to perform login request: %w", err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("unable to read response body: %w", err) + } + + var authResp AuthResponse + if err := json.Unmarshal(body, &authResp); err != nil { + return "", fmt.Errorf("unable to decode response: %w", err) + } + + return authResp.Auth.ClientToken, nil +} + +func StoreKubeconfig(kubeconfigData corev1.Secret, client *vault.Client, secretPath, clusterName string) error { + // Read the Kubeconfig file + + // Prepare the data to store + data := map[string]interface{}{ + "data": map[string]interface{}{ + clusterName: kubeconfigData.Data, + }, + } + + // Store the data in Vault + _, err := client.Logical().Write(secretPath, data) + if err != nil { + return fmt.Errorf("unable to write secret to Vault: %w", err) + } + + return nil +} + +func FetchKubeconfig(client *vault.Client, secretPath, clusterName string) (string, error) { + // Read the secret + secret, err := client.Logical().Read(secretPath) + if err != nil { + return "", fmt.Errorf("unable to read secret: %w", err) + } + + if secret == nil { + return "", fmt.Errorf("secret not found at path: %s", secretPath) + } + + // Extract the Kubeconfig data + kubeconfig, ok := secret.Data["test"].(string) + if !ok { + return "", fmt.Errorf("kubeconfig for cluster %s not found", clusterName) + } + + return kubeconfig, nil +} From b07546491cb511d685ee80f12dbfc057383135cc Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Thu, 18 Jul 2024 09:12:23 +0530 Subject: [PATCH 12/14] Getting svid Signed-off-by: PrimalPimmy Getting svid-2 Signed-off-by: PrimalPimmy Getting svid-2 Signed-off-by: PrimalPimmy Getting svid-3 Signed-off-by: PrimalPimmy Getting svid-4 Signed-off-by: PrimalPimmy Getting svid-5 Signed-off-by: PrimalPimmy Getting svid-6 Signed-off-by: PrimalPimmy --- .../reconcilers/spire-bootstrap/reconciler.go | 12 +++++++++++ controllers/pkg/resource/workloadapi.go | 20 ++++++++++++++++++- controllers/pkg/vault-client/vault.go | 7 ++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 9248e85b..128987af 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -135,6 +135,18 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu fmt.Println("TESTTT 4444444") + // workloadAPIAddr := flag.String("workload-api-addr", "", "Workload API Address") + // flag.Parse() + + // var opts []workloadapi.ClientOption + // if *workloadAPIAddr != "" { + // opts = append(opts, workloadapi.WithAddr(*workloadAPIAddr)) + // } + + // fmt.Println("Watching...") + // err = workloadapi.WatchX509Context(context.Background(), resource.Watcher{}, opts...) + // log.Error(err, "Error: ") + clientToken, err := vaultClient.AuthenticateToVault(vaultAddr, jwtSVID.Marshal(), "dev") if err != nil { log.Error(err, "Error authenticating to Vault:") diff --git a/controllers/pkg/resource/workloadapi.go b/controllers/pkg/resource/workloadapi.go index 45054cc8..67be931e 100644 --- a/controllers/pkg/resource/workloadapi.go +++ b/controllers/pkg/resource/workloadapi.go @@ -13,7 +13,7 @@ import ( ) func GetJWT(ctx context.Context) (*jwtsvid.SVID, error) { - socketPath := "unix:///spiffe-workload-api/agent.sock" + socketPath := "unix:///spiffe-workload-api/spire-agent.sock" log := log.FromContext(ctx) clientOptions := workloadapi.WithClientOptions(workloadapi.WithAddr(socketPath)) jwtSource, err := workloadapi.NewJWTSource(ctx, clientOptions) @@ -40,3 +40,21 @@ func GetJWT(ctx context.Context) (*jwtsvid.SVID, error) { return jwtSVID, err } + +type Watcher struct{} + +func (Watcher) OnX509ContextUpdate(x509Context *workloadapi.X509Context) { + fmt.Println("Update:") + fmt.Println(" SVIDs:") + for _, svid := range x509Context.SVIDs { + fmt.Printf(" %s\n", svid.ID) + } + fmt.Println(" Bundles:") + for _, bundle := range x509Context.Bundles.Bundles() { + fmt.Printf(" %s (%d authorities)\n", bundle.TrustDomain(), len(bundle.X509Authorities())) + } +} + +func (Watcher) OnX509ContextWatchError(err error) { + fmt.Println("Error:", err) +} diff --git a/controllers/pkg/vault-client/vault.go b/controllers/pkg/vault-client/vault.go index 3f9aa7ed..58398c80 100644 --- a/controllers/pkg/vault-client/vault.go +++ b/controllers/pkg/vault-client/vault.go @@ -47,6 +47,8 @@ func AuthenticateToVault(vaultAddr, jwt, role string) (string, error) { return "", fmt.Errorf("unable to create Vault client: %w", err) } + fmt.Println("VAULT PRINT JWT: ", jwt) + payload := LoginPayload{ Role: role, JWT: jwt, @@ -60,12 +62,15 @@ func AuthenticateToVault(vaultAddr, jwt, role string) (string, error) { req := client.NewRequest("POST", "/v1/auth/jwt/login") req.Body = bytes.NewBuffer(payloadBytes) + fmt.Println("VAULT PRINT REQ:", req) resp, err := client.RawRequest(req) if err != nil { return "", fmt.Errorf("unable to perform login request: %w", err) } defer resp.Body.Close() + fmt.Println("VAULT PRINT: ", resp) + body, err := ioutil.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("unable to read response body: %w", err) @@ -76,7 +81,7 @@ func AuthenticateToVault(vaultAddr, jwt, role string) (string, error) { return "", fmt.Errorf("unable to decode response: %w", err) } - return authResp.Auth.ClientToken, nil + return authResp.Auth.ClientToken, err } func StoreKubeconfig(kubeconfigData corev1.Secret, client *vault.Client, secretPath, clusterName string) error { From 7f7d286165689a276a47373c86f7b372929ce021 Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Mon, 22 Jul 2024 08:45:23 +0530 Subject: [PATCH 13/14] Vault addr and patch configmap Signed-off-by: PrimalPimmy Vault addr and patch configmap Signed-off-by: PrimalPimmy --- .../reconcilers/spire-bootstrap/reconciler.go | 91 +++++++++++++++++-- 1 file changed, 85 insertions(+), 6 deletions(-) diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 128987af..247c9832 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -115,8 +115,6 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return reconcile.Result{}, err } - fmt.Println("TESTTT @@@@@@") - secrets := &v1.SecretList{} if err := r.List(ctx, secrets); err != nil { msg := "cannot list secrets" @@ -124,17 +122,21 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu return ctrl.Result{}, errors.Wrap(err, msg) } - fmt.Println("TESTTT 3333333") + vaultAddress := types.NamespacedName{Name: "vault-config", Namespace: "default"} + vaultconfigMap := &v1.ConfigMap{} + err = r.Get(ctx, vaultAddress, vaultconfigMap) + if err != nil { + log.Error(err, "unable to fetch ConfigMap") + return reconcile.Result{}, err + } - vaultAddr := "http://10.146.0.21:8200" + vaultAddr := vaultconfigMap.Data["VAULT_ADDR"] jwtSVID, err := resource.GetJWT(ctx) if err != nil { log.Error(err, "Unable to get jwtSVID") } - fmt.Println("TESTTT 4444444") - // workloadAPIAddr := flag.String("workload-api-addr", "", "Workload API Address") // flag.Parse() @@ -192,7 +194,11 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu Client, err := createK8sClientFromKubeconfig(decodedKubeConfig) createK8sSATokenResources(Client) + if err != nil { + fmt.Println("Error creating K8s", err) + } + err = r.createKubeconfigConfigMap(ctx, Client, cl.Name) if err != nil { fmt.Println("Error creating K8s", err) } @@ -362,3 +368,76 @@ func createK8sSATokenResources(clientset *kubernetes.Clientset) error { return nil } + +func (r *reconciler) createKubeconfigConfigMap(ctx context.Context, clientset *kubernetes.Clientset, clustername string) error { + + existingConfigMap, err := clientset.CoreV1().ConfigMaps("spire").Get(context.TODO(), "restricted-kubeconfigs", metav1.GetOptions{}) + if err != nil { + // ConfigMap doesn't exist, create a new one + existingConfigMap = &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restricted-kubeconfigs", + Namespace: "spire", + }, + Data: make(map[string]string), + } + } else { + return fmt.Errorf("failed to get existing ConfigMap: %v", err) + } + + // Retrieve the ServiceAccount token + secret, err := clientset.CoreV1().Secrets("spire").Get(context.TODO(), "agent-sa-secret", metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("failed to get ServiceAccount token: %v", err) + } + token := string(secret.Data["token"]) + + // Retrieve the cluster's CA certificate + configMap, err := clientset.CoreV1().ConfigMaps("kube-system").Get(context.TODO(), "kube-root-ca.crt", metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("failed to get cluster CA certificate: %v", err) + } + caCert := configMap.Data["ca.crt"] + + // Create kubeconfig content + kubeconfig := fmt.Sprintf(` +apiVersion: v1 +kind: Config +clusters: +- cluster: + certificate-authority-data: %s + server: https://kubernetes.default.svc + name: regional +contexts: +- context: + cluster: regional + namespace: spire + user: default-user + name: default-context +current-context: default-context +users: +- name: default-user + user: + token: %s +`, base64.StdEncoding.EncodeToString([]byte(caCert)), token) + + // Generate a unique key for the new kubeconfig + newConfigKey := fmt.Sprintf("kubeconfig-%s", clustername) + + // Add the new kubeconfig to the existing ConfigMap + if existingConfigMap.Data == nil { + existingConfigMap.Data = make(map[string]string) + } + existingConfigMap.Data[newConfigKey] = kubeconfig + + // _, err = clientset.CoreV1().ConfigMaps("spire").Create(context.TODO(), kubeconfigCM, metav1.CreateOptions{}) + err = r.Update(ctx, existingConfigMap) + if err != nil { + return fmt.Errorf("failed to create kubeconfig ConfigMap: %v", err) + } + + return nil +} + +// TODO +// Make Kubeconfig and patch the kubeconfigs configmap From 0f84207f7b8a12cd710fc02b71f92ba995b25c22 Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Thu, 25 Jul 2024 00:15:20 +0530 Subject: [PATCH 14/14] Restricted Kubeconfig Signed-off-by: PrimalPimmy configmap perms Signed-off-by: PrimalPimmy server addr Signed-off-by: PrimalPimmy Struct to yaml Signed-off-by: PrimalPimmy Struct to yaml Signed-off-by: PrimalPimmy Reverting changes Signed-off-by: PrimalPimmy Reverting changes Signed-off-by: PrimalPimmy Reverting changes Signed-off-by: PrimalPimmy Reverting changes Signed-off-by: PrimalPimmy Reverting changes Signed-off-by: PrimalPimmy Reverting changes Signed-off-by: PrimalPimmy Reverting changes Signed-off-by: PrimalPimmy Reverting changes Signed-off-by: PrimalPimmy --- .../reconcilers/spire-bootstrap/reconciler.go | 153 ++++++++++-------- 1 file changed, 88 insertions(+), 65 deletions(-) diff --git a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go index 247c9832..d4fca40e 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -17,10 +17,12 @@ limitations under the License. package spirebootstrap import ( + "bytes" "context" "encoding/base64" "fmt" "strings" + "text/template" "time" "github.com/nephio-project/nephio/controllers/pkg/cluster" @@ -83,16 +85,6 @@ type reconciler struct { func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { log := log.FromContext(ctx) - // Fetch the Cluster instance - - // List all Cluster instances - // clusterList := &capiv1beta1.ClusterList{} - // err := r.List(ctx, clusterList) - // if err != nil { - // log.Error(err, "unable to list Clusters") - // return reconcile.Result{}, err - // } - cl := &capiv1beta1.Cluster{} err := r.Get(ctx, req.NamespacedName, cl) if err != nil { @@ -104,7 +96,6 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu // Add your reconciliation logic here log.Info("Reconciling Cluster", "cluster", cl.Name) - fmt.Println("TESTTT !!!!!!!!!") // Fetch the ConfigMap from the current cluster configMapName := types.NamespacedName{Name: "spire-bundle", Namespace: "spire"} @@ -137,25 +128,11 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu log.Error(err, "Unable to get jwtSVID") } - // workloadAPIAddr := flag.String("workload-api-addr", "", "Workload API Address") - // flag.Parse() - - // var opts []workloadapi.ClientOption - // if *workloadAPIAddr != "" { - // opts = append(opts, workloadapi.WithAddr(*workloadAPIAddr)) - // } - - // fmt.Println("Watching...") - // err = workloadapi.WatchX509Context(context.Background(), resource.Watcher{}, opts...) - // log.Error(err, "Error: ") - clientToken, err := vaultClient.AuthenticateToVault(vaultAddr, jwtSVID.Marshal(), "dev") if err != nil { log.Error(err, "Error authenticating to Vault:") } - fmt.Println("TESTTT 5555555") - log.Info("Successfully authenticated to Vault.", "Client token:", clientToken) fmt.Println(clientToken) @@ -173,7 +150,6 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu if strings.Contains(secret.GetName(), cl.Name) { secret := secret vaultClient.StoreKubeconfig(secret, client, "secret/my-super-secret", cl.Name) - // clusterClient, ok := cluster.Cluster{Client: r.Client}.GetClusterClient(&secret) } } @@ -189,7 +165,7 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu fmt.Println("Error decoding base64:", err) } - log.Info("Secret retrieved:", "Secret", decodedKubeConfig) + log.Info("Secret retrieved:", "Secret", string(decodedKubeConfig)) Client, err := createK8sClientFromKubeconfig(decodedKubeConfig) @@ -198,11 +174,13 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu fmt.Println("Error creating K8s", err) } - err = r.createKubeconfigConfigMap(ctx, Client, cl.Name) + kubeconfigCM, err := r.createKubeconfigConfigMap(ctx, Client, cl.Name) if err != nil { - fmt.Println("Error creating K8s", err) + fmt.Println("Error creating K8s kubeconfig configmap", err) } + r.Update(ctx, kubeconfigCM) + for _, secret := range secrets.Items { if strings.Contains(secret.GetName(), cl.Name) { secret := secret // required to prevent gosec warning: G601 (CWE-118): Implicit memory aliasing in for loop @@ -369,74 +347,119 @@ func createK8sSATokenResources(clientset *kubernetes.Clientset) error { return nil } -func (r *reconciler) createKubeconfigConfigMap(ctx context.Context, clientset *kubernetes.Clientset, clustername string) error { +func (r *reconciler) createKubeconfigConfigMap(ctx context.Context, clientset *kubernetes.Clientset, clustername string) (*v1.ConfigMap, error) { - existingConfigMap, err := clientset.CoreV1().ConfigMaps("spire").Get(context.TODO(), "restricted-kubeconfigs", metav1.GetOptions{}) + cmName := types.NamespacedName{Name: "kubeconfigs", Namespace: "spire"} + restrictedKC := &v1.ConfigMap{} + err := r.Get(ctx, cmName, restrictedKC) if err != nil { - // ConfigMap doesn't exist, create a new one - existingConfigMap = &v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "restricted-kubeconfigs", - Namespace: "spire", - }, - Data: make(map[string]string), - } - } else { - return fmt.Errorf("failed to get existing ConfigMap: %v", err) + return nil, fmt.Errorf("failed to get existing ConfigMap: %v", err) } // Retrieve the ServiceAccount token secret, err := clientset.CoreV1().Secrets("spire").Get(context.TODO(), "agent-sa-secret", metav1.GetOptions{}) if err != nil { - return fmt.Errorf("failed to get ServiceAccount token: %v", err) + return nil, fmt.Errorf("failed to get ServiceAccount token: %v", err) } token := string(secret.Data["token"]) // Retrieve the cluster's CA certificate configMap, err := clientset.CoreV1().ConfigMaps("kube-system").Get(context.TODO(), "kube-root-ca.crt", metav1.GetOptions{}) if err != nil { - return fmt.Errorf("failed to get cluster CA certificate: %v", err) + return nil, fmt.Errorf("failed to get cluster CA certificate: %v", err) } caCert := configMap.Data["ca.crt"] - // Create kubeconfig content - kubeconfig := fmt.Sprintf(` + tmpl := ` +--- apiVersion: v1 kind: Config clusters: -- cluster: - certificate-authority-data: %s - server: https://kubernetes.default.svc - name: regional + - name: {{.ClusterName}} + cluster: + certificate-authority-data: {{.CA}} + server: {{.Server}} contexts: -- context: - cluster: regional - namespace: spire - user: default-user - name: default-context -current-context: default-context + - name: {{.ServiceAccount}}@{{.ClusterName}} + context: + cluster: {{.ClusterName}} + namespace: {{.Namespace}} + user: {{.ServiceAccount}} users: -- name: default-user - user: - token: %s -`, base64.StdEncoding.EncodeToString([]byte(caCert)), token) + - name: {{.ServiceAccount}} + user: + token: {{.Token}} +current-context: {{.ServiceAccount}}@{{.ClusterName}} +` + + // Create a struct to hold the data + data := struct { + ClusterName string + CA string + Server string + ServiceAccount string + Namespace string + Token string + }{ + ClusterName: clustername, + CA: caCert, + Server: clientset.RESTClient().Get().URL().String(), + ServiceAccount: "spire-kubeconfig", + Namespace: "spire", + Token: token, + } + + // Create a new template and parse the template string + t, err := template.New("kubeconfig").Parse(tmpl) + if err != nil { + fmt.Printf("Error parsing template: %v\n", err) + } + + // Execute the template with the data + var buf bytes.Buffer + err = t.Execute(&buf, data) + if err != nil { + fmt.Printf("Error executing template: %v\n", err) + } + + formattedKubeconfig := buf.String() + + // kubeconfig := strings.TrimSpace(fmt.Sprintf(` + // apiVersion: v1 + // kind: Config + // clusters: + // - cluster: + // certificate-authority-data: %s + // server: %s + // name: regional + // contexts: + // - context: + // cluster: %s + // namespace: spire + // user: spire-kubeconfig + // current-context: spire-kubeconfig@regional + // users: + // - name: spire-kubeconfig + // user: + // token: %s + // `, base64.StdEncoding.EncodeToString([]byte(caCert)), clientset.RESTClient().Get().URL().String(), clustername, token)) // Generate a unique key for the new kubeconfig newConfigKey := fmt.Sprintf("kubeconfig-%s", clustername) // Add the new kubeconfig to the existing ConfigMap - if existingConfigMap.Data == nil { - existingConfigMap.Data = make(map[string]string) + if restrictedKC.Data == nil { + restrictedKC.Data = make(map[string]string) } - existingConfigMap.Data[newConfigKey] = kubeconfig + restrictedKC.Data[newConfigKey] = formattedKubeconfig // _, err = clientset.CoreV1().ConfigMaps("spire").Create(context.TODO(), kubeconfigCM, metav1.CreateOptions{}) - err = r.Update(ctx, existingConfigMap) + err = r.Update(ctx, restrictedKC) if err != nil { - return fmt.Errorf("failed to create kubeconfig ConfigMap: %v", err) + return nil, fmt.Errorf("failed to create kubeconfig ConfigMap: %v", err) } - return nil + return restrictedKC, nil } // TODO