From 1a2bfd94ab41edbdbeb3cd4f9584ae055bc0be54 Mon Sep 17 00:00:00 2001 From: David V Date: Sun, 31 Mar 2019 21:00:38 -0400 Subject: [PATCH 01/11] don't default to adding ssh key to local agent --- get_cert.go | 5 +++-- util/config.go | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/get_cert.go b/get_cert.go index 3a51cac..2bbd2d5 100644 --- a/get_cert.go +++ b/get_cert.go @@ -32,9 +32,10 @@ func getCertFlags() []cli.Flag { Value: configPath, Usage: "Path to config.json", }, - cli.BoolTFlag{ + cli.BoolFlag{ Name: "add-key", Usage: "When set automatically call ssh-add", + Value: false, }, cli.StringFlag{ Name: "ssh-dir", @@ -65,7 +66,7 @@ func getCert(c *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Sprintf("%s", err), 1) } - if c.BoolT("add-key") { + if c.Bool("add-key") { err = addCertToAgent(cert, sshDir) if err != nil { return cli.NewExitError(fmt.Sprintf("%s", err), 1) diff --git a/util/config.go b/util/config.go index 46da76a..2b78cc4 100644 --- a/util/config.go +++ b/util/config.go @@ -10,6 +10,7 @@ type RequesterConfig struct { PublicKeyPath string `json:",omitempty"` PublicKeyFingerprint string `json:",omitempty"` SignerUrl string + DefaultAddKey bool } type SignerdConfig struct { From 3393faab213687c88a758ef75c85efb1f7c6fa55 Mon Sep 17 00:00:00 2001 From: David V Date: Sun, 31 Mar 2019 21:04:58 -0400 Subject: [PATCH 02/11] misc work --- get_cert.go | 1 - 1 file changed, 1 deletion(-) diff --git a/get_cert.go b/get_cert.go index 2bbd2d5..3887730 100644 --- a/get_cert.go +++ b/get_cert.go @@ -35,7 +35,6 @@ func getCertFlags() []cli.Flag { cli.BoolFlag{ Name: "add-key", Usage: "When set automatically call ssh-add", - Value: false, }, cli.StringFlag{ Name: "ssh-dir", From f49f7acb3f269995696df6a323cde042548bd86d Mon Sep 17 00:00:00 2001 From: David V Date: Sun, 31 Mar 2019 21:22:08 -0400 Subject: [PATCH 03/11] misc work --- util/config.go | 1 - 1 file changed, 1 deletion(-) diff --git a/util/config.go b/util/config.go index 2b78cc4..46da76a 100644 --- a/util/config.go +++ b/util/config.go @@ -10,7 +10,6 @@ type RequesterConfig struct { PublicKeyPath string `json:",omitempty"` PublicKeyFingerprint string `json:",omitempty"` SignerUrl string - DefaultAddKey bool } type SignerdConfig struct { From ca5d378667a03610df305ec45b58f03216257213 Mon Sep 17 00:00:00 2001 From: David V Date: Sun, 31 Mar 2019 21:30:04 -0400 Subject: [PATCH 04/11] misc work --- get_cert.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/get_cert.go b/get_cert.go index 3887730..3dac833 100644 --- a/get_cert.go +++ b/get_cert.go @@ -65,7 +65,7 @@ func getCert(c *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Sprintf("%s", err), 1) } - if c.Bool("add-key") { + if c.BoolF("add-key") { err = addCertToAgent(cert, sshDir) if err != nil { return cli.NewExitError(fmt.Sprintf("%s", err), 1) From 9c12f0afa3e7bf5d4ebf01885ab73199eb768476 Mon Sep 17 00:00:00 2001 From: David V Date: Sun, 31 Mar 2019 21:55:51 -0400 Subject: [PATCH 05/11] this is working well enough, not throwing errors by default --- get_cert.go | 2 +- request_cert.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/get_cert.go b/get_cert.go index 3dac833..3887730 100644 --- a/get_cert.go +++ b/get_cert.go @@ -65,7 +65,7 @@ func getCert(c *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Sprintf("%s", err), 1) } - if c.BoolF("add-key") { + if c.Bool("add-key") { err = addCertToAgent(cert, sshDir) if err != nil { return cli.NewExitError(fmt.Sprintf("%s", err), 1) diff --git a/request_cert.go b/request_cert.go index dac0852..ca7043f 100644 --- a/request_cert.go +++ b/request_cert.go @@ -67,7 +67,7 @@ func requestCertFlags() []cli.Flag { Name: "quiet", Usage: "Print only the request id on success", }, - cli.BoolTFlag{ + cli.BoolFlag{ Name: "add-key", Usage: "When set automatically call ssh-add if cert was auto-signed by server", }, @@ -176,7 +176,7 @@ func requestCert(c *cli.Context) error { appendage = " auto-signed" } fmt.Printf("Cert request id: %s%s\n", requestID, appendage) - if signed && c.BoolT("add-key") { + if signed && c.Bool("add-key") { cert, err := downloadCert(config, requestID, sshDir) if err != nil { return cli.NewExitError(fmt.Sprintf("%s", err), 1) From 20ad7b72d25bd9ccb789bb67403a4fcc58c9fade Mon Sep 17 00:00:00 2001 From: David V Date: Sun, 31 Mar 2019 22:03:05 -0400 Subject: [PATCH 06/11] this is working well enough, not throwing errors by default --- get_cert.go | 1 + 1 file changed, 1 insertion(+) diff --git a/get_cert.go b/get_cert.go index 3887730..bba0594 100644 --- a/get_cert.go +++ b/get_cert.go @@ -119,6 +119,7 @@ func downloadCert(config ssh_ca_util.RequesterConfig, certRequestID string, sshD return nil, err } pubKeyPath = strings.Replace(pubKeyPath, ".pub", "-cert.pub", 1) + fmt.Printf("%s\n", getRespBuf) err = ioutil.WriteFile(pubKeyPath, getRespBuf, 0644) if err != nil { fmt.Printf("Couldn't write certificate file to %s: %s\n", pubKeyPath, err) From b7ef17520d80f53ad9630d4dcad248188de5b928 Mon Sep 17 00:00:00 2001 From: David V Date: Wed, 3 Apr 2019 22:00:04 -0400 Subject: [PATCH 07/11] working first pass at using an ssh tunnel to CA server. still need to make the tunnel configurable --- get_cert.go | 41 +++++++++++++++++ request_cert.go | 40 ++++++++++++++++ util/sshtunnel.go | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 util/sshtunnel.go diff --git a/get_cert.go b/get_cert.go index bba0594..41dea50 100644 --- a/get_cert.go +++ b/get_cert.go @@ -12,6 +12,7 @@ import ( "os/exec" "strings" "time" + "net" ) func getCertFlags() []cli.Flag { @@ -94,6 +95,46 @@ func addCertToAgent(cert *ssh.Certificate, sshDir string) error { } func downloadCert(config ssh_ca_util.RequesterConfig, certRequestID string, sshDir string) (*ssh.Certificate, error) { + // new stuff to try and set up ssh tunnel + fmt.Printf("starting tunnel config...\n") + localEndpoint := &ssh_ca_util.Endpoint{ + Host: "localhost", + Port: 8080, + } + + serverEndpoint := &ssh_ca_util.Endpoint{ + Host: "bsdtest.potatohead.ca", + Port: 22, + } + + remoteEndpoint := &ssh_ca_util.Endpoint{ + Host: "localhost", + Port: 8080, + } + + sshConfig := &ssh.ClientConfig{ + User: "david", + Auth: []ssh.AuthMethod{ + ssh_ca_util.SSHAgent(), + }, + // TODO: fix this to actually check the trusted hosts + HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { + return nil + }, + } + + tunnel := &ssh_ca_util.SSHtunnel{ + Config: sshConfig, + Local: localEndpoint, + Server: serverEndpoint, + Remote: remoteEndpoint, + } + + fmt.Printf("starting tunnel...\n") + go tunnel.Start() + + fmt.Printf("doing normal stuff...\n") + // end new stuff getResp, err := http.Get(config.SignerUrl + "cert/requests/" + certRequestID) if err != nil { return nil, fmt.Errorf("Didn't get a valid response: %s", err) diff --git a/request_cert.go b/request_cert.go index ca7043f..81a86c2 100644 --- a/request_cert.go +++ b/request_cert.go @@ -80,6 +80,46 @@ func requestCertFlags() []cli.Flag { } func requestCert(c *cli.Context) error { + // new stuff to try and set up ssh tunnel + fmt.Printf("starting tunnel config...\n") + localEndpoint := &ssh_ca_util.Endpoint{ + Host: "localhost", + Port: 8080, + } + + serverEndpoint := &ssh_ca_util.Endpoint{ + Host: "bsdtest.potatohead.ca", + Port: 22, + } + + remoteEndpoint := &ssh_ca_util.Endpoint{ + Host: "localhost", + Port: 8080, + } + + sshConfig := &ssh.ClientConfig{ + User: "david", + Auth: []ssh.AuthMethod{ + ssh_ca_util.SSHAgent(), + }, + // TODO: fix this to actually check the trusted hosts + HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { + return nil + }, + } + + tunnel := &ssh_ca_util.SSHtunnel{ + Config: sshConfig, + Local: localEndpoint, + Server: serverEndpoint, + Remote: remoteEndpoint, + } + + fmt.Printf("starting tunnel...\n") + go tunnel.Start() + + fmt.Printf("doing normal stuff...\n") + // end new stuff allConfig := make(map[string]ssh_ca_util.RequesterConfig) configPath := c.String("config-file") sshDir := c.String("ssh-dir") diff --git a/util/sshtunnel.go b/util/sshtunnel.go new file mode 100644 index 0000000..bc2a5e5 --- /dev/null +++ b/util/sshtunnel.go @@ -0,0 +1,113 @@ +// copied from https://gist.github.com/svett/5d695dcc4cc6ad5dd275 + +package ssh_ca_util + +import ( +// "log" +// "bufio" +// "time" + "os" + "fmt" + "io" + "net" + + "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/agent" +) + +type Endpoint struct { + Host string + Port int +} + +func (endpoint *Endpoint) String() string { + return fmt.Sprintf("%s:%d", endpoint.Host, endpoint.Port) +} + +type SSHtunnel struct { + Local *Endpoint + Server *Endpoint + Remote *Endpoint + + Config *ssh.ClientConfig +} + +func (tunnel *SSHtunnel) Start() error { + listener, err := net.Listen("tcp", tunnel.Local.String()) + if err != nil { + return err + } + defer listener.Close() + + for { + conn, err := listener.Accept() + if err != nil { + return err + } + go tunnel.forward(conn) + } +} + +func (tunnel *SSHtunnel) forward(localConn net.Conn) { + serverConn, err := ssh.Dial("tcp", tunnel.Server.String(), tunnel.Config) + if err != nil { + fmt.Printf("Server dial error: %s\n", err) + return + } + + remoteConn, err := serverConn.Dial("tcp", tunnel.Remote.String()) + if err != nil { + fmt.Printf("Remote dial error: %s\n", err) + return + } + + copyConn:=func(writer, reader net.Conn) { + _, err:= io.Copy(writer, reader) + if err != nil { + fmt.Printf("io.Copy error: %s", err) + } + } + + go copyConn(localConn, remoteConn) + go copyConn(remoteConn, localConn) +} + +func SSHAgent() ssh.AuthMethod { + if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil { + return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers) + } + return nil +} + +//func main() { + //localEndpoint := &Endpoint{ + //Host: "localhost", + //Port: 9000, + //} + + //serverEndpoint := &Endpoint{ + //Host: "example.com", + //Port: 22, + //} + + //remoteEndpoint := &Endpoint{ + //Host: "localhost", + //Port: 8080, + //} + + //sshConfig := &ssh.ClientConfig{ + //User: "vcap", + //Auth: []ssh.AuthMethod{ + //SSHAgent(), + //}, + //} + + //tunnel := &SSHtunnel{ + //Config: sshConfig, + //Local: localEndpoint, + //Server: serverEndpoint, + //Remote: remoteEndpoint, + //} + + //tunnel.Start() +//} From e350b64c5d43d05e5e1362233ef4e1536fa0a023 Mon Sep 17 00:00:00 2001 From: David V Date: Sat, 6 Apr 2019 22:02:50 -0400 Subject: [PATCH 08/11] more work on making ssh tunnel work --- get_cert.go | 41 +--------------------- util/config.go | 1 + util/sshtunnel.go | 88 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 41 deletions(-) diff --git a/get_cert.go b/get_cert.go index 41dea50..0f69c60 100644 --- a/get_cert.go +++ b/get_cert.go @@ -12,7 +12,6 @@ import ( "os/exec" "strings" "time" - "net" ) func getCertFlags() []cli.Flag { @@ -95,46 +94,8 @@ func addCertToAgent(cert *ssh.Certificate, sshDir string) error { } func downloadCert(config ssh_ca_util.RequesterConfig, certRequestID string, sshDir string) (*ssh.Certificate, error) { - // new stuff to try and set up ssh tunnel - fmt.Printf("starting tunnel config...\n") - localEndpoint := &ssh_ca_util.Endpoint{ - Host: "localhost", - Port: 8080, - } - - serverEndpoint := &ssh_ca_util.Endpoint{ - Host: "bsdtest.potatohead.ca", - Port: 22, - } - - remoteEndpoint := &ssh_ca_util.Endpoint{ - Host: "localhost", - Port: 8080, - } - - sshConfig := &ssh.ClientConfig{ - User: "david", - Auth: []ssh.AuthMethod{ - ssh_ca_util.SSHAgent(), - }, - // TODO: fix this to actually check the trusted hosts - HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { - return nil - }, - } - - tunnel := &ssh_ca_util.SSHtunnel{ - Config: sshConfig, - Local: localEndpoint, - Server: serverEndpoint, - Remote: remoteEndpoint, - } - - fmt.Printf("starting tunnel...\n") - go tunnel.Start() + ssh_ca_util.StartTunnelIfNeeded(config) - fmt.Printf("doing normal stuff...\n") - // end new stuff getResp, err := http.Get(config.SignerUrl + "cert/requests/" + certRequestID) if err != nil { return nil, fmt.Errorf("Didn't get a valid response: %s", err) diff --git a/util/config.go b/util/config.go index 46da76a..aad3061 100644 --- a/util/config.go +++ b/util/config.go @@ -10,6 +10,7 @@ type RequesterConfig struct { PublicKeyPath string `json:",omitempty"` PublicKeyFingerprint string `json:",omitempty"` SignerUrl string + SshBastion string `json:",omitempty"` } type SignerdConfig struct { diff --git a/util/sshtunnel.go b/util/sshtunnel.go index bc2a5e5..eae9fe1 100644 --- a/util/sshtunnel.go +++ b/util/sshtunnel.go @@ -9,8 +9,10 @@ import ( "os" "fmt" "io" + "strings" + "strconv" "net" - + "net/url" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" ) @@ -79,6 +81,90 @@ func SSHAgent() ssh.AuthMethod { return nil } +func StartTunnelIfNeeded(config RequesterConfig) { + if len(config.SshBastion) > 0 { + + if !strings.HasPrefix(config.SshBastion, "ssh://") { + fmt.Printf("Bastion host must start with ssh://. Exiting\n") + os.Exit(1) + } + + bastion_parsed, err := url.Parse(config.SshBastion) + if err != nil { + fmt.Printf("url.Parse error for SshBastion: %s", err) + } + + // Check to see if it's a nonstardard port + host_parts := strings.Split(bastion_parsed.Host, ":") + var ssh_port int + ssh_port = 22 + if len(host_parts) == 2 { + var err error + ssh_port, err = strconv.Atoi(host_parts[1]) + if err != nil { + fmt.Printf("strconv.Atoi error: %s", err) + } + } + + // Get remote end information + remote_parsed, err := url.Parse(config.SignerUrl) + if err != nil { + fmt.Printf("url.Parse error on SignerUrl: %s", err) + } + remote_parts := strings.Split(remote_parsed.Host, ":") + if len(remote_parts) != 2 { + fmt.Printf("Missing port for SignerUrl. Exiting") + os.Exit(1) + } + remote_port, err := strconv.Atoi(remote_parts[1]) + if err != nil { + fmt.Printf("strconv.Atoi error: %s", err) + } + + fmt.Printf("config stuff: %s, %d\n", host_parts[0], ssh_port) + fmt.Printf("starting tunnel config...\n") + localEndpoint := &Endpoint{ + Host: "localhost", + Port: 8080, + } + + serverEndpoint := &Endpoint{ + Host: host_parts[0], + Port: ssh_port, + } + + remoteEndpoint := &Endpoint{ + Host: remote_parts[0], + Port: remote_port, + } + + sshConfig := &ssh.ClientConfig{ + User: bastion_parsed.User, + Auth: []ssh.AuthMethod{ + SSHAgent(), + }, + // TODO: fix this to actually check the trusted hosts + // https://utcc.utoronto.ca/~cks/space/blog/programming/GoSSHHostKeyCheckingNotes + HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { + return nil + }, + } + + tunnel := &SSHtunnel{ + Config: sshConfig, + Local: localEndpoint, + Server: serverEndpoint, + Remote: remoteEndpoint, + } + + fmt.Printf("starting tunnel...\n") + go tunnel.Start() + + fmt.Printf("doing normal stuff...\n") + // end new stuff + } +} + //func main() { //localEndpoint := &Endpoint{ //Host: "localhost", From 5694b056f2d87581b6f0f0b5911bae1764b22889 Mon Sep 17 00:00:00 2001 From: David V Date: Mon, 8 Apr 2019 21:54:32 -0400 Subject: [PATCH 09/11] all working with ssh tunnel, I think --- get_cert.go | 3 ++- request_cert.go | 42 ++------------------------------ util/sshtunnel.go | 61 ++++++++++++++++------------------------------- 3 files changed, 24 insertions(+), 82 deletions(-) diff --git a/get_cert.go b/get_cert.go index 0f69c60..f0e74ce 100644 --- a/get_cert.go +++ b/get_cert.go @@ -94,7 +94,8 @@ func addCertToAgent(cert *ssh.Certificate, sshDir string) error { } func downloadCert(config ssh_ca_util.RequesterConfig, certRequestID string, sshDir string) (*ssh.Certificate, error) { - ssh_ca_util.StartTunnelIfNeeded(config) + ssh_ca_util.StartTunnelIfNeeded(&config) + //fmt.Printf("get_cert downloadCert using signer url: %s", config.SignerUrl) getResp, err := http.Get(config.SignerUrl + "cert/requests/" + certRequestID) if err != nil { diff --git a/request_cert.go b/request_cert.go index 81a86c2..32d7ad1 100644 --- a/request_cert.go +++ b/request_cert.go @@ -80,46 +80,6 @@ func requestCertFlags() []cli.Flag { } func requestCert(c *cli.Context) error { - // new stuff to try and set up ssh tunnel - fmt.Printf("starting tunnel config...\n") - localEndpoint := &ssh_ca_util.Endpoint{ - Host: "localhost", - Port: 8080, - } - - serverEndpoint := &ssh_ca_util.Endpoint{ - Host: "bsdtest.potatohead.ca", - Port: 22, - } - - remoteEndpoint := &ssh_ca_util.Endpoint{ - Host: "localhost", - Port: 8080, - } - - sshConfig := &ssh.ClientConfig{ - User: "david", - Auth: []ssh.AuthMethod{ - ssh_ca_util.SSHAgent(), - }, - // TODO: fix this to actually check the trusted hosts - HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { - return nil - }, - } - - tunnel := &ssh_ca_util.SSHtunnel{ - Config: sshConfig, - Local: localEndpoint, - Server: serverEndpoint, - Remote: remoteEndpoint, - } - - fmt.Printf("starting tunnel...\n") - go tunnel.Start() - - fmt.Printf("doing normal stuff...\n") - // end new stuff allConfig := make(map[string]ssh_ca_util.RequesterConfig) configPath := c.String("config-file") sshDir := c.String("ssh-dir") @@ -134,6 +94,8 @@ func requestCert(c *cli.Context) error { return cli.NewExitError(fmt.Sprintf("%s", err), 1) } config := wrongTypeConfig.(ssh_ca_util.RequesterConfig) + + ssh_ca_util.StartTunnelIfNeeded(&config) reason := c.String("reason") if reason == "" { diff --git a/util/sshtunnel.go b/util/sshtunnel.go index eae9fe1..5f2dcae 100644 --- a/util/sshtunnel.go +++ b/util/sshtunnel.go @@ -34,11 +34,14 @@ type SSHtunnel struct { Config *ssh.ClientConfig } -func (tunnel *SSHtunnel) Start() error { +func (tunnel *SSHtunnel) Start(out_port chan int) error { listener, err := net.Listen("tcp", tunnel.Local.String()) if err != nil { return err } + //fmt.Println("Using local port:", listener.Addr().(*net.TCPAddr).Port) + //tunnel.LocalPort = listener.Addr().(*net.TCPAddr).Port + out_port <- listener.Addr().(*net.TCPAddr).Port defer listener.Close() for { @@ -81,7 +84,7 @@ func SSHAgent() ssh.AuthMethod { return nil } -func StartTunnelIfNeeded(config RequesterConfig) { +func StartTunnelIfNeeded(config *RequesterConfig) { if len(config.SshBastion) > 0 { if !strings.HasPrefix(config.SshBastion, "ssh://") { @@ -121,11 +124,11 @@ func StartTunnelIfNeeded(config RequesterConfig) { fmt.Printf("strconv.Atoi error: %s", err) } - fmt.Printf("config stuff: %s, %d\n", host_parts[0], ssh_port) - fmt.Printf("starting tunnel config...\n") + //fmt.Printf("config stuff: %s, %d\n", host_parts[0], ssh_port) + //fmt.Printf("starting tunnel config...\n") localEndpoint := &Endpoint{ Host: "localhost", - Port: 8080, + Port: 0, } serverEndpoint := &Endpoint{ @@ -139,7 +142,7 @@ func StartTunnelIfNeeded(config RequesterConfig) { } sshConfig := &ssh.ClientConfig{ - User: bastion_parsed.User, + User: bastion_parsed.User.Username(), Auth: []ssh.AuthMethod{ SSHAgent(), }, @@ -157,43 +160,19 @@ func StartTunnelIfNeeded(config RequesterConfig) { Remote: remoteEndpoint, } - fmt.Printf("starting tunnel...\n") - go tunnel.Start() + //fmt.Printf("starting tunnel...\n") - fmt.Printf("doing normal stuff...\n") + out_port_chan := make(chan int) + go tunnel.Start(out_port_chan) + var local_port int + local_port = <- out_port_chan + //fmt.Printf("Using local port: %d\n", local_port) + + //fmt.Printf("doing normal stuff...\n") + + config.SignerUrl = fmt.Sprintf("%s://localhost:%d/", remote_parsed.Scheme, local_port) + //fmt.Printf("sshtunnel using signer url: %s", config.SignerUrl) // end new stuff } } -//func main() { - //localEndpoint := &Endpoint{ - //Host: "localhost", - //Port: 9000, - //} - - //serverEndpoint := &Endpoint{ - //Host: "example.com", - //Port: 22, - //} - - //remoteEndpoint := &Endpoint{ - //Host: "localhost", - //Port: 8080, - //} - - //sshConfig := &ssh.ClientConfig{ - //User: "vcap", - //Auth: []ssh.AuthMethod{ - //SSHAgent(), - //}, - //} - - //tunnel := &SSHtunnel{ - //Config: sshConfig, - //Local: localEndpoint, - //Server: serverEndpoint, - //Remote: remoteEndpoint, - //} - - //tunnel.Start() -//} From 8b1de8d88f48a9f125fe3833c513d520f14105af Mon Sep 17 00:00:00 2001 From: David V Date: Tue, 9 Apr 2019 22:50:41 -0400 Subject: [PATCH 10/11] went down to a single config file --- client/client.go | 4 ++-- list_requests.go | 4 +++- sign_cert.go | 8 +++++--- util/config.go | 26 ++++---------------------- 4 files changed, 14 insertions(+), 28 deletions(-) diff --git a/client/client.go b/client/client.go index 391bea0..27c4f85 100644 --- a/client/client.go +++ b/client/client.go @@ -32,10 +32,10 @@ func MakeCertRequest() CertRequest { type SigningRequest struct { signedCert ssh.Certificate requestID string - config ssh_ca_util.SignerConfig + config ssh_ca_util.RequesterConfig } -func MakeSigningRequest(cert ssh.Certificate, requestID string, config ssh_ca_util.SignerConfig) SigningRequest { +func MakeSigningRequest(cert ssh.Certificate, requestID string, config ssh_ca_util.RequesterConfig) SigningRequest { var request SigningRequest request.signedCert = cert request.requestID = requestID diff --git a/list_requests.go b/list_requests.go index 5d6300d..590535d 100644 --- a/list_requests.go +++ b/list_requests.go @@ -18,7 +18,7 @@ func listCertFlags() []cli.Flag { if home == "" { home = "/" } - configPath := home + "/.ssh_ca/signer_config.json" + configPath := home + "/.ssh_ca/requester_config.json" return []cli.Flag{ cli.StringFlag{ @@ -51,6 +51,8 @@ func listCerts(c *cli.Context) error { return cli.NewExitError(fmt.Sprintf("%s", err), 1) } config := wrongTypeConfig.(ssh_ca_util.RequesterConfig) + + ssh_ca_util.StartTunnelIfNeeded(&config) getResp, err := http.Get(config.SignerUrl + "cert/requests") if err != nil { diff --git a/sign_cert.go b/sign_cert.go index e88887b..b9039c3 100644 --- a/sign_cert.go +++ b/sign_cert.go @@ -30,7 +30,7 @@ func signCertFlags() []cli.Flag { if home == "" { home = "/" } - configPath := home + "/.ssh_ca/signer_config.json" + configPath := home + "/.ssh_ca/requester_config.json" return []cli.Flag{ cli.StringFlag{ @@ -53,7 +53,7 @@ func signCertFlags() []cli.Flag { func signCert(c *cli.Context) error { configPath := c.String("config-file") - allConfig := make(map[string]ssh_ca_util.SignerConfig) + allConfig := make(map[string]ssh_ca_util.RequesterConfig) err := ssh_ca_util.LoadConfig(configPath, &allConfig) if err != nil { return cli.NewExitError(fmt.Sprintf("Load Config failed: %s", err), 1) @@ -71,7 +71,9 @@ func signCert(c *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Sprintf("%s", err), 1) } - config := wrongTypeConfig.(ssh_ca_util.SignerConfig) + config := wrongTypeConfig.(ssh_ca_util.RequesterConfig) + + ssh_ca_util.StartTunnelIfNeeded(&config) conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")) if err != nil { diff --git a/util/config.go b/util/config.go index aad3061..e2d119a 100644 --- a/util/config.go +++ b/util/config.go @@ -11,6 +11,7 @@ type RequesterConfig struct { PublicKeyFingerprint string `json:",omitempty"` SignerUrl string SshBastion string `json:",omitempty"` + KeyFingerprint string `json:",omitempty"` } type SignerdConfig struct { @@ -26,11 +27,6 @@ type SignerdConfig struct { CriticalOptions map[string]string } -type SignerConfig struct { - KeyFingerprint string - SignerUrl string -} - func LoadConfig(configPath string, environmentConfigs interface{}) error { buf, err := ioutil.ReadFile(configPath) if err != nil { @@ -38,7 +34,7 @@ func LoadConfig(configPath string, environmentConfigs interface{}) error { } switch configType := environmentConfigs.(type) { - case *map[string]RequesterConfig, *map[string]SignerConfig, *map[string]SignerdConfig: + case *map[string]RequesterConfig, *map[string]SignerdConfig: return json.Unmarshal(buf, &environmentConfigs) default: return fmt.Errorf("oops: %T\n", configType) @@ -57,24 +53,10 @@ func GetConfigForEnv(environment string, environmentConfigs interface{}) (interf // lame way of extracting first and only key from a map? } } + config, ok := configs[environment] if !ok { - return nil, fmt.Errorf("Requested environment not found in config file.") - } - return config, nil - case *map[string]SignerConfig: - configs := *environmentConfigs.(*map[string]SignerConfig) - if len(configs) > 1 && environment == "" { - return nil, fmt.Errorf("You must tell me which environment to use.") - } - if len(configs) == 1 && environment == "" { - for environment = range configs { - // lame way of extracting first and only key from a map? - } - } - config, ok := configs[environment] - if !ok { - return nil, fmt.Errorf("Requested environment not found in config file.") + return nil, fmt.Errorf("Requested environment not found in config file1.") } return config, nil } From 4597f496145853fadeb0854d383c6e2b05909298 Mon Sep 17 00:00:00 2001 From: David V Date: Thu, 11 Apr 2019 08:05:05 -0400 Subject: [PATCH 11/11] add option to not automatically download cert --- request_cert.go | 13 ++-- util/sshtunnel.go | 168 +++++++++++++++++++++++++--------------------- 2 files changed, 95 insertions(+), 86 deletions(-) diff --git a/request_cert.go b/request_cert.go index 32d7ad1..b781549 100644 --- a/request_cert.go +++ b/request_cert.go @@ -68,8 +68,8 @@ func requestCertFlags() []cli.Flag { Usage: "Print only the request id on success", }, cli.BoolFlag{ - Name: "add-key", - Usage: "When set automatically call ssh-add if cert was auto-signed by server", + Name: "no-get-key", + Usage: "When set don't automatically download the key", }, cli.StringFlag{ Name: "ssh-dir", @@ -178,15 +178,12 @@ func requestCert(c *cli.Context) error { appendage = " auto-signed" } fmt.Printf("Cert request id: %s%s\n", requestID, appendage) - if signed && c.Bool("add-key") { - cert, err := downloadCert(config, requestID, sshDir) - if err != nil { - return cli.NewExitError(fmt.Sprintf("%s", err), 1) - } - err = addCertToAgent(cert, sshDir) + if signed && !c.Bool("no-get-key") { + _, err := downloadCert(config, requestID, sshDir) if err != nil { return cli.NewExitError(fmt.Sprintf("%s", err), 1) } + // add cert to agent didn't seem to work and seemed unnecessary } } } else { diff --git a/util/sshtunnel.go b/util/sshtunnel.go index 5f2dcae..5ae6446 100644 --- a/util/sshtunnel.go +++ b/util/sshtunnel.go @@ -12,6 +12,7 @@ import ( "strings" "strconv" "net" + "sync" "net/url" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" @@ -84,95 +85,106 @@ func SSHAgent() ssh.AuthMethod { return nil } +var ( + jobIsRunning bool + JobIsrunningMu sync.Mutex +) + func StartTunnelIfNeeded(config *RequesterConfig) { if len(config.SshBastion) > 0 { - if !strings.HasPrefix(config.SshBastion, "ssh://") { - fmt.Printf("Bastion host must start with ssh://. Exiting\n") - os.Exit(1) - } - - bastion_parsed, err := url.Parse(config.SshBastion) - if err != nil { - fmt.Printf("url.Parse error for SshBastion: %s", err) - } - - // Check to see if it's a nonstardard port - host_parts := strings.Split(bastion_parsed.Host, ":") - var ssh_port int - ssh_port = 22 - if len(host_parts) == 2 { - var err error - ssh_port, err = strconv.Atoi(host_parts[1]) + JobIsrunningMu.Lock() + start := !jobIsRunning + jobIsRunning = true + JobIsrunningMu.Unlock() + if start { + if !strings.HasPrefix(config.SshBastion, "ssh://") { + fmt.Printf("Bastion host must start with ssh://. Exiting\n") + os.Exit(1) + } + + bastion_parsed, err := url.Parse(config.SshBastion) + if err != nil { + fmt.Printf("url.Parse error for SshBastion: %s", err) + } + + // Check to see if it's a nonstardard port + host_parts := strings.Split(bastion_parsed.Host, ":") + var ssh_port int + ssh_port = 22 + if len(host_parts) == 2 { + var err error + ssh_port, err = strconv.Atoi(host_parts[1]) + if err != nil { + fmt.Printf("strconv.Atoi error: %s", err) + } + } + + // Get remote end information + remote_parsed, err := url.Parse(config.SignerUrl) + if err != nil { + fmt.Printf("url.Parse error on SignerUrl: %s", err) + } + remote_parts := strings.Split(remote_parsed.Host, ":") + if len(remote_parts) != 2 { + fmt.Printf("Missing port for SignerUrl. Exiting") + os.Exit(1) + } + remote_port, err := strconv.Atoi(remote_parts[1]) if err != nil { fmt.Printf("strconv.Atoi error: %s", err) } - } - - // Get remote end information - remote_parsed, err := url.Parse(config.SignerUrl) - if err != nil { - fmt.Printf("url.Parse error on SignerUrl: %s", err) - } - remote_parts := strings.Split(remote_parsed.Host, ":") - if len(remote_parts) != 2 { - fmt.Printf("Missing port for SignerUrl. Exiting") - os.Exit(1) - } - remote_port, err := strconv.Atoi(remote_parts[1]) - if err != nil { - fmt.Printf("strconv.Atoi error: %s", err) - } - - //fmt.Printf("config stuff: %s, %d\n", host_parts[0], ssh_port) - //fmt.Printf("starting tunnel config...\n") - localEndpoint := &Endpoint{ - Host: "localhost", - Port: 0, - } + + //fmt.Printf("config stuff: %s, %d\n", host_parts[0], ssh_port) + //fmt.Printf("starting tunnel config...\n") + localEndpoint := &Endpoint{ + Host: "localhost", + Port: 0, + } - serverEndpoint := &Endpoint{ - Host: host_parts[0], - Port: ssh_port, - } + serverEndpoint := &Endpoint{ + Host: host_parts[0], + Port: ssh_port, + } - remoteEndpoint := &Endpoint{ - Host: remote_parts[0], - Port: remote_port, - } + remoteEndpoint := &Endpoint{ + Host: remote_parts[0], + Port: remote_port, + } - sshConfig := &ssh.ClientConfig{ - User: bastion_parsed.User.Username(), - Auth: []ssh.AuthMethod{ - SSHAgent(), - }, - // TODO: fix this to actually check the trusted hosts - // https://utcc.utoronto.ca/~cks/space/blog/programming/GoSSHHostKeyCheckingNotes - HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { - return nil - }, - } + sshConfig := &ssh.ClientConfig{ + User: bastion_parsed.User.Username(), + Auth: []ssh.AuthMethod{ + SSHAgent(), + }, + // TODO: fix this to actually check the trusted hosts + // https://utcc.utoronto.ca/~cks/space/blog/programming/GoSSHHostKeyCheckingNotes + HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { + return nil + }, + } - tunnel := &SSHtunnel{ - Config: sshConfig, - Local: localEndpoint, - Server: serverEndpoint, - Remote: remoteEndpoint, + tunnel := &SSHtunnel{ + Config: sshConfig, + Local: localEndpoint, + Server: serverEndpoint, + Remote: remoteEndpoint, + } + + //fmt.Printf("starting tunnel...\n") + + out_port_chan := make(chan int) + go tunnel.Start(out_port_chan) + var local_port int + local_port = <- out_port_chan + //fmt.Printf("Using local port: %d\n", local_port) + + //fmt.Printf("doing normal stuff...\n") + + config.SignerUrl = fmt.Sprintf("%s://localhost:%d/", remote_parsed.Scheme, local_port) + //fmt.Printf("sshtunnel using signer url: %s", config.SignerUrl) + // end new stuff } - - //fmt.Printf("starting tunnel...\n") - - out_port_chan := make(chan int) - go tunnel.Start(out_port_chan) - var local_port int - local_port = <- out_port_chan - //fmt.Printf("Using local port: %d\n", local_port) - - //fmt.Printf("doing normal stuff...\n") - - config.SignerUrl = fmt.Sprintf("%s://localhost:%d/", remote_parsed.Scheme, local_port) - //fmt.Printf("sshtunnel using signer url: %s", config.SignerUrl) - // end new stuff } }