Skip to content

Commit

Permalink
Revert changes to the ec2 metadata server since v5.3.2
Browse files Browse the repository at this point in the history
  • Loading branch information
mtibben committed May 4, 2020
1 parent 2eaabb9 commit 06cb65b
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 417 deletions.
223 changes: 78 additions & 145 deletions cli/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
"log"
"os"
osexec "os/exec"
"os/exec"
"os/signal"
"runtime"
"strings"
Expand All @@ -15,7 +15,6 @@ import (
"github.com/99designs/aws-vault/server"
"github.com/99designs/aws-vault/vault"
"github.com/99designs/keyring"
"github.com/aws/aws-sdk-go/aws/credentials"
"gopkg.in/alecthomas/kingpin.v2"
)

Expand All @@ -24,8 +23,7 @@ type ExecCommandInput struct {
Command string
Args []string
Keyring keyring.Keyring
StartEc2Server bool
StartEcsServer bool
StartServer bool
CredentialHelper bool
Config vault.Config
SessionDuration time.Duration
Expand All @@ -38,7 +36,7 @@ type AwsCredentialHelperData struct {
Version int `json:"Version"`
AccessKeyID string `json:"AccessKeyId"`
SecretAccessKey string `json:"SecretAccessKey"`
SessionToken string `json:"SessionToken,omitempty"`
SessionToken string `json:"SessionToken"`
Expiration string `json:"Expiration,omitempty"`
}

Expand Down Expand Up @@ -66,17 +64,9 @@ func ConfigureExecCommand(app *kingpin.Application) {
Short('j').
BoolVar(&input.CredentialHelper)

cmd.Flag("server", "Run a server in the background for credentials").
cmd.Flag("server", "Run the server in the background for credentials").
Short('s').
BoolVar(&input.StartEc2Server)

cmd.Flag("ec2-server", "Run a EC2 metadata server in the background for credentials").
Hidden().
BoolVar(&input.StartEc2Server)

cmd.Flag("ecs-server", "Run a ECS credential server in the background for credentials").
Hidden().
BoolVar(&input.StartEcsServer)
BoolVar(&input.StartServer)

cmd.Arg("profile", "Name of the profile").
Required().
Expand All @@ -95,7 +85,7 @@ func ConfigureExecCommand(app *kingpin.Application) {
input.Config.MfaPromptMethod = GlobalFlags.PromptDriver
input.Config.NonChainedGetSessionTokenDuration = input.SessionDuration
input.Config.AssumeRoleDuration = input.SessionDuration
app.FatalIfError(ExecCommand(input), "")
app.FatalIfError(ExecCommand(input), "exec")
return nil
})
}
Expand All @@ -105,23 +95,8 @@ func ExecCommand(input ExecCommandInput) error {
return fmt.Errorf("aws-vault sessions should be nested with care, unset $AWS_VAULT to force")
}

if input.StartEc2Server && input.StartEcsServer {
return fmt.Errorf("Can't use --server with --ecs-server")
}
if input.StartEc2Server && input.CredentialHelper {
return fmt.Errorf("Can't use --server with --json")
}
if input.StartEc2Server && input.NoSession {
return fmt.Errorf("Can't use --server with --no-session")
}
if input.StartEcsServer && input.CredentialHelper {
return fmt.Errorf("Can't use --ecs-server with --json")
}
if input.StartEcsServer && input.NoSession {
return fmt.Errorf("Can't use --ecs-server with --no-session")
}

vault.UseSession = !input.NoSession
setEnv := true

configLoader.BaseConfig = input.Config
configLoader.ActiveProfile = input.ProfileName
Expand All @@ -136,125 +111,83 @@ func ExecCommand(input ExecCommandInput) error {
return fmt.Errorf("Error getting temporary credentials: %w", err)
}

if input.StartEc2Server {
return execEc2Server(input, config, creds)
}

