Add PoC of connectivity using session-manager-plugin

* Add a bunch of hard coded values for testing on port 8081; ssh configs
are set to localhost and 8081
* Add a base drive for communicating with the session manager plugin
* Update step for creating tunnel to actually create SSM session tunnel via driver
This commit is contained in:
Wilken Rivera 2020-03-12 22:26:38 -04:00
parent 16604373ac
commit 3dd46eb5f4
3 changed files with 126 additions and 3 deletions

View File

@ -0,0 +1,50 @@
package common
import (
"bytes"
"fmt"
"log"
"os/exec"
"sync"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
)
type SSMDriver struct {
Ui packer.Ui
Ctx *interpolate.Context
l sync.Mutex
}
// sessJson, region, "StartSession", profile, paramJson, endpoint
func (s *SSMDriver) StartSession(sessionData, region, profile, params, endpoint string) error {
var stdout bytes.Buffer
var stderr bytes.Buffer
args := []string{
sessionData,
region,
"StartSession",
profile,
params,
endpoint,
}
// Remove log statement
log.Printf("Attempting to start session with the following args: %v", args)
cmd := exec.Command("session-manager-plugin", args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Start(); err != nil {
err = fmt.Errorf("Error committing container: %s\nStderr: %s", err, stderr.String())
s.Ui.Error(err.Error())
return err
}
log.Println(stdout.String())
log.Println(stderr.String())
return nil
}

View File

@ -2,11 +2,17 @@ package common
import (
"context"
"encoding/json"
"fmt"
"net"
"strconv"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/hashicorp/packer/common/retry"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
@ -20,31 +26,91 @@ type StepCreateSSMTunnel struct {
SrcPort string
ssmSession *ssm.StartSessionOutput
tunnel net.Listener
}
func (s *StepCreateSSMTunnel) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ui := state.Get("ui").(packer.Ui)
/*
p, _ := strconv.Atoi(s.SrcPort)
//TODO dynamically setup local port
// Find an available TCP port for our HTTP server
l, err := packernet.ListenRangeConfig{
Min: p,
Max: p,
Addr: "0.0.0.0",
Network: "tcp",
}.Listen(ctx)
if err != nil {
err := fmt.Errorf("Error finding port: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
*/
params := map[string][]*string{
"portNumber": []*string{aws.String(s.DstPort)},
"localPortNumber": []*string{aws.String(s.SrcPort)},
"localPortNumber": []*string{aws.String(strconv.Itoa(8081))},
}
instance, ok := state.Get("instance").(*ec2.Instance)
if !ok {
err := fmt.Errorf("error encountered in obtaining target instance id for SSM tunnel")
ui.Error(err.Error())
state.Put("error", err)
return multistep.ActionHalt
}
s.InstanceID = aws.StringValue(instance.InstanceId)
ssmconn := ssm.New(s.AWSSession)
input := ssm.StartSessionInput{
DocumentName: aws.String("AWS-StartPortForwardingSession"),
Parameters: params,
Target: aws.String(s.InstanceID),
}
var output *ssm.StartSessionOutput
var err error
err = retry.Config{
Tries: 11,
ShouldRetry: func(err error) bool { return isAWSErr(err, "TargetNotConnected", "") },
RetryDelay: (&retry.Backoff{InitialBackoff: 200 * time.Millisecond, MaxBackoff: 30 * time.Second, Multiplier: 2}).Linear,
}.Run(ctx, func(ctx context.Context) error {
output, err = ssmconn.StartSessionWithContext(ctx, &input)
return err
})
output, err := ssmconn.StartSession(&input)
if err != nil {
err = fmt.Errorf("error encountered in creating a connection to the SSM agent: %s", err)
err = fmt.Errorf("error encountered in starting session: %s", err)
ui.Error(err.Error())
state.Put("error", err)
return multistep.ActionHalt
}
s.ssmSession = output
sessJson, err := json.Marshal(s.ssmSession)
if err != nil {
ui.Error(err.Error())
state.Put("error", err)
return multistep.ActionHalt
}
paramsJson, err := json.Marshal(input)
if err != nil {
ui.Error(err.Error())
state.Put("error", err)
return multistep.ActionHalt
}
driver := SSMDriver{Ui: ui}
// sessJson, region, "StartSession", profile, paramJson, endpoint
if err := driver.StartSession(string(sessJson), "us-east-1", "packer", string(paramsJson), ssmconn.Endpoint); err != nil {
err = fmt.Errorf("error encountered in creating a connection to the SSM agent: %s", err)
ui.Error(err.Error())
state.Put("error", err)
return multistep.ActionHalt
}
return multistep.ActionContinue
}
@ -61,4 +127,5 @@ func (s *StepCreateSSMTunnel) Cleanup(state multistep.StateBag) {
aws.StringValue(s.ssmSession.SessionId), err)
ui.Error(msg)
}
}

View File

@ -11,6 +11,7 @@ package ebs
import (
"context"
"fmt"
"strconv"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/iam"
@ -255,6 +256,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
Timeout: b.config.WindowsPasswordTimeout,
BuildName: b.config.PackerBuildName,
},
&awscommon.StepCreateSSMTunnel{
AWSSession: session,
DstPort: strconv.Itoa(22),
SrcPort: "8081",
},
&communicator.StepConnect{
Config: &b.config.RunConfig.Comm,
Host: awscommon.SSHHost(