Added new route to retrieve the host's kubeconfig with the execution's SA token

This commit is contained in:
pb 2025-02-28 14:07:45 +01:00
parent 7b27945493
commit f75499d827
4 changed files with 183 additions and 5 deletions

View File

@ -1,9 +1,12 @@
package controllers
import (
"encoding/base64"
"encoding/json"
"fmt"
"oc-datacenter/conf"
"oc-datacenter/infrastructure"
"oc-datacenter/models"
"slices"
"time"
@ -20,7 +23,7 @@ type KubeInfo struct {
KubeKey *string
}
type Kubeconfig struct {
type RemoteKubeconfig struct {
Data *string
}
@ -30,6 +33,35 @@ type KubeUser struct {
Token string
}
}
type KubeconfigToken struct {
ApiVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Preferences string `yaml:"preferences"`
CurrentContext string `yaml:"current-context"`
Clusters []struct{
Cluster struct{
CA string `yaml:"certificate-authority-data"`
Server string `yaml:"server"`
} `yaml:"cluster"`
Name string `yaml:"name"`
} `yaml:"clusters"`
Contexts []struct{
Context struct{
Cluster string `yaml:"cluster"`
User string `yaml:"user"`
} `yaml:"context"`
Name string `yaml:"name"`
} `yaml:"contexts"`
Users []struct{
Name string `yaml:"name"`
User struct {
Token string `yaml:"token"`
} `yaml:"user"`
} `yaml:"users"`
}
// Operations about the admiralty objects of the datacenter
type AdmiraltyController struct {
beego.Controller
@ -250,7 +282,7 @@ func(c *AdmiraltyController) GetKubeSecret() {
// @Success 200
// @router /secret/:dc_id/:execution [post]
func (c *AdmiraltyController) CreateKubeSecret() {
var kubeconfig Kubeconfig
var kubeconfig RemoteKubeconfig
var respData map[string]interface{}
data := c.Ctx.Input.CopyBody(100000)
@ -388,4 +420,93 @@ func (c *AdmiraltyController) GetNodeReady(){
c.Data["json"] = map[string]bool{"ok": true}
c.ServeJSON()
}
// @name Get Admiralty Kubeconfig
// @description Retrieve a kubeconfig from the host with the token to authenticate as the SA from the namespace identified with execution id
// @Param dc_id path string true "which dc to contact"
// @Param execution path string true "execution id of the workflow"
// @Success 200
// @router /kubeconfig/:dc_id/:execution [get]
func (c *AdmiraltyController) GetAdmiraltyKubeconfig() {
dc_id := c.Ctx.Input.Param(":dc_id")
execution := c.Ctx.Input.Param(":execution")
_ = dc_id
serv, err := infrastructure.NewService()
if err != nil {
// change code to 500
c.Ctx.Output.SetStatus(500)
c.Data["json"] = map[string]string{"error": err.Error()}
c.ServeJSON()
return
}
generatedToken, err := serv.GenerateToken(c.Ctx.Request.Context(),execution,3600)
if err != nil {
fmt.Println("Couldn't generate a token for ns-", execution)
fmt.Println(err)
c.Ctx.Output.SetStatus(500)
c.Data["json"] = map[string]string{"error": err.Error()}
c.ServeJSON()
return
}
kubeconfig, err := NewHostKubeWithToken(generatedToken)
if err != nil {
fmt.Println("Could not retrieve the Kubeconfig edited with token")
fmt.Println(err)
c.Ctx.Output.SetStatus(500)
c.Data["json"] = map[string]string{"error": err.Error()}
c.ServeJSON()
return
}
c.Data["json"] = kubeconfig
c.ServeJSON()
return
}
func NewHostKubeWithToken(token string) (*models.KubeConfigValue, error){
if len(token) == 0 {
return nil, fmt.Errorf("You didn't provide a token to be inserted in the Kubeconfig")
}
encodedCA := base64.StdEncoding.EncodeToString([]byte(conf.GetConfig().KubeCA))
hostKube := models.KubeConfigValue{
APIVersion: "v1",
CurrentContext: "default",
Kind: "Config",
Preferences: struct{}{},
Clusters: []models.KubeconfigNamedCluster{
{
Name: "default",
Cluster: models.KubeconfigCluster{
Server: conf.GetConfig().KubeHost,
CertificateAuthorityData: encodedCA,
},
},
},
Contexts: []models.KubeconfigNamedContext{
{
Name: "default",
Context: models.KubeconfigContext{
Cluster: "default",
User: "default",
},
},
},
Users: []models.KubeconfigUser{
models.KubeconfigUser{
Name: "default",
User: models.KubeconfigUserKeyPair{
Token: token,
},
},
},
}
return &hostKube, nil
}

View File

@ -9,11 +9,9 @@ workflow --> locdc : POST /booking/ {booking object}
locdc --> locdc : create Namespace + ServiceAccount
monitord --> monitord : retrieves a Workflow to execute
monitord --> monitord : workflow needs repartited execution
' monitord --> locdc : POST /admiralty/setup/:executions_id
monitord --> rocdc : POST /????? (route that use the same \nmethods as /booking/ to create NS & SA)
monitord --> rocdc : POST /admiralty/source
rocdc --> rocdc : create token for SA in NS
rocdc --> rocdc : edit
monitord --> rodc : GET /admiralty/token/:execution_id
rocdc -> monitord : base64 encoded edited kubeconfig with token (**how to make it secure** ???)
monitord --> locdc : POST /admiralty/secret/:execution_id
monitord --> locdc : POST /admiralty/target/:execution_id

View File

@ -174,6 +174,9 @@ func (k *KubernetesService) DeleteNamespace(ctx context.Context, ns string) erro
return nil
}
// Returns the string representing the token generated for the serviceAccount
// in the namespace identified by the value `ns` with the name sa-`ns`, which is valid for
// `duration` seconds
func (k *KubernetesService) GenerateToken(ctx context.Context, ns string, duration int) (string, error) {
// Define TokenRequest (valid for 1 hour)
d := int64(duration)

56
models/kubeconfig.go Normal file
View File

@ -0,0 +1,56 @@
package models
// KubeConfigValue is a struct used to create a kubectl configuration YAML file.
type KubeConfigValue struct {
APIVersion string `yaml:"apiVersion"`
Kind string `yaml:"kind"`
Clusters []KubeconfigNamedCluster `yaml:"clusters"`
Users []KubeconfigUser `yaml:"users"`
Contexts []KubeconfigNamedContext `yaml:"contexts"`
CurrentContext string `yaml:"current-context"`
Preferences struct{} `yaml:"preferences"`
}
// KubeconfigUser is a struct used to create a kubectl configuration YAML file
type KubeconfigUser struct {
Name string `yaml:"name"`
User KubeconfigUserKeyPair `yaml:"user"`
}
// KubeconfigUserKeyPair is a struct used to create a kubectl configuration YAML file
type KubeconfigUserKeyPair struct {
Token string `yaml:"token"`
}
// KubeconfigAuthProvider is a struct used to create a kubectl authentication provider
type KubeconfigAuthProvider struct {
Name string `yaml:"name"`
Config map[string]string `yaml:"config"`
}
// KubeconfigNamedCluster is a struct used to create a kubectl configuration YAML file
type KubeconfigNamedCluster struct {
Name string `yaml:"name"`
Cluster KubeconfigCluster `yaml:"cluster"`
}
// KubeconfigCluster is a struct used to create a kubectl configuration YAML file
type KubeconfigCluster struct {
Server string `yaml:"server"`
CertificateAuthorityData string `yaml:"certificate-authority-data"`
CertificateAuthority string `yaml:"certificate-authority"`
}
// KubeconfigNamedContext is a struct used to create a kubectl configuration YAML file
type KubeconfigNamedContext struct {
Name string `yaml:"name"`
Context KubeconfigContext `yaml:"context"`
}
// KubeconfigContext is a struct used to create a kubectl configuration YAML file
type KubeconfigContext struct {
Cluster string `yaml:"cluster"`
Namespace string `yaml:"namespace,omitempty"`
User string `yaml:"user"`
}