2020-03-12 22:26:38 -04:00
|
|
|
package common
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2020-04-24 09:05:13 -04:00
|
|
|
"context"
|
2020-04-29 14:58:36 -04:00
|
|
|
"encoding/json"
|
2020-03-12 22:26:38 -04:00
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"os/exec"
|
|
|
|
|
2020-04-29 14:58:36 -04:00
|
|
|
"github.com/aws/aws-sdk-go/service/ssm"
|
2020-03-12 22:26:38 -04:00
|
|
|
)
|
|
|
|
|
2020-04-29 14:58:36 -04:00
|
|
|
const sessionManagerPluginName string = "session-manager-plugin"
|
|
|
|
|
|
|
|
//sessionCommand is the AWS-SDK equivalent to the command you would specify to `aws ssm ...`
|
|
|
|
const sessionCommand string = "StartSession"
|
2020-03-12 22:26:38 -04:00
|
|
|
|
2020-04-22 07:52:47 -04:00
|
|
|
type SSMDriver struct {
|
2020-04-29 14:58:36 -04:00
|
|
|
Region string
|
|
|
|
ProfileName string
|
|
|
|
Session *ssm.StartSessionOutput
|
|
|
|
SessionParams ssm.StartSessionInput
|
|
|
|
SessionEndpoint string
|
|
|
|
// Provided for testing purposes; if not specified it defaults to sessionManagerPluginName
|
2020-04-22 07:52:47 -04:00
|
|
|
PluginName string
|
2020-03-12 22:26:38 -04:00
|
|
|
}
|
|
|
|
|
2020-04-22 07:52:47 -04:00
|
|
|
// StartSession starts an interactive Systems Manager session with a remote instance via the AWS session-manager-plugin
|
2020-04-29 14:58:36 -04:00
|
|
|
func (sd *SSMDriver) StartSession(ctx context.Context) error {
|
2020-03-12 22:26:38 -04:00
|
|
|
var stdout bytes.Buffer
|
|
|
|
var stderr bytes.Buffer
|
|
|
|
|
2020-04-29 14:58:36 -04:00
|
|
|
if sd.PluginName == "" {
|
|
|
|
sd.PluginName = sessionManagerPluginName
|
2020-04-22 07:52:47 -04:00
|
|
|
}
|
|
|
|
|
2020-04-29 14:58:36 -04:00
|
|
|
args, err := sd.Args()
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("error encountered validating session details: %s", err)
|
2020-04-22 07:52:47 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-04-29 14:58:36 -04:00
|
|
|
cmd := exec.CommandContext(ctx, sd.PluginName, args...)
|
2020-03-12 22:26:38 -04:00
|
|
|
cmd.Stdout = &stdout
|
|
|
|
cmd.Stderr = &stderr
|
|
|
|
|
|
|
|
if err := cmd.Start(); err != nil {
|
2020-04-29 14:58:36 -04:00
|
|
|
err = fmt.Errorf("error encountered when calling %s: %s\nStderr: %s", sd.PluginName, err, stderr.String())
|
2020-03-12 22:26:38 -04:00
|
|
|
return err
|
|
|
|
}
|
2020-04-22 07:52:47 -04:00
|
|
|
// TODO capture logging for testing
|
2020-03-12 22:26:38 -04:00
|
|
|
log.Println(stdout.String())
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-04-29 14:58:36 -04:00
|
|
|
func (sd *SSMDriver) Args() ([]string, error) {
|
|
|
|
if sd.Session == nil {
|
|
|
|
return nil, fmt.Errorf("an active Amazon SSM Session is required before trying to open a session tunnel")
|
|
|
|
}
|
|
|
|
|
|
|
|
// AWS session-manager-plugin requires a valid session be passed in JSON.
|
|
|
|
sessionDetails, err := json.Marshal(sd.Session)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error encountered in reading session details %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AWS session-manager-plugin requires the parameters used in the session to be passed in JSON as well.
|
|
|
|
sessionParameters, err := json.Marshal(sd.SessionParams)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error encountered in reading session parameter details %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
args := []string{
|
|
|
|
string(sessionDetails),
|
|
|
|
sd.Region,
|
|
|
|
sessionCommand,
|
|
|
|
sd.ProfileName,
|
|
|
|
string(sessionParameters),
|
|
|
|
sd.SessionEndpoint,
|
|
|
|
}
|
|
|
|
|
|
|
|
return args, nil
|
|
|
|
}
|