* configuration file located at ~/.aws-oidc/config * sets default parameters, but can still be overridden on the cli * named AuthProviders are accessible via the auth [name] command Renamed exec command to auth. Upgraded auth command to take defaults from the config file. Added new command exec, that puts the temporary credentials as environment variables in the specified command Automatically append URL to end of auth command if not specified
141 lines
3.5 KiB
Go
141 lines
3.5 KiB
Go
package cli
|
|
|
|
import (
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"gopkg.in/alecthomas/kingpin.v2"
|
|
)
|
|
|
|
// ExecConfig stores the parameters needed for an exec command
|
|
type ExecConfig struct {
|
|
Profile string
|
|
Command string
|
|
Args []string
|
|
Signals chan os.Signal
|
|
}
|
|
|
|
// ConfigureExec configures the exec command with arguments and flags
|
|
func ConfigureExec(app *kingpin.Application, config *GlobalConfig) {
|
|
|
|
execConfig := ExecConfig{}
|
|
|
|
cmd := app.Command("exec", "Retrieve temporary credentials and set them as environment variables")
|
|
|
|
cmd.Arg("profile", "Name of the profile").
|
|
StringVar(&config.Profile)
|
|
|
|
cmd.Arg("cmd", "Command to execute").
|
|
Default(os.Getenv("SHELL")).
|
|
StringVar(&execConfig.Command)
|
|
|
|
cmd.Arg("args", "Command arguments").
|
|
StringsVar(&execConfig.Args)
|
|
|
|
cmd.Action(func(c *kingpin.ParseContext) error {
|
|
execConfig.Signals = make(chan os.Signal)
|
|
ExecCommand(app, config, &execConfig)
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// ExecCommand retrieves temporary credentials and sets them as environment variables
|
|
func ExecCommand(app *kingpin.Application, config *GlobalConfig, execConfig *ExecConfig) {
|
|
|
|
if os.Getenv("AWS_OIDC") != "" {
|
|
app.Fatalf("aws-vault sessions should be nested with care, unset $AWS_OIDC to force")
|
|
return
|
|
}
|
|
|
|
val, err := config.Session.Config.Credentials.Get()
|
|
if err != nil {
|
|
app.Fatalf("Unable to get credentials for profile: %s", config.Profile)
|
|
}
|
|
|
|
env := environ(os.Environ())
|
|
env.Set("AWS_OIDC", config.Profile)
|
|
|
|
env.Unset("AWS_ACCESS_KEY_ID")
|
|
env.Unset("AWS_SECRET_ACCESS_KEY")
|
|
env.Unset("AWS_CREDENTIAL_FILE")
|
|
env.Unset("AWS_DEFAULT_PROFILE")
|
|
env.Unset("AWS_PROFILE")
|
|
|
|
if config.Region != "" {
|
|
log.Printf("Setting subprocess env: AWS_DEFAULT_REGION=%s, AWS_REGION=%s", config.Region, config.Region)
|
|
env.Set("AWS_DEFAULT_REGION", config.Region)
|
|
env.Set("AWS_REGION", config.Region)
|
|
}
|
|
|
|
log.Println("Setting subprocess env: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY")
|
|
env.Set("AWS_ACCESS_KEY_ID", val.AccessKeyID)
|
|
env.Set("AWS_SECRET_ACCESS_KEY", val.SecretAccessKey)
|
|
|
|
if val.SessionToken != "" {
|
|
log.Println("Setting subprocess env: AWS_SESSION_TOKEN, AWS_SECURITY_TOKEN")
|
|
env.Set("AWS_SESSION_TOKEN", val.SessionToken)
|
|
env.Set("AWS_SECURITY_TOKEN", val.SessionToken)
|
|
}
|
|
|
|
cmd := exec.Command(execConfig.Command, execConfig.Args...)
|
|
cmd.Env = env
|
|
cmd.Stdin = os.Stdin
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
signal.Notify(execConfig.Signals, os.Interrupt, os.Kill)
|
|
|
|
if err := cmd.Start(); err != nil {
|
|
app.Fatalf("%v", err)
|
|
}
|
|
// wait for the command to finish
|
|
waitCh := make(chan error, 1)
|
|
go func() {
|
|
waitCh <- cmd.Wait()
|
|
close(waitCh)
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case sig := <-execConfig.Signals:
|
|
if err = cmd.Process.Signal(sig); err != nil {
|
|
app.Errorf("%v", err)
|
|
break
|
|
}
|
|
case err := <-waitCh:
|
|
var waitStatus syscall.WaitStatus
|
|
if exitError, ok := err.(*exec.ExitError); ok {
|
|
waitStatus = exitError.Sys().(syscall.WaitStatus)
|
|
os.Exit(waitStatus.ExitStatus())
|
|
}
|
|
if err != nil {
|
|
app.Fatalf("%v", err)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// environ is a slice of strings representing the environment, in the form "key=value".
|
|
type environ []string
|
|
|
|
// Unset an environment variable by key
|
|
func (e *environ) Unset(key string) {
|
|
for i := range *e {
|
|
if strings.HasPrefix((*e)[i], key+"=") {
|
|
(*e)[i] = (*e)[len(*e)-1]
|
|
*e = (*e)[:len(*e)-1]
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set adds an environment variable, replacing any existing ones of the same key
|
|
func (e *environ) Set(key, val string) {
|
|
e.Unset(key)
|
|
*e = append(*e, key+"="+val)
|
|
}
|