From bce2a71d0d179ec2d8eaf0aaea54a657103bfd93 Mon Sep 17 00:00:00 2001 From: Lachlan Donald Date: Wed, 16 Sep 2015 17:23:05 +1000 Subject: [PATCH] Add a command to generate login links for AWS Console --- login.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 9 ++++++ 2 files changed, 92 insertions(+) create mode 100644 login.go diff --git a/login.go b/login.go new file mode 100644 index 000000000..00c574bb8 --- /dev/null +++ b/login.go @@ -0,0 +1,83 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "time" + + "github.com/99designs/aws-vault/keyring" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/credentials" +) + +type LoginCommandInput struct { + Profile string + Keyring keyring.Keyring +} + +func LoginCommand(ui Ui, input LoginCommandInput) { + provider, err := NewVaultProvider(input.Keyring, input.Profile, time.Hour) + if err != nil { + ui.Error.Fatal(err) + } + + creds := credentials.NewCredentials(provider) + val, err := creds.Get() + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" { + ui.Error.Fatalf("No credentials found for profile %q", input.Profile) + } else { + ui.Error.Fatal(err) + } + } + + jsonBytes, err := json.Marshal(map[string]string{ + "sessionId": val.AccessKeyID, + "sessionKey": val.SecretAccessKey, + "sessionToken": val.SessionToken, + }) + if err != nil { + ui.Error.Fatal(err) + } + + req, err := http.NewRequest("GET", "https://signin.aws.amazon.com/federation", nil) + if err != nil { + ui.Error.Fatal(err) + } + + q := req.URL.Query() + q.Add("Action", "getSigninToken") + q.Add("Session", string(jsonBytes)) + req.URL.RawQuery = q.Encode() + + resp, err := http.DefaultClient.Do(req) + if err != nil { + ui.Error.Fatal(err) + } + + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + ui.Error.Fatal(err) + } + + var respParsed map[string]string + + if err = json.Unmarshal([]byte(body), &respParsed); err != nil { + ui.Error.Fatal(err) + } + + signinToken, ok := respParsed["SigninToken"] + if !ok { + ui.Error.Fatal("Expected a response with SigninToken") + } + + fmt.Printf( + "https://signin.aws.amazon.com/federation?Action=login&Issuer=aws-vault&Destination=%s&SigninToken=%s", + url.QueryEscape("https://console.aws.amazon.com/"), + url.QueryEscape(signinToken), + ) +} diff --git a/main.go b/main.go index 3ef70a8e3..cc8a06267 100644 --- a/main.go +++ b/main.go @@ -41,6 +41,8 @@ func main() { execCmdArgs = exec.Arg("args", "Command arguments").Strings() rm = kingpin.Command("rm", "Removes credentials") rmProfile = rm.Arg("profile", "Name of the profile").Required().String() + login = kingpin.Command("login", "Generate a login link for the AWS Console") + loginProfile = login.Arg("profile", "Name of the profile").Required().String() ) kingpin.Version(Version) @@ -96,5 +98,12 @@ func main() { Keyring: keyring, Duration: *execSessDuration, }) + + case login.FullCommand(): + LoginCommand(ui, LoginCommandInput{ + Profile: *loginProfile, + Keyring: keyring, + }) } + }