if input.StartEcsServer {
return execEcsServer(input, config, creds)
}

if input.CredentialHelper {
return execCredentialHelper(input, config, creds)
}

return execEnvironment(input, config, creds)
}

func updateEnvForAwsVault(env environ, profileName string, region string) environ {
env.Unset("AWS_ACCESS_KEY_ID")
env.Unset("AWS_SECRET_ACCESS_KEY")
env.Unset("AWS_SESSION_TOKEN")
env.Unset("AWS_SECURITY_TOKEN")
env.Unset("AWS_CREDENTIAL_FILE")
env.Unset("AWS_DEFAULT_PROFILE")
env.Unset("AWS_PROFILE")
env.Unset("AWS_SDK_LOAD_CONFIG")

env.Set("AWS_VAULT", profileName)

if region != "" {
log.Printf("Setting subprocess env: AWS_DEFAULT_REGION=%s, AWS_REGION=%s", region, region)
env.Set("AWS_DEFAULT_REGION", region)
env.Set("AWS_REGION", region)
}

return env
}

func execEc2Server(input ExecCommandInput, config *vault.Config, creds *credentials.Credentials) error {
if err := server.StartEc2CredentialsServer(creds, config.Region); err != nil {
return fmt.Errorf("Failed to start credential server: %w", err)
}

env := environ(os.Environ())
env = updateEnvForAwsVault(env, input.ProfileName, config.Region)

return execCmd(input.Command, input.Args, env)
}

func execEcsServer(input ExecCommandInput, config *vault.Config, creds *credentials.Credentials) error {
uri, token, err := server.StartEcsCredentialServer(creds)
if err != nil {
return fmt.Errorf("Failed to start credential server: %w", err)
}

env := environ(os.Environ())
env = updateEnvForAwsVault(env, input.ProfileName, config.Region)

log.Println("Setting subprocess env AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_CONTAINER_AUTHORIZATION_TOKEN")
env.Set("AWS_CONTAINER_CREDENTIALS_FULL_URI", uri)
env.Set("AWS_CONTAINER_AUTHORIZATION_TOKEN", token)

return execCmd(input.Command, input.Args, env)
}

func execCredentialHelper(input ExecCommandInput, config *vault.Config, creds *credentials.Credentials) error {
val, err := creds.Get()
if err != nil {
return fmt.Errorf("Failed to get credentials for %s: %w", input.ProfileName, err)
}

credentialData := AwsCredentialHelperData{
Version: 1,
AccessKeyID: val.AccessKeyID,
SecretAccessKey: val.SecretAccessKey,
}
if val.SessionToken != "" {
credentialData.SessionToken = val.SessionToken
}
if credsExpiresAt, err := creds.ExpiresAt(); err == nil {
credentialData.Expiration = credsExpiresAt.Format("2006-01-02T15:04:05Z")
}

json, err := json.Marshal(&credentialData)
if err != nil {
return fmt.Errorf("Error creating credential json: %w", err)
}

fmt.Print(string(json))

return nil
}

