Added login command to exchange temporary credentials for an AWS Console login URL

* Added login subcommand
* Updated Readme
This commit is contained in:
Jeremy Stott 2019-06-21 15:26:44 +12:00
parent dbfc079550
commit db2460d7db
No known key found for this signature in database
GPG Key ID: 74E9C385710FA51F
4 changed files with 106 additions and 0 deletions

View File

@ -37,6 +37,14 @@ Most AWS SDK implementations should be able to use the `credential_process` conf
* aws-cli
* boto3
## Sign into the AWS Console
Use the `login` command to exchange the temporary credentials with an [AWS Console login URL](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html)
aws-oidc login
![example](docs/aws-oidc-console-login.gif)
## Open Chrome with a particular profile
Open `chrome://version/` in the Chrome profile you want to open as, and make a note of the last part of the profile path.

View File

@ -49,6 +49,7 @@ func run(args []string, exit func(int)) {
cli.ConfigureAuth(app, &config)
cli.ConfigureExec(app, &config)
cli.ConfigureList(app, &config)
cli.ConfigureLogin(app, &config)
kingpin.MustParse(app.Parse(args))
}

97
cli/login.go Normal file
View File

@ -0,0 +1,97 @@
package cli
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
"gopkg.in/alecthomas/kingpin.v2"
)
// LoginConfig stores the parameters needed for an login command
type LoginConfig struct {
Profile string
}
type signinSession struct {
SessionID string `json:"sessionId"`
SessionKey string `json:"sessionKey"`
SessionToken string `json:"sessionToken"`
}
type signinToken struct {
SigninToken string
}
// ConfigureLogin configures the login command with arguments and flags
func ConfigureLogin(app *kingpin.Application, config *GlobalConfig) {
loginConfig := LoginConfig{}
cmd := app.Command("login", "Login to the AWS console for a given profile")
cmd.Arg("profile", "Name of the profile").
StringVar(&config.Profile)
cmd.Action(func(c *kingpin.ParseContext) error {
LoginCommand(app, config, &loginConfig)
return nil
})
}
// LoginCommand exchanges temporary credentials for an AWS Console signin url
// https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html
func LoginCommand(app *kingpin.Application, config *GlobalConfig, loginConfig *LoginConfig) {
// Retrieve credentials from current session. This will try and get credentials
// using aws-oidc itself if configured in ~/.aws/config.
val, err := config.Session.Config.Credentials.Get()
if err != nil {
app.Fatalf("Unable to get credentials for profile: %s", config.Profile)
}
credentialData := signinSession{
SessionID: val.AccessKeyID,
SessionKey: val.SecretAccessKey,
SessionToken: val.SessionToken,
}
credentialJSON, err := json.Marshal(&credentialData)
if err != nil {
app.Fatalf("Unable to marshal credentials for profile: %s", config.Profile)
}
// Create the federation URL to exchange access keys for a session token
tokenURL, _ := url.Parse("https://signin.aws.amazon.com/federation")
tokenQuery := url.Values{}
tokenQuery.Set("Action", "getSigninToken")
tokenQuery.Set("Session", string(credentialJSON))
tokenURL.RawQuery = tokenQuery.Encode()
var client = &http.Client{
Timeout: time.Second * 60,
}
resp, err := client.Get(tokenURL.String())
if err != nil {
app.Fatalf("Unable to get signin token for profile: %s", config.Profile)
} else if resp.StatusCode != 200 {
app.Fatalf("GetSigninToken returned %d instead of 200 for profile: %s", resp.StatusCode, config.Profile)
}
defer resp.Body.Close()
token := signinToken{}
if err := json.NewDecoder(resp.Body).Decode(&token); err != nil {
app.Fatalf("Unable to decode GetSigninToken response for profile: %s", config.Profile)
}
// Create the federation URL to exchange the session token for a login URL
loginURL, _ := url.Parse("https://signin.aws.amazon.com/federation")
loginQuery := url.Values{}
loginQuery.Set("Action", "login")
loginQuery.Set("Destination", "https://console.aws.amazon.com/")
loginQuery.Set("SigninToken", token.SigninToken)
loginURL.RawQuery = loginQuery.Encode()
fmt.Println(loginURL)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB