Skip to content

Commit

Permalink
Register SSH pub key during tunnel creation
Browse files Browse the repository at this point in the history
  • Loading branch information
iximiuz committed Mar 4, 2024
1 parent 507d796 commit 7f2541d
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 40 deletions.
5 changes: 3 additions & 2 deletions cmd/portforward/portforward.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ func runPortForward(ctx context.Context, cli labcli.CLI, opts *options) error {
}

tunnel, err := portforward.StartTunnel(ctx, cli.Client(), portforward.TunnelOptions{
PlayID: opts.playID,
Machine: opts.machine,
PlayID: opts.playID,
Machine: opts.machine,
SSHDirPath: cli.Config().SSHDirPath,
})
if err != nil {
return fmt.Errorf("couldn't start tunnel: %w", err)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/docker/cli v25.0.3+incompatible
github.com/google/uuid v1.6.0
github.com/iximiuz/wsmux v0.0.2
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a
github.com/moby/term v0.5.0
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/spf13/cobra v1.8.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a h1:eU8j/ClY2Ty3qdHnn0TyW3ivFoPC/0F1gQZz8yTxbbE=
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a/go.mod h1:v8eSC2SMp9/7FTKUncp7fH9IwPfw+ysMObcEz5FWheQ=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down
1 change: 1 addition & 0 deletions internal/api/plays.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type StartTunnelRequest struct {
Port int `json:"port"`
Access PortAccess `json:"access"`
GenerateLoginURL bool `json:"generateLoginUrl"`
SSHPubKey string `json:"sshPubKey"`
}

type StartTunnelResponse struct {
Expand Down
18 changes: 16 additions & 2 deletions internal/portforward/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ import (
"github.com/iximiuz/wsmux/pkg/client"

"github.com/iximiuz/labctl/internal/api"
"github.com/iximiuz/labctl/internal/ssh"
)

const (
conductorSessionCookieName = ".ixcondsess"
)

type TunnelOptions struct {
PlayID string
Machine string
PlayID string
Machine string
SSHDirPath string
}

type Tunnel struct {
Expand All @@ -27,8 +29,20 @@ type Tunnel struct {
}

func StartTunnel(ctx context.Context, client *api.Client, opts TunnelOptions) (*Tunnel, error) {
var (
sshPubKey string
err error
)
if opts.SSHDirPath != "" {
sshPubKey, err = ssh.ReadPublicKey(opts.SSHDirPath)
if err != nil {
return nil, fmt.Errorf("ssh.ReadPublicKey(): %w", err)
}
}

resp, err := client.StartTunnel(ctx, opts.PlayID, api.StartTunnelRequest{
Machine: opts.Machine,
SSHPubKey: sshPubKey,
Access: api.PortAccessPrivate,
GenerateLoginURL: true,
})
Expand Down
57 changes: 21 additions & 36 deletions internal/ssh/ssh.go → internal/ssh/ident.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,23 @@
package ssh

// Based on https://gist.github.com/devinodaniel/8f9b8a4f31573f428f29ec0e884e6673

import (
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"os"
"path/filepath"

"github.com/mikesmitty/edkey"
"golang.org/x/crypto/ssh"
)

const (
identityFile = "id_rsa"

bitSize = 4096
identityFile = "id_ed25519"
)

func GenerateIdentity(dirpath string) error {
privateKey, err := generatePrivateKey(bitSize)
if err != nil {
return fmt.Errorf("generate SSH private key: %w", err)
}

publicKey, err := generatePublicKey(&privateKey.PublicKey)
publicKey, privateKey, err := generateKeys()
if err != nil {
return err
}
Expand All @@ -40,7 +31,7 @@ func GenerateIdentity(dirpath string) error {

if err := os.WriteFile(
filepath.Join(dirpath, identityFile),
encodePrivateKeyToPEM(privateKey),
privateKey,
0600,
); err != nil {
return fmt.Errorf("write SSH private key to file: %w", err)
Expand Down Expand Up @@ -69,36 +60,30 @@ func RemoveIdentity(dirpath string) error {
return nil
}

func generatePrivateKey(bitSize int) (*rsa.PrivateKey, error) {
key, err := rsa.GenerateKey(rand.Reader, bitSize)
func ReadPublicKey(dirpath string) (string, error) {
publicKey, err := os.ReadFile(filepath.Join(dirpath, identityFile+".pub"))
if err != nil {
return nil, fmt.Errorf("generate SSH private key: %w", err)
}

if err = key.Validate(); err != nil {
return nil, fmt.Errorf("validate SSH private key: %w", err)
return "", fmt.Errorf("read SSH public key: %w", err)
}

return key, nil
return string(publicKey), nil
}

func encodePrivateKeyToPEM(privateKey *rsa.PrivateKey) []byte {
privDER := x509.MarshalPKCS1PrivateKey(privateKey)

privBlock := pem.Block{
Type: "RSA PRIVATE KEY",
Headers: nil,
Bytes: privDER,
func generateKeys() ([]byte, []byte, error) {
pubKey, privKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, nil, fmt.Errorf("generate ed25519 keys: %w", err)
}

return pem.EncodeToMemory(&privBlock)
}

func generatePublicKey(privatekey *rsa.PublicKey) ([]byte, error) {
key, err := ssh.NewPublicKey(privatekey)
publicKey, err := ssh.NewPublicKey(pubKey)
if err != nil {
return nil, fmt.Errorf("generate SSH public key: %w", err)
return nil, nil, fmt.Errorf("create SSH public key: %w", err)
}

pemKey := &pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: edkey.MarshalED25519PrivateKey(privKey),
}

return ssh.MarshalAuthorizedKey(key), nil
return ssh.MarshalAuthorizedKey(publicKey), pem.EncodeToMemory(pemKey), nil
}

0 comments on commit 7f2541d

Please sign in to comment.