Skip to content

Commit

Permalink
Adding support for a mechanism to display or open the AWS Conosle URL -
Browse files Browse the repository at this point in the history
Resolves #9
  • Loading branch information
Jordan Kueh committed Dec 4, 2020
1 parent 5c3ae18 commit 6f4c917
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 1 deletion.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ I wrote this because I came across the following pattern:
Quite frankly, I tired of using a convoluted bash script to generate session tokens in order to assume a role, so I
wrote a thing to do it for me.

## Command Precedence

There's a few flags that are used to determine behaviour, and they are given the following precedence:

* `--console` or `--console-url`
* `--write-profile`

If none of the above are specified, it defaults to executing the command provided.

## Configuration

If you run `roo` once without a configuration file, it will generate a dummy one for you (at `${HOME}/.roo/config.yaml`)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ go 1.15

require (
github.com/aws/aws-sdk-go v1.36.0
github.com/pkg/browser v0.0.0-20201112035734-206646e67786
gopkg.in/yaml.v2 v2.4.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/pkg/browser v0.0.0-20201112035734-206646e67786 h1:4Gk0Dsp90g2YwfsxDOjvkEIgKGh+2R9FlvormRycveA=
github.com/pkg/browser v0.0.0-20201112035734-206646e67786/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down
71 changes: 70 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"regexp"
Expand All @@ -12,6 +15,7 @@ import (
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/pkg/browser"

"github.com/jkueh/roo/cachedcredsprovider"

Expand All @@ -22,7 +26,7 @@ import (
"github.com/aws/aws-sdk-go/service/sts"
)

const rooVersion = "0.2.0"
const rooVersion = "0.3.0"

var debug bool
var verbose bool
Expand All @@ -43,6 +47,7 @@ func main() {
var tokenNeedsRefresh bool
var writeToProfile bool
var targetProfile string
var openConsoleURL, showConsoleURL bool

flag.BoolVar(&debug, "debug", false, "Enables debug logging.")
flag.BoolVar(&showRoleList, "list", false, "Displays a list of configured roles, then exits.")
Expand All @@ -59,6 +64,8 @@ func main() {
"If set, roo will write the credentials to an AWS profile using the AWS CLI.",
)
flag.StringVar(&targetProfile, "target-profile", "", "The name of the profile to write credentials for.")
flag.BoolVar(&openConsoleURL, "console", false, "Opens an AWS console session")
flag.BoolVar(&showConsoleURL, "console-url", false, "Prints the console URL to stdout")

flag.Parse()

Expand Down Expand Up @@ -327,6 +334,68 @@ func main() {
}

fmt.Println("Profile written:", targetProfileName)
} else if openConsoleURL || showConsoleURL { // We also skip command execution if
// Step one... Is to build the URL.
request, err := http.NewRequest(http.MethodGet, "https://signin.aws.amazon.com/federation", nil)
if err != nil {
log.Fatalln("Unable to construct request to federation endpoint:", err)
}
sessionData := map[string]string{
"sessionId": retrievedCreds.AccessKeyID,
"sessionKey": retrievedCreds.SecretAccessKey,
"sessionToken": retrievedCreds.SessionToken,
}
sessionDataJSON, err := json.Marshal(&sessionData)
if err != nil {
log.Fatalln("Unable to build session credentials for federation endpoint call:", err)
}
query := request.URL.Query()
query.Add("Action", "getSigninToken")
query.Add("SessionDuration", "43200")
query.Add("Session", string(sessionDataJSON))
request.URL.RawQuery = query.Encode()

resp, err := http.DefaultClient.Do(request)
if err != nil {
log.Fatalln("An error occurred while retrieving data from federation endpoint:", err)
}

respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln("An error occurred while trying to read the response body from the federation endpoint:", err)
}

var signInTokenResponse SigninTokenResponse
err = json.Unmarshal(respBody, &signInTokenResponse)

consoleURLRequest, err := http.NewRequest(http.MethodGet, "https://signin.aws.amazon.com/federation", nil)
if err != nil {
log.Fatalln("Unable to construct console sign-in URL:", err)
}
consoleURLRequestQuery := consoleURLRequest.URL.Query()
consoleURLRequestQuery.Add("Action", "login")
consoleURLRequestQuery.Add("Issuer", "Example.org")
consoleURLRequestQuery.Add("Issuer", fmt.Sprintf("roo-%s", rooVersion))
consoleURLRequestQuery.Add("Destination", "https://console.aws.amazon.com/")
consoleURLRequestQuery.Add("SigninToken", signInTokenResponse.SigninToken)

consoleURLRequest.URL.RawQuery = consoleURLRequestQuery.Encode()

urlString := consoleURLRequest.URL.String()

if showConsoleURL { // If we're only asked to show it, print it and call it a day.
fmt.Println(urlString)
} else if openConsoleURL {
if debug {
log.Println("SigninToken:", signInTokenResponse.SigninToken)
}
err := browser.OpenURL(urlString)
if err != nil {
log.Fatalln("An error occurred while trying to get the system to open the console URL:", err)
}
} else {
log.Fatalln("Unhandled scenario: Not showConsoleURL or openConsoleURL")
}
} else {
if debug {
log.Println("flag.Args() length:", len(flag.Args()))
Expand Down
6 changes: 6 additions & 0 deletions sign_in_token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package main

// SigninTokenResponse - The payload that comes back from https://signin.aws.amazon.com/federation
type SigninTokenResponse struct {
SigninToken string `json:"SigninToken"`
}

0 comments on commit 6f4c917

Please sign in to comment.