Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add console subcommand #93

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

RowdyLemon
Copy link
Contributor

Vaulted console uses an access key to open an AWS console in the
default browser.

console.go Outdated
)

var (
ErrInvalidTemporaryCredentials = errors.New("Invalid temporary session credentials present, permanent credentials are required.\nPermanent credentials can be used be specifying a vault name")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message should probably be tweaked. First, "invalid temporary session credentials present" isn't accurate. It has nothing to do with the validity of the creds, they're simply not capable of invoking the console. Second, I think we can explain the permanent credentials / vault option a little cleaner.

console.go Outdated

var (
ErrInvalidTemporaryCredentials = errors.New("Invalid temporary session credentials present, permanent credentials are required.\nPermanent credentials can be used be specifying a vault name")
ErrInvalidDuration = errors.New("Minimum console duration must be at least 15 min")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should either not abbreviate "minutes" or abbreviate it more in line with other messages we post about duration - "15m"

console.go Outdated
if err != nil {
return nil, nil, err
}
awsCreds, err = awsCreds.GetFederationToken(*fedDuration)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if there are no AWS credentials in the vault?

console.go Outdated
}
}
} else {
tempCreds, err := session.AWSCreds.GetLoadedOrDefaultCreds()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens here if it is unable to load default creds from the environment? Does it error, or does it simply set the values to empty string or nil?

console.go Outdated
}

if c.Role != "" {
awsCreds, err = session.AWSCreds.AssumeRole(c.Role, *fedDuration)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we can try to merge some of these checks / assumes? We seem to be repeating certain actions between vault and no-vault, I think we can wrap them a bit cleaner.

console.go Outdated
return nil, nil, err
}
} else {
awsCreds, err = session.AWSCreds.GetFederationToken(*fedDuration)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if we were unable to load credentials by this point?

A role to assume can be specified either in a vault's configuration (via
`vaulted edit`) or specified via the `--assume` option.

Vaulted first opens the specified vault to retrieve the appropriate credentials. If a role is specified in the vault's configuration it will use that unless a role is explicitely passed in through the `--asume` option.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple typos:

  • --assume
  • explicitly

"fmt"
// "io/ioutil"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this have been removed?

@RowdyLemon RowdyLemon force-pushed the consoleSubcommand branch 4 times, most recently from bdf1167 to bd677cb Compare August 1, 2017 20:45
Copy link
Collaborator

@ryan-norton ryan-norton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good! Just a couple nits.

}

return creds.GetSigninToken(&duration)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: line gap

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

console.go Outdated
}

func (c *Console) getSigninToken(store vaulted.Store) (string, error) {
// Setup default values (may be overwritten by values from vault)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future work: Perhaps we should allow this to be passed via command line as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


Opens the AWS console in the default web browser. Uses either the credentials in the current environment or the credentials in the specified vault. Console sessions either use the provided vault's duration or defaults to 1 hour.

Durations must be at least 15 min and less than 12 hours.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: s/min/minutes

command_test.go Outdated
@@ -445,6 +449,30 @@ var (
Args: []string{"-V"},
Command: &Version{},
},
// Console
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any tests for "duration"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

console.go Outdated
}

// If duration was provided through the command line overwrite with that
if c.Duration != 0 && (c.Duration < 15*time.Minute || c.Duration > 12*time.Hour) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be checking if the Duration is valid when we receive the command, rather than in the console handling?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

console.go Outdated
)

const (
CONSOLE_URL = "https://console.aws.amazon.com/console/home"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be mixing UPPER_CASE and CamelCase types here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

console.go Outdated
CONSOLE_URL = "https://console.aws.amazon.com/console/home"
SIGNIN_URL = "https://signin.aws.amazon.com/federation"

MinConsoleDuration = 15 * time.Minute
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should probably begin with "Console" like the above consts, just to keep a consistent namespace.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

console.go Outdated
}
}

// If duration was provided through the command line overwrite with that
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, 15*time.Minute and 12*time.Hour should be used as consts when we do these checks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

console.go Outdated
if tokenErr != nil {
return "", tokenErr
}
creds, err = creds.AssumeRoleWithMFA(awsKey.MFA, tokenCode, awsKey.Role, 15*time.Minute)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15*time.Minute feels like it should be used as a const.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

