diff --git a/containers/types.go b/containers/types.go index 1d28872..372a01b 100644 --- a/containers/types.go +++ b/containers/types.go @@ -231,6 +231,71 @@ func (c *Container) SetPassword(password string) error { return err } +// Generate SSH keys and copies it into authorized keys +// Returns true if the key was generated in this call and error if there is any. +func (c *Container) GenerateDeploySSHKeys() (bool, error) { + driver := c.getDriver() + + privateKey, pubKey, _ := c.GetDeploySSHKeys() + if privateKey != "" || pubKey != "" { + return false, nil + } + + _, err := driver.Exec(c.App.Name, []string{"mkdir", "-p", "/srv/.ssh"}, "", []string{}, false) + if err != nil { + return false, err + } + + _, err = driver.Exec(c.App.Name, []string{"ssh-keygen", "-f", "/srv/.ssh/id_rsa", "-P", ""}, "", []string{}, false) + if err != nil { + return false, err + } + + _, err = driver.Exec(c.App.Name, []string{"chown", "app:app", "-R", "/srv/.ssh"}, "", []string{}, false) + if err != nil { + return false, err + } + + return true, nil +} + +// Generate SSH keys and copies it into authorized keys +// Return private key, public key and error. +func (c *Container) GetDeploySSHKeys() (string, string, error) { + driver := c.getDriver() + + privateKey, err := driver.Exec(c.App.Name, []string{"cat ", "/srv/.ssh/id_rsa"}, "", []string{}, true) + if err != nil { + return "", "", err + } + pubKey, err := driver.Exec(c.App.Name, []string{"cat ", "/srv/.ssh/id_rsa.pub"}, "", []string{}, true) + if err != nil { + return "", "", err + } + + if privateKey != nil || pubKey != nil { + return string(*privateKey), string(*pubKey), nil + } + + return "", "", nil +} + +func (c *Container) AppendOfFile(filename string, text string, mode string) error { + driver := c.getDriver() + + _, err := driver.Exec(c.App.Name, []string{"tee", "-a", filename}, text, []string{}, false) + if err != nil { + return err + } + + _, err = driver.Exec(c.App.Name, []string{"chmod", mode, filename}, "", []string{}, false) + if err != nil { + return err + } + + return nil +} + // SetAppPort changes application port in the container func (c *Container) SetAppPort(port int) error { driver := c.getDriver() diff --git a/glue/main.go b/glue/main.go index 12ea6b6..944864a 100644 --- a/glue/main.go +++ b/glue/main.go @@ -484,6 +484,41 @@ func (p *Processor) SetPassword(password string) error { return nil } +// Generate SSH key and adds it into authorized_keys +// These pair of keys is used for deployment. +// Returns private key, pubkey and error. +// Keys are returned every time even if it was already generated +func (p *Processor) GenerateDeploySSHKeys() (string, string, error) { + err := p.waitForApp() + if err != nil { + return "", "", err + } + + container, err := p.getContainer() + if err != nil { + return "", "", err + } + + created, err := container.GenerateDeploySSHKeys() + if err != nil { + return "", "", err + } + + privateKey, pubKey, err := container.GetDeploySSHKeys() + if err != nil { + return "", "", err + } + + if created { + err = container.AppendOfFile(sshPubKeysLocation, pubKey+"\n", "0600") + if err != nil { + return "", "", err + } + } + + return privateKey, pubKey, nil +} + // Processes returns list of supervisord processes func (p *Processor) Processes() ([]docker.Process, error) { container, err := p.getContainer() diff --git a/handlers_nats.go b/handlers_nats.go index b8678d6..2e140dd 100644 --- a/handlers_nats.go +++ b/handlers_nats.go @@ -50,6 +50,7 @@ func _messageHandler(m *nats.Msg) error { "stop": stopEventHandler, "start": startEventHandler, "restart": restartEventHandler, + "get_deploy_ssh_keys": getDeploySSHKeysEventHandler, "update_keys": updateKeysEventHandler, "set_password": setPasswordEventHandler, "processes": processesEventHandler, @@ -398,6 +399,45 @@ func restartEventHandler(m *nats.Msg, message *RequestMessage) error { return nil } +func getDeploySSHKeysEventHandler(m *nats.Msg, message *RequestMessage) error { + processor := glue.Processor{ + AppName: message.AppName, + DB: common.GetDBConnection(), + SnapshotProcessor: &snapshotProcessor, + DockerSock: config.DockerSocket, + BindIPHTTP: config.AppsBindIPHTTP, + BindIPSSH: config.AppsBindIPSSH, + AppsPath: config.AppsPath, + } + + privateKey, pubKey, err := processor.GenerateDeploySSHKeys() + if err != nil { + log.Printf("backend error: %v\n", err) + return errorReplyFormater(m, "backend error", err) + } + + // Assembling reply message + reply := ReplyMessage{ + Payload: struct{ PrivateKey, PublicKey string }{ + PrivateKey: privateKey, + PublicKey: pubKey, + }, + } + + data, err := json.Marshal(reply) + if err != nil { + return errorReplyFormater(m, "reply formatter error", err) + } + + err = m.Respond(data) + if err != nil { + log.Println("ERROR: get app:", err.Error()) + return err + } + + return nil +} + // Copies body of the request into /srv/.ssh/authorized_keys func updateKeysEventHandler(m *nats.Msg, message *RequestMessage) error { body := message.Payload