From 213838715b509811066761e5f5fded8a716328e8 Mon Sep 17 00:00:00 2001 From: Akilan Date: Fri, 15 Dec 2023 17:15:57 +0000 Subject: [PATCH] fixed adding public key as parameter when spawning a container --- client/container.go | 19 +- config/config.go | 11 + config/generate/generate.go | 11 +- config/generate/generateFiles.go | 336 ++++++++++++++++--------------- server/docker/docker.go | 31 ++- server/server.go | 15 +- 6 files changed, 244 insertions(+), 179 deletions(-) diff --git a/client/container.go b/client/container.go index 056acf4..295b39a 100644 --- a/client/container.go +++ b/client/container.go @@ -1,8 +1,10 @@ package client import ( + b64 "encoding/base64" "encoding/json" "fmt" + "github.com/Akilan1999/p2p-rendering-computation/config" "github.com/Akilan1999/p2p-rendering-computation/p2p" "github.com/Akilan1999/p2p-rendering-computation/server/docker" "io/ioutil" @@ -33,9 +35,22 @@ func StartContainer(IP string, NumPorts int, GPU bool, ContainerName string, bas //if version == "version 6" { // URL = "http://[" + IP + "]:" + serverPort + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName //} else { - URL = "http://" + IP + "/startcontainer?ports=" + fmt.Sprint(NumPorts) + "&GPU=" + strconv.FormatBool(GPU) + "&ContainerName=" + ContainerName + "&BaseImage=" + baseImage - //} + // Get config information + Config, err := config.ConfigInit(nil, nil) + if err != nil { + return nil, err + } + // Get public key + PublicKey, err := Config.GetPublicKey() + if err != nil { + return nil, err + } + + // Used in URL to pass public key -> b64.StdEncoding.EncodeToString([]byte(PublicKey)) + URL = `http://` + IP + `/startcontainer?ports=` + fmt.Sprint(NumPorts) + `&GPU=` + strconv.FormatBool(GPU) + `&ContainerName=` + ContainerName + `&BaseImage=` + baseImage + `&PublicKey=` + b64.StdEncoding.EncodeToString([]byte(PublicKey)) + + // Encode URL due to public key passed. resp, err := http.Get(URL) if err != nil { return nil, err diff --git a/config/config.go b/config/config.go index 1ccc772..772c844 100644 --- a/config/config.go +++ b/config/config.go @@ -158,3 +158,14 @@ func (c *Config) WriteConfig() error { _ = ioutil.WriteFile(defaultPath+"config.json", file, 0644) return nil } + +// GetPublicKey Gets public key of the current machine +// based on the path provided on the +// config file +func (c *Config) GetPublicKey() (string, error) { + publicKey, err := ioutil.ReadFile(c.PublicKeyFile) // just pass the file name + if err != nil { + return "", err + } + return string(publicKey), nil +} diff --git a/config/generate/generate.go b/config/generate/generate.go index d8ed3ab..2d21838 100644 --- a/config/generate/generate.go +++ b/config/generate/generate.go @@ -99,12 +99,19 @@ func SetDefaults(envName string, forceDefault bool, CustomConfig interface{}, No Defaults.PublicKeyFile = defaultPath + "p2prc.publicKey" Defaults.PrivateKeyFile = defaultPath + "p2prc.privateKey" - // Generate SSH keys - err = MakeSSHKeyPair(Defaults.PublicKeyFile, Defaults.PrivateKeyFile) + PrivateKeyExists, err := FileExists(Defaults.PrivateKeyFile) if err != nil { return nil, err } + if !PrivateKeyExists { + // Generate SSH keys + err = MakeSSHKeyPair(Defaults.PublicKeyFile, Defaults.PrivateKeyFile) + if err != nil { + return nil, err + } + } + Defaults.MachineName = hostname + "-" + String(7) } else { Defaults = *ConfigUpdate[0] diff --git a/config/generate/generateFiles.go b/config/generate/generateFiles.go index 3eff648..3bb6da8 100644 --- a/config/generate/generateFiles.go +++ b/config/generate/generateFiles.go @@ -1,171 +1,180 @@ package generate import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/pem" - "github.com/Akilan1999/p2p-rendering-computation/p2p" - "github.com/go-git/go-git/v5" - "golang.org/x/crypto/ssh" - "io/ioutil" - "os" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "github.com/Akilan1999/p2p-rendering-computation/p2p" + "github.com/go-git/go-git/v5" + "golang.org/x/crypto/ssh" + "io/ioutil" + "os" ) // GenerateFiles Generates all the files needed to setup P2PRC func GenerateFiles(rootNodes ...p2p.IpAddress) (err error) { - err = GenerateIPTableFile(rootNodes) - err = GenerateDockerFiles() - err = GeneratePluginDirectory() - err = GenerateClientTrackContainers() - return + err = GenerateIPTableFile(rootNodes) + if err != nil { + return err + } + err = GenerateDockerFiles() + if err != nil { + return err + } + err = GeneratePluginDirectory() + if err != nil { + return err + } + err = GenerateClientTrackContainers() + return } // GenerateIPTableFile Generates the IPTable file with the appropirate root node func GenerateIPTableFile(rootNodes []p2p.IpAddress) (err error) { - var rootnodes p2p.IpAddresses - var rootnode p2p.IpAddress + var rootnodes p2p.IpAddresses + var rootnode p2p.IpAddress - err = CreateIPTableFolderStructure() - if err != nil { - return err - } + err = CreateIPTableFolderStructure() + if err != nil { + return err + } - // If root node addresses are not provided as optional parameters - if len(rootNodes) <= 0 { - rootnode.Name = "Node1" - rootnode.ServerPort = "8078" - rootnode.NAT = "False" - rootnode.Ipv4 = "139.59.162.154" + // If root node addresses are not provided as optional parameters + if len(rootNodes) <= 0 { + rootnode.Name = "Node1" + rootnode.ServerPort = "8078" + rootnode.NAT = "False" + rootnode.Ipv4 = "139.59.162.154" - rootnodes.IpAddress = append(rootnodes.IpAddress, rootnode) - } else { - // if root nodes are provided then override them as the optional parameter - for i := range rootNodes { - rootnodes.IpAddress = append(rootnodes.IpAddress, rootNodes[i]) - } - } + rootnodes.IpAddress = append(rootnodes.IpAddress, rootnode) + } else { + // if root nodes are provided then override them as the optional parameter + for i := range rootNodes { + rootnodes.IpAddress = append(rootnodes.IpAddress, rootNodes[i]) + } + } - err = rootnodes.WriteIpTable() - return + err = rootnodes.WriteIpTable() + return } // CreateIPTableFolderStructure Create folder structure for IPTable func CreateIPTableFolderStructure() (err error) { - path, err := GetCurrentPath() - if err != nil { - return err - } - if _, err = os.Stat(path + "p2p"); os.IsNotExist(err) { - if err = os.Mkdir(path+"p2p", os.ModePerm); err != nil { - return err - } - } - if _, err = os.Stat(path + "p2p/iptable"); os.IsNotExist(err) { - if err = os.Mkdir(path+"p2p/iptable", os.ModePerm); err != nil { - return err - } - } - if _, err = os.Stat(path + "p2p/iptable/ip_table.json"); os.IsNotExist(err) { - _, err = os.Create(path + "p2p/iptable/ip_table.json") - if err != nil { - return err - } - } + path, err := GetCurrentPath() + if err != nil { + return err + } + if _, err = os.Stat(path + "p2p"); os.IsNotExist(err) { + if err = os.Mkdir(path+"p2p", os.ModePerm); err != nil { + return err + } + } + if _, err = os.Stat(path + "p2p/iptable"); os.IsNotExist(err) { + if err = os.Mkdir(path+"p2p/iptable", os.ModePerm); err != nil { + return err + } + } + if _, err = os.Stat(path + "p2p/iptable/ip_table.json"); os.IsNotExist(err) { + _, err = os.Create(path + "p2p/iptable/ip_table.json") + if err != nil { + return err + } + } - return + return } // GenerateDockerFiles Generate default docker files func GenerateDockerFiles() (err error) { - path, err := GetCurrentPath() - if err != nil { - return err - } - if _, err = os.Stat(path + "server"); os.IsNotExist(err) { - if err = os.Mkdir(path+"server", os.ModePerm); err != nil { - return err - } - if _, err = os.Stat(path + "server/docker"); os.IsNotExist(err) { - if err = os.Mkdir(path+"server/docker", os.ModePerm); err != nil { - return err - } - } - if _, err = os.Stat(path + "server/docker/containers"); os.IsNotExist(err) { - if err = os.Mkdir(path+"server/docker/containers", os.ModePerm); err != nil { - return err - } - } - if _, err = os.Stat(path + "server/docker/containers"); os.IsNotExist(err) { - if err = os.Mkdir(path+"server/docker/containers", os.ModePerm); err != nil { - return err - } - } - if _, err = os.Stat(path + "server/docker/containers/docker-ubuntu-sshd"); os.IsNotExist(err) { - if err = os.Mkdir(path+"server/docker/containers/docker-ubuntu-sshd", os.ModePerm); err != nil { - return err - } - } + path, err := GetCurrentPath() + if err != nil { + return err + } + if _, err = os.Stat(path + "server"); os.IsNotExist(err) { + if err = os.Mkdir(path+"server", os.ModePerm); err != nil { + return err + } + if _, err = os.Stat(path + "server/docker"); os.IsNotExist(err) { + if err = os.Mkdir(path+"server/docker", os.ModePerm); err != nil { + return err + } + } + if _, err = os.Stat(path + "server/docker/containers"); os.IsNotExist(err) { + if err = os.Mkdir(path+"server/docker/containers", os.ModePerm); err != nil { + return err + } + } + if _, err = os.Stat(path + "server/docker/containers"); os.IsNotExist(err) { + if err = os.Mkdir(path+"server/docker/containers", os.ModePerm); err != nil { + return err + } + } + if _, err = os.Stat(path + "server/docker/containers/docker-ubuntu-sshd"); os.IsNotExist(err) { + if err = os.Mkdir(path+"server/docker/containers/docker-ubuntu-sshd", os.ModePerm); err != nil { + return err + } + } - } + } - // Clone base docker image - _, err = git.PlainClone(path+"server/docker/containers/docker-ubuntu-sshd", false, &git.CloneOptions{ - URL: "https://github.com/Akilan1999/docker-ubuntu-sshd", - Progress: os.Stdout, - }) - if err != nil { - return err - } + // Clone base docker image + _, err = git.PlainClone(path+"server/docker/containers/docker-ubuntu-sshd", false, &git.CloneOptions{ + URL: "https://github.com/Akilan1999/docker-ubuntu-sshd", + Progress: os.Stdout, + }) + if err != nil { + return err + } - return + return } // GeneratePluginDirectory Generates plugin directory structure func GeneratePluginDirectory() (err error) { - path, err := GetCurrentPath() - if err != nil { - return err - } - if _, err = os.Stat(path + "plugin"); os.IsNotExist(err) { - if err = os.Mkdir(path+"plugin", os.ModePerm); err != nil { - return err - } - if _, err = os.Stat(path + "plugin/deploy"); os.IsNotExist(err) { - if err = os.Mkdir(path+"plugin/deploy", os.ModePerm); err != nil { - return err - } - } - } - return + path, err := GetCurrentPath() + if err != nil { + return err + } + if _, err = os.Stat(path + "plugin"); os.IsNotExist(err) { + if err = os.Mkdir(path+"plugin", os.ModePerm); err != nil { + return err + } + if _, err = os.Stat(path + "plugin/deploy"); os.IsNotExist(err) { + if err = os.Mkdir(path+"plugin/deploy", os.ModePerm); err != nil { + return err + } + } + } + return } func GenerateClientTrackContainers() (err error) { - path, err := GetCurrentPath() - if err != nil { - return err - } - if _, err = os.Stat(path + "client"); os.IsNotExist(err) { - if err = os.Mkdir(path+"client", os.ModePerm); err != nil { - return err - } - if err = os.Mkdir(path+"client/trackcontainers", os.ModePerm); err != nil { - return err - } + path, err := GetCurrentPath() + if err != nil { + return err + } + if _, err = os.Stat(path + "client"); os.IsNotExist(err) { + if err = os.Mkdir(path+"client", os.ModePerm); err != nil { + return err + } + if err = os.Mkdir(path+"client/trackcontainers", os.ModePerm); err != nil { + return err + } - if _, err = os.Stat(path + "client/trackcontainers/trackcontainers.json"); os.IsNotExist(err) { - _, err = os.Create(path + "client/trackcontainers/trackcontainers.json") - if err != nil { - return err - } - _, err = os.Create(path + "client/trackcontainers/grouptrackcontainers.json") - if err != nil { - return err - } - } + if _, err = os.Stat(path + "client/trackcontainers/trackcontainers.json"); os.IsNotExist(err) { + _, err = os.Create(path + "client/trackcontainers/trackcontainers.json") + if err != nil { + return err + } + _, err = os.Create(path + "client/trackcontainers/grouptrackcontainers.json") + if err != nil { + return err + } + } - } - return + } + return } // MakeSSHKeyPair make a pair of public and private keys for SSH access. @@ -173,31 +182,44 @@ func GenerateClientTrackContainers() (err error) { // Private Key generated is PEM encoded // source: https://gist.github.com/goliatone/e9c13e5f046e34cef6e150d06f20a34c func MakeSSHKeyPair(pubKeyPath, privateKeyPath string) error { - privateKey, err := rsa.GenerateKey(rand.Reader, 1024) - if err != nil { - return err - } - // generate and write private key as PEM - privateKeyFile, err := os.Create(privateKeyPath) - defer privateKeyFile.Close() - if err != nil { - return err - } + privateKey, err := rsa.GenerateKey(rand.Reader, 1024) + if err != nil { + return err + } + // generate and write private key as PEM + privateKeyFile, err := os.Create(privateKeyPath) + defer privateKeyFile.Close() + if err != nil { + return err + } - // Set permission to private key to SSH into docker machine - err = os.Chmod("privateKeyPath", 600) - if err != nil { - return err - } + // Set permission to private key to SSH into docker machine + err = os.Chmod(privateKeyPath, 600) + if err != nil { + return err + } - privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)} - if err := pem.Encode(privateKeyFile, privateKeyPEM); err != nil { - return err - } - // generate and write public key - pub, err := ssh.NewPublicKey(&privateKey.PublicKey) - if err != nil { - return err - } - return ioutil.WriteFile(pubKeyPath, ssh.MarshalAuthorizedKey(pub), 0655) + privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)} + if err := pem.Encode(privateKeyFile, privateKeyPEM); err != nil { + return err + } + // generate and write public key + pub, err := ssh.NewPublicKey(&privateKey.PublicKey) + if err != nil { + return err + } + return ioutil.WriteFile(pubKeyPath, ssh.MarshalAuthorizedKey(pub), 0655) +} + +// FileExists exists returns whether the given file or directory exists +// source: https://stackoverflow.com/questions/10510691/how-to-check-whether-a-file-or-directory-exists +func FileExists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err } diff --git a/server/docker/docker.go b/server/docker/docker.go index d0d9473..26dcd10 100644 --- a/server/docker/docker.go +++ b/server/docker/docker.go @@ -20,18 +20,17 @@ import ( ) type DockerVM struct { - SSHUsername string `json:"SSHUsername"` - SSHPublcKey string `json:"SSHPublicKey"` - SSHPrivateKey string `json:"SSHPrivateKey"` - ID string `json:"ID"` - TagName string `json:"TagName"` - ImagePath string `json:"ImagePath"` - Ports Ports `json:"Ports"` - GPU string `json:"GPU"` - TempPath string - BaseImage string - LogsPath string - SSHCommand string `json:"SSHCommand"` + SSHUsername string `json:"SSHUsername"` + SSHPublcKey string `json:"SSHPublicKey"` + ID string `json:"ID"` + TagName string `json:"TagName"` + ImagePath string `json:"ImagePath"` + Ports Ports `json:"Ports"` + GPU string `json:"GPU"` + TempPath string + BaseImage string + LogsPath string + SSHCommand string `json:"SSHCommand"` } type DockerContainers struct { @@ -68,7 +67,7 @@ var dockerRegistryUserID = "" // BuildRunContainer Function is incharge to invoke building and running contianer and also allocating external // ports -func BuildRunContainer(NumPorts int, GPU string, ContainerName string, baseImage string) (*DockerVM, error) { +func BuildRunContainer(NumPorts int, GPU string, ContainerName string, baseImage string, publicKey string) (*DockerVM, error) { //Docker Struct Variable var RespDocker *DockerVM = new(DockerVM) @@ -95,8 +94,7 @@ func BuildRunContainer(NumPorts int, GPU string, ContainerName string, baseImage } RespDocker.ImagePath = config.DefaultDockerFile RespDocker.LogsPath = config.DockerRunLogs - RespDocker.SSHPublcKey = config.PublicKeyFile - RespDocker.SSHPrivateKey = config.PrivateKeyFile + RespDocker.SSHPublcKey = publicKey // We are checking if the container name is not nil and not equal to the default one used // which is docker-ubuntu-sshd @@ -198,10 +196,9 @@ func (d *DockerVM) imageBuild(dockerClient *client.Client) error { //defer cancel() var cmd bytes.Buffer - cmd.WriteString("docker build -t " + d.TagName + " " + d.ImagePath + "/" + d.TagName + ` --build-arg SSH_KEY="$(cat ` + d.SSHPublcKey + `)"`) + cmd.WriteString("docker build -t " + d.TagName + " " + d.ImagePath + "/" + d.TagName + ` --build-arg SSH_KEY="` + d.SSHPublcKey + `"`) //"-v=/opt/data:/data p2p-ubuntu /start > /dev/null" cmdStr := cmd.String() - fmt.Println(cmdStr) output, err := exec.Command("/bin/sh", "-c", cmdStr).Output() fmt.Printf("%s", output) if err != nil { diff --git a/server/server.go b/server/server.go index 802b549..5f19a6c 100644 --- a/server/server.go +++ b/server/server.go @@ -1,6 +1,7 @@ package server import ( + b64 "encoding/base64" "encoding/json" "fmt" "github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable" @@ -108,14 +109,26 @@ func Server() (*gin.Engine, error) { GPU := c.DefaultQuery("GPU", "false") ContainerName := c.DefaultQuery("ContainerName", "") BaseImage := c.DefaultQuery("BaseImage", "") + PublicKey := c.DefaultQuery("PublicKey", "") var PortsInt int + if PublicKey == "" { + c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", "Publickey not passed")) + } + + PublicKeyDecoded, err := b64.StdEncoding.DecodeString(PublicKey) + if err != nil { + c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) + } + // Convert Get Request value to int fmt.Sscanf(Ports, "%d", &PortsInt) + fmt.Println(string(PublicKeyDecoded[:])) + // Creates container and returns-back result to // access container - resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName, BaseImage) + resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName, BaseImage, string(PublicKeyDecoded[:])) if err != nil { c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))