console.go Outdated
}
creds, err = creds.AssumeRoleWithMFA(awsKey.MFA, tokenCode, awsKey.Role, 15*time.Minute)
} else {
creds, err = creds.AssumeRole(awsKey.Role, 15*time.Minute)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15*time.Minute feels like it should be used as a const.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

doc/vaulted.1.md Outdated
@@ -28,6 +28,9 @@ COMMANDS
`add` / `create` / `new`
Interactively creates the content of a new vault. See vaulted-add(1).

`console`
Opens the AWS console in the default web browser. See vauled-console(1).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/vauled/vaulted

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

DESCRIPTION
-----------

Opens the AWS console in the default web browser. Uses either the credentials in the current environment or the credentials in the specified vault. Console sessions either use the passed in duration, the provided vault's duration, or defaults to 1 hour.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this description can use a little work. For starters, "uses either the credentials in the current environment or the credentials in the specified vault" doesn't really capture the order of preference.

Second, "Console sessions use" seems unnecessary, given that this is a document on the console command, so the duration is implied to correspond to the console. Additionally, it feels a bit disjointed in how we are going about describing the methods by which a duration is supplied, made worse when we seem to take on the duration range after the rest.

Perhaps we should take a pass on this and see if we can improve the wording a bit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Collaborator

@ryan-norton ryan-norton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting thing I noticed when I pulled this down to check something - I ran vaulted console on two different vaults containing credentials for two different AWS accounts. The first attempt worked, the second attempt went to an error page informing me that I was logged into a different account. We should see if this can be rectified, or at least document the case in which this is occurring. In this case I had already closed out of the console window for the other account, so it felt odd.

Also, were you able to apply any further error handling around the case where we receive permission errors?

doc/vaulted.1.md Outdated
@@ -28,6 +28,9 @@ COMMANDS
`add` / `create` / `new`
Interactively creates the content of a new vault. See vaulted-add(1).

`console`
Opens the AWS console in the default web browser. See vauled-console(1).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still wrong.

command_test.go Outdated
@@ -544,6 +579,11 @@ var (
Args: []string{"upgrade", "one"},
},

// Console
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should alphabetize this with the rest of the commands.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

command_test.go Outdated
@@ -544,6 +579,11 @@ var (
Args: []string{"upgrade", "one"},
},

// Console
{
Args: []string{"Console", "one", "two"},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is Console capitalized here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In our fail test cases here we should probably test --duration min/max values outside of the accepted range, like:

Args: []string{"console", "one", "--duration", "14m"},

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

command_test.go Outdated
Args: []string{"console", "--duration", "15m", "one"},
Command: &Console{
VaultName: "one",
Duration: ConsoleMinDuration,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels weird to specify it as "15m" in the args string and "ConsoleMinDuration" in the Command. The above string is meant to represent an entered command, so it seems wrong to then correlate their input to a const duration, particularly if the test isn't explicitly meant to test the ConsoleMinDuration (which, if this is, we need to be testing the ConsoleMaxDuration as well, including testing that values outside of those ranges do not work)

command_test.go Outdated
@@ -445,6 +449,37 @@ var (
Args: []string{"-V"},
Command: &Version{},
},
// Console
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should include this in the command list alphabetically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

console.go Outdated
if err != nil {
if err != credentials.ErrNoValidProvidersFoundInChain {
return nil, err
} else if err == credentials.ErrNoValidProvidersFoundInChain || !awsCreds.Valid() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

err == credentials.ErrNoValidProvidersFoundInChain || is unnecessary, right? We effectively did this check in the above part of the if statement.

Plus, we're never actually checking !awsCreds.Valid() since we will trigger on the ErrNoValidProvidersFoundInChain piece.

console.go Outdated
} else if err == credentials.ErrNoValidProvidersFoundInChain || !awsCreds.Valid() {
return nil, ErrNoCredentialsFound
}
} else if awsCreds.ValidSession() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else if statement here can probably be pulled out of the transition statement and just be checked before return awsCreds, nil at the end, right?

The above check confirms that the creds are Valid, but does not check if its a session, we should probably always be checking that.

console.go Outdated
}

func (c *Console) getSigninToken(store vaulted.Store) (string, error) {
vault, err := c.getVault(store)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like we really should not be storing and passing on a vault to everything in this function.

It feels like we should be calling OpenVault when necessary and pulling the requisite pieces (Key, Duration, etc) long enough to store those but not holding and sharing the vault with everything else to get their piece from it.

It feels like this level should have some sort of control flow on if c.VaultName != "", rather than doing this down in another method.

console.go Outdated

awsKey := c.getAWSKey(vault)

awsCreds, err := c.getCredentials(vault, awsKey)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awsCreds feels wrong here. iirc You can use AWSKey.Credentials() to get the creds from a key, so we don't need to keep passing them along separately.

duration = ConsoleDefaultDuration
}

return capDuration(duration)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if we've validated the Duration when we received the command, it still feels like we shouldn't be calling capDuration on the command flag duration. capDuration really only belongs with the Vault duration.

@RowdyLemon RowdyLemon force-pushed the consoleSubcommand branch 2 times, most recently from b6f3a18 to bfb11b8 Compare October 30, 2017 17:02
Copy link
Contributor

@ryanmt ryanmt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by ping, still wish I had this feature sometimes.

vaultName := ""
assume, _ := flag.GetString("assume")
duration, _ := flag.GetDuration("duration")
if duration != 0 && (duration < ConsoleMinDuration || duration > ConsoleMaxDuration) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Console*Duration constants aren't specific to the console, but to the underlying Role. These should probably be named/refactored accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants