Added new route to retrieve the host's kubeconfig with the execution's SA token
This commit is contained in:
		@@ -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
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
									
								
							
							
						
						
									
										56
									
								
								models/kubeconfig.go
									
									
									
									
									
										Normal 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"`
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user