Skip to content

Commit 853d4a1

Browse files
committed
refactor: new proxyCommands.env & stable ssh host key
1 parent 08a5a4e commit 853d4a1

6 files changed

Lines changed: 86 additions & 3 deletions

File tree

helper/cmd/ssh.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
// SSHCmd holds the ssh cmd flags
1515
type SSHCmd struct {
16+
HostKey string
1617
AuthorizedKeys string
1718
Address string
1819
}
@@ -28,6 +29,7 @@ func NewSSHCmd() *cobra.Command {
2829
}
2930

3031
sshCmd.Flags().StringVar(&cmd.Address, "address", fmt.Sprintf(":%d", helperssh.DefaultPort), "Address to listen to")
32+
sshCmd.Flags().StringVar(&cmd.HostKey, "host-key", "", "Base64 encoded host key to use")
3133
sshCmd.Flags().StringVar(&cmd.AuthorizedKeys, "authorized-key", "", "Base64 encoded authorized keys to use")
3234
return sshCmd
3335
}
@@ -52,7 +54,16 @@ func (cmd *SSHCmd) Run(_ *cobra.Command, _ []string) error {
5254
}
5355
}
5456

55-
server, err := helperssh.NewServer(cmd.Address, keys)
57+
hostKey := []byte{}
58+
if len(cmd.HostKey) > 0 {
59+
var err error
60+
hostKey, err = base64.StdEncoding.DecodeString(cmd.HostKey)
61+
if err != nil {
62+
return fmt.Errorf("decode host key")
63+
}
64+
}
65+
66+
server, err := helperssh.NewServer(cmd.Address, hostKey, keys)
5667
if err != nil {
5768
return err
5869
}

helper/ssh/server.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717

1818
var DefaultPort = 8022
1919

20-
func NewServer(addr string, keys []ssh.PublicKey) (*Server, error) {
20+
func NewServer(addr string, hostKey []byte, keys []ssh.PublicKey) (*Server, error) {
2121
shell, err := getShell()
2222
if err != nil {
2323
return nil, err
@@ -64,6 +64,13 @@ func NewServer(addr string, keys []ssh.PublicKey) (*Server, error) {
6464
},
6565
}
6666

67+
if len(hostKey) > 0 {
68+
err = server.sshServer.SetOption(ssh.HostKeyPEM(hostKey))
69+
if err != nil {
70+
return nil, err
71+
}
72+
}
73+
6774
server.sshServer.Handler = server.handler
6875
return server, nil
6976
}

pkg/devspace/config/versions/latest/schema.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,9 @@ type ProxyCommand struct {
870870

871871
// SkipContainerEnv will not forward the container environment variables to the local command
872872
SkipContainerEnv bool `yaml:"skipContainerEnv,omitempty" json:"skipContainerEnv,omitempty"`
873+
874+
// Env are extra environment variables to set for the command
875+
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
873876
}
874877

875878
type SSH struct {

pkg/devspace/services/proxycommands/server.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ func (s *Server) getCommand(sess ssh.Session) (*exec.Cmd, *types.ProxyCommand, e
180180
cmd.Env = append(cmd.Env, command.Env...)
181181
}
182182
cmd.Env = append(cmd.Env, os.Environ()...)
183+
for k, v := range reverseCommand.Env {
184+
cmd.Env = append(cmd.Env, k+"="+v)
185+
}
183186
return cmd, command, nil
184187
}
185188

pkg/devspace/services/ssh/keys.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,37 @@ import (
1919

2020
var (
2121
DevSpaceSSHFolder = "ssh"
22+
DevSpaceSSHHostKeyFile = "id_devspace_host_rsa"
2223
DevSpaceSSHPrivateKeyFile = "id_devspace_rsa"
2324
DevSpaceSSHPublicKeyFile = "id_devspace_rsa.pub"
2425
)
2526

2627
func init() {
2728
homeDir, _ := homedir.Dir()
2829
DevSpaceSSHFolder = filepath.Join(homeDir, constants.DefaultHomeDevSpaceFolder, DevSpaceSSHFolder)
30+
DevSpaceSSHHostKeyFile = filepath.Join(DevSpaceSSHFolder, DevSpaceSSHHostKeyFile)
2931
DevSpaceSSHPrivateKeyFile = filepath.Join(DevSpaceSSHFolder, DevSpaceSSHPrivateKeyFile)
3032
DevSpaceSSHPublicKeyFile = filepath.Join(DevSpaceSSHFolder, DevSpaceSSHPublicKeyFile)
3133
}
3234

3335
var keyLock sync.Mutex
3436

37+
func MakeHostKey() (string, error) {
38+
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
39+
if err != nil {
40+
return "", err
41+
}
42+
43+
// generate and write private key as PEM
44+
var privKeyBuf strings.Builder
45+
privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
46+
if err := pem.Encode(&privKeyBuf, privateKeyPEM); err != nil {
47+
return "", err
48+
}
49+
50+
return privKeyBuf.String(), nil
51+
}
52+
3553
func MakeSSHKeyPair() (string, string, error) {
3654
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
3755
if err != nil {
@@ -56,6 +74,41 @@ func MakeSSHKeyPair() (string, string, error) {
5674
return pubKeyBuf.String(), privKeyBuf.String(), nil
5775
}
5876

77+
func getHostKey() (string, error) {
78+
keyLock.Lock()
79+
defer keyLock.Unlock()
80+
81+
_, err := os.Stat(DevSpaceSSHFolder)
82+
if err != nil {
83+
err = os.MkdirAll(DevSpaceSSHFolder, 0755)
84+
if err != nil {
85+
return "", err
86+
}
87+
}
88+
89+
// check if key pair exists
90+
_, err = os.Stat(DevSpaceSSHHostKeyFile)
91+
if err != nil {
92+
privateKey, err := MakeHostKey()
93+
if err != nil {
94+
return "", errors.Wrap(err, "generate host key")
95+
}
96+
97+
err = ioutil.WriteFile(DevSpaceSSHHostKeyFile, []byte(privateKey), 0600)
98+
if err != nil {
99+
return "", errors.Wrap(err, "write host key")
100+
}
101+
}
102+
103+
// read public key
104+
out, err := ioutil.ReadFile(DevSpaceSSHHostKeyFile)
105+
if err != nil {
106+
return "", errors.Wrap(err, "read host ssh key")
107+
}
108+
109+
return base64.StdEncoding.EncodeToString(out), nil
110+
}
111+
59112
func getPublicKey() (string, error) {
60113
keyLock.Lock()
61114
defer keyLock.Unlock()

pkg/devspace/services/ssh/ssh.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,14 +160,20 @@ func startSSHWithRestart(ctx *devspacecontext.Context, arch, addr, sshHost strin
160160
return err
161161
}
162162

163+
// get host key
164+
hostKey, err := getHostKey()
165+
if err != nil {
166+
return errors.Wrap(err, "generate host key")
167+
}
168+
163169
// get public key
164170
publicKey, err := getPublicKey()
165171
if err != nil {
166172
return errors.Wrap(err, "generate key pair")
167173
}
168174

169175
// get command
170-
command := []string{inject.DevSpaceHelperContainerPath, "ssh", "--authorized-key", publicKey}
176+
command := []string{inject.DevSpaceHelperContainerPath, "ssh", "--authorized-key", publicKey, "--host-key", hostKey}
171177
if addr != "" {
172178
command = append(command, "--address", addr)
173179
}

0 commit comments

Comments
 (0)