func execEnvironment(input ExecCommandInput, config *vault.Config, creds *credentials.Credentials) error {
val, err := creds.Get()
if err != nil {
return fmt.Errorf("Failed to get credentials for %s: %w", input.ProfileName, err)
if input.StartServer {
if err := server.StartCredentialsServer(creds); err != nil {
return fmt.Errorf("Failed to start credential server: %w", err)
}
setEnv = false
}

env := environ(os.Environ())
env = updateEnvForAwsVault(env, input.ProfileName, config.Region)
if input.CredentialHelper {
credentialData := AwsCredentialHelperData{
Version: 1,
AccessKeyID: val.AccessKeyID,
SecretAccessKey: val.SecretAccessKey,
SessionToken: val.SessionToken,
}
if !input.NoSession {
credsExprest, err := creds.ExpiresAt()
if err != nil {
return fmt.Errorf("Error getting credential expiration: %w", err)
}
credentialData.Expiration = credsExprest.Format("2006-01-02T15:04:05Z")
}
json, err := json.Marshal(&credentialData)
if err != nil {
return fmt.Errorf("Error creating credential json: %w", err)
}
fmt.Print(string(json))
} else {

env := environ(os.Environ())
env.Set("AWS_VAULT", input.ProfileName)

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 setEnv {
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)
expiration, err := creds.ExpiresAt()
if err == nil {
log.Println("Setting subprocess env: AWS_SESSION_EXPIRATION")
env.Set("AWS_SESSION_EXPIRATION", expiration.Format(time.RFC3339))
}
}
}

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)
}
if expiration, err := creds.ExpiresAt(); err == nil {
log.Println("Setting subprocess env: AWS_SESSION_EXPIRATION")
env.Set("AWS_SESSION_EXPIRATION", expiration.Format(time.RFC3339))
}
if input.StartServer {
err = execCmd(input.Command, input.Args, env)
} else {
err = execSyscall(input.Command, input.Args, env)
}

if !supportsExecSyscall() {
return execCmd(input.Command, input.Args, env)
if err != nil {
return fmt.Errorf("Error execing process: %w", err)
}
}

return execSyscall(input.Command, input.Args, env)
return nil
}

// environ is a slice of strings representing the environment, in the form "key=value".
Expand All @@ -278,9 +211,7 @@ func (e *environ) Set(key, val string) {
}

func execCmd(command string, args []string, env []string) error {
log.Printf("Starting child process: %s %s", command, strings.Join(args, " "))

cmd := osexec.Command(command, args...)
cmd := exec.Command(command, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Expand All @@ -290,7 +221,7 @@ func execCmd(command string, args []string, env []string) error {
signal.Notify(sigChan)

if err := cmd.Start(); err != nil {
return err
return fmt.Errorf("Failed to start command: %v", err)
}

go func() {
Expand All @@ -315,9 +246,11 @@ func supportsExecSyscall() bool {
}

func execSyscall(command string, args []string, env []string) error {
log.Printf("Exec command %s %s", command, strings.Join(args, " "))
if !supportsExecSyscall() {
return execCmd(command, args, env)
}

argv0, err := osexec.LookPath(command)
argv0, err := exec.LookPath(command)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func ConfigureServerCommand(app *kingpin.Application) {
}

func ServerCommand(app *kingpin.Application, input ServerCommandInput) {
if err := server.StartEc2MetadataEndpointProxy(); err != nil {
if err := server.StartMetadataServer(); err != nil {
app.Fatalf("Server failed: %v", err)
}
}
2 changes: 1 addition & 1 deletion server/ec2alias_bsd.go → server/alias_bsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ package server

import "os/exec"

func installEc2EndpointNetworkAlias() ([]byte, error) {
func installNetworkAlias() ([]byte, error) {
return exec.Command("ifconfig", "lo0", "alias", "169.254.169.254").CombinedOutput()
}
2 changes: 1 addition & 1 deletion server/ec2alias_linux.go → server/alias_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ package server

import "os/exec"

func installEc2EndpointNetworkAlias() ([]byte, error) {
func installNetworkAlias() ([]byte, error) {
return exec.Command("ip", "addr", "add", "169.254.169.254/24", "dev", "lo", "label", "lo:0").CombinedOutput()
}
2 changes: 1 addition & 1 deletion server/ec2alias_windows.go → server/alias_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"strings"
)

func installEc2EndpointNetworkAlias() ([]byte, error) {
func installNetworkAlias() ([]byte, error) {
out, err := exec.Command("netsh", "interface", "ipv4", "add", "address", "Loopback Pseudo-Interface 1", "169.254.169.254", "255.255.0.0").CombinedOutput()

if err == nil || strings.Contains(string(out), "The object already exists") {
Expand Down
Loading

0 comments on commit 06cb65b

Please sign in to comment.