From 59aa8166d230870850729561a4c58b638f5a1f34 Mon Sep 17 00:00:00 2001 From: PrimalPimmy Date: Tue, 9 Jul 2024 18:13:58 +0530 Subject: [PATCH] Mid testing Signed-off-by: PrimalPimmy --- controllers/pkg/go.sum | 20 +- .../reconcilers/spire-bootstrap/reconciler.go | 243 +++++++++++++----- 2 files changed, 184 insertions(+), 79 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..091928db 100644 --- a/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go +++ b/controllers/pkg/reconcilers/spire-bootstrap/reconciler.go @@ -23,11 +23,15 @@ import ( "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" vault "github.com/hashicorp/vault/api" "github.com/spiffe/go-spiffe/v2/spiffeid" @@ -35,6 +39,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 +125,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) @@ -212,9 +165,80 @@ func (r *reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu fmt.Printf("Secret retrieved: %v\n", kubeconfig) + // decodedKubeConfig, err := base64.StdEncoding.DecodeString(kubeconfig) + // if err != nil { + // fmt.Println("Error decoding base64:", err) + // } + + secret := r.createKubeconfigSecret(cl.Name+"-kubeconfig", []byte(kubeconfig)) + + if err != nil { + fmt.Println("Error creating K8s", err) + } + + 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 { + 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) + } + + } + } + return reconcile.Result{}, nil } +func (r *reconciler) createKubeconfigSecret(secretName string, kubeconfigData []byte) *v1.Secret { + secret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretName, + }, + Data: map[string][]byte{ + "kubeconfig": kubeconfigData, + }, + } + + return secret +} + func getJWT(ctx context.Context) (*jwtsvid.SVID, error) { socketPath := "unix:///spiffe-workload-api/agent.sock" log := log.FromContext(ctx) @@ -285,24 +309,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 +347,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 +}