Skip to content

Commit

Permalink
added tunnel stdout to provider
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewChubatiuk committed Dec 23, 2021
1 parent a8fdf66 commit 47dc0fc
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 97 deletions.
47 changes: 0 additions & 47 deletions Makefile

This file was deleted.

50 changes: 10 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,22 @@
### terraform-provider-ssh

This provider enables SSH port forwarding in Terraform. It is intended as a
This experimental provider enables SSH port forwarding in Terraform. It is intended as a
bandaid [until it is supported in Terraform itself](https://github.com/hashicorp/terraform/issues/8367).

**Note: Terraform v0.12 support is highly experimental!**

#### Example

See [main.tf](main.tf).
See [example/main.tf](main.tf).

#### Installation

On Linux:

```shell
mkdir -p terraform.d/plugins/linux_amd64
wget https://github.com/stefansundin/terraform-provider-ssh/releases/download/v0.0.4/terraform-provider-ssh_v0.0.4_linux_amd64.zip
unzip terraform-provider-ssh_v0.0.4_linux_amd64.zip -d terraform.d/plugins/linux_amd64
rm terraform-provider-ssh_v0.0.4_linux_amd64.zip
terraform init
```

On Mac:

```shell
mkdir -p terraform.d/plugins/darwin_amd64
wget https://github.com/stefansundin/terraform-provider-ssh/releases/download/v0.0.4/terraform-provider-ssh_v0.0.4_darwin_amd64.zip
unzip terraform-provider-ssh_v0.0.4_darwin_amd64.zip -d terraform.d/plugins/darwin_amd64
rm terraform-provider-ssh_v0.0.4_darwin_amd64.zip
terraform init
```

#### Applying an output file

Note that there is a gotcha when trying to apply a generated plan output file (see [issue #1](https://github.com/stefansundin/terraform-provider-ssh/issues/1)). In this case, the SSH tunnels will not be automatically opened.

As a workaround, before you apply, run the companion program `terraform-open-ssh-tunnels` on the plan file first in order to reopen the SSH tunnels. [Download from the releases.](https://github.com/stefansundin/terraform-provider-ssh/releases/latest)

Because of [this commit](https://github.com/stefansundin/terraform-provider-ssh/commit/37fa9835b75fde095c863fca89e2f28a0169919d), only the SSH agent is currently supported in this program. Let me know if you can think of a good fix for this.

#### TODO

- Support another hop (ProxyJump-like behavior)
- Note that the Windows binary is completely untested!

#### Building
Provider can be automatically installed using Terraform >= 0.13 by providing a `terraform` configuration block:

```
$ go get -u github.com/golang/protobuf/protoc-gen-go
$ make
terraform {
required_providers {
ssh = {
source = "AndrewChubatiuk/ssh"
}
}
}
```
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ func main() {
var proto string
var err error

log.SetFlags(0)

flag.IntVar(&ppid, "ppid", 0, "parent process pid")
flag.StringVar(&addr, "addr", os.Getenv("TF_SSH_PROVIDER_TUNNEL_ADDR"), "set rpc server address")
flag.StringVar(&proto, "proto", os.Getenv("TF_SSH_PROVIDER_TUNNEL_PROTO"), "set rpc server protocol")
Expand Down
19 changes: 15 additions & 4 deletions provider/data_source_ssh_tunnel.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package provider

import (
"bufio"
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
Expand Down Expand Up @@ -303,8 +304,18 @@ func dataSourceSSHTunnelRead(ctx context.Context, d *schema.ResourceData, m inte
return diag.FromErr(err)
}

go io.Copy(os.Stdout, stdout)
go io.Copy(os.Stderr, stderr)
redirectStd := func(std io.ReadCloser) {
in := bufio.NewScanner(std)
for in.Scan() {
log.Printf(in.Text())
}
if err := in.Err(); err != nil {
log.Printf("[ERROR] %s", err)
}
}

go redirectStd(stdout)
go redirectStd(stderr)

var commandError error
timer := time.NewTimer(30 * time.Second)
Expand All @@ -322,7 +333,7 @@ func dataSourceSSHTunnelRead(ctx context.Context, d *schema.ResourceData, m inte
}()

for !tunnelServer.Ready {
log.Printf("[DEBUG] waiting for local port availability")
log.Printf("[DEBUG] Waiting for local port availability")
if commandError != nil {
return diag.FromErr(commandError)
}
Expand All @@ -331,7 +342,7 @@ func dataSourceSSHTunnelRead(ctx context.Context, d *schema.ResourceData, m inte

tunnelServerInbound.Close()

log.Printf("[DEBUG] local port: %v", sshTunnel.Local.Port)
log.Printf("[DEBUG] Local port: %v", sshTunnel.Local.Port)
d.Set("local", flattenEndpoint(sshTunnel.Local))
d.SetId(sshTunnel.Local.Address())

Expand Down
12 changes: 6 additions & 6 deletions ssh/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,25 +88,25 @@ func (pk SSHPrivateKey) Enabled() bool {
func (pk SSHPrivateKey) Authenticate() (methods []ssh.AuthMethod, err error) {
var signer ssh.Signer
if pk.Password != "" {
log.Println("[DEBUG] using private key with password for authentication")
log.Println("[DEBUG] Using private key with password for authentication")
signer, err = ssh.ParsePrivateKeyWithPassphrase([]byte(pk.PrivateKey), []byte(pk.Password))
} else {
log.Println("[DEBUG] using private key without password for authentication")
log.Println("[DEBUG] Using private key without password for authentication")
signer, err = ssh.ParsePrivateKey([]byte(pk.PrivateKey))
}
if err != nil {
return nil, fmt.Errorf("Failed to parse private key:\n%v", err)
}
methods = append(methods, ssh.PublicKeys(signer))
if pk.Certificate != "" {
log.Println("[DEBUG] using client certificate for authentication")
log.Println("[DEBUG] Using client certificate for authentication")
pcert, _, _, _, err := ssh.ParseAuthorizedKey([]byte(pk.Certificate))
if err != nil {
return nil, fmt.Errorf("failed to parse certificate %q: %s", pk.Certificate, err)
return nil, fmt.Errorf("Failed to parse certificate %q: %s", pk.Certificate, err)
}
certSigner, err := ssh.NewCertSigner(pcert.(*ssh.Certificate), signer)
if err != nil {
return nil, fmt.Errorf("failed to create cert signer %q: %s", certSigner, err)
return nil, fmt.Errorf("Failed to create cert signer %q: %s", certSigner, err)
}
methods = append(methods, ssh.PublicKeys(certSigner))
}
Expand Down Expand Up @@ -134,7 +134,7 @@ func (st *SSHTunnel) Run(proto, serverAddress string, ppid int) error {
gob.Register(SSHPassword{})
client, err := rpc.Dial("tcp", serverAddress)
if err != nil {
log.Fatal("[ERROR] failed to connect to RPC server:\n", err)
log.Fatal("[ERROR] Failed to connect to RPC server:\n", err)
}

defer client.Close()
Expand Down

0 comments on commit 47dc0fc

Please sign in to comment.