Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions pkg/assume/assume.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,10 +280,11 @@ func AssumeCommand(c *cli.Context) error {
}

configOpts := cfaws.ConfigOpts{
Duration: time.Hour,
MFATokenCode: assumeFlags.String("mfa-token"),
Args: assumeFlags.StringSlice("pass-through"),
DisableCache: assumeFlags.Bool("no-cache"),
Duration: time.Hour,
MFATokenCode: assumeFlags.String("mfa-token"),
Args: assumeFlags.StringSlice("pass-through"),
DisableCache: assumeFlags.Bool("no-cache"),
SSOBrowserProfile: assumeFlags.String("sso-browser-profile"),
}

// attempt to get session duration from profile
Expand All @@ -307,7 +308,7 @@ func AssumeCommand(c *cli.Context) error {

// if getConsoleURL is true, we'll use the AWS federated login to retrieve a URL to access the console.
// depending on how Granted is configured, this is then printed to the terminal or a browser is launched at the URL automatically.
getConsoleURL := !assumeFlags.Bool("env") && ((assumeFlags.Bool("console") || assumeFlags.String("console-destination") != "") || assumeFlags.Bool("active-role") || assumeFlags.String("service") != "" || assumeFlags.Bool("url") || assumeFlags.String("browser-profile") != "")
getConsoleURL := !assumeFlags.Bool("env") && ((assumeFlags.Bool("console") || assumeFlags.String("console-destination") != "") || assumeFlags.Bool("active-role") || assumeFlags.String("service") != "" || assumeFlags.Bool("url"))

// this makes it easy for users to copy the actual command and avoid needing to lookup profiles
if !cfg.DisableUsageTips && showRerunCommand {
Expand Down
3 changes: 2 additions & 1 deletion pkg/assume/entrypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ func GlobalFlags() []cli.Flag {
&cli.StringFlag{Name: "sso-region", Usage: "Use this in conjunction with --sso, the sso-region"},
&cli.StringFlag{Name: "account-id", Usage: "Use this in conjunction with --sso, the account-id"},
&cli.StringFlag{Name: "role-name", Usage: "Use this in conjunction with --sso, the role-name"},
&cli.StringFlag{Name: "browser-profile", Aliases: []string{"bp"}, Usage: "Use a pre-existing profile in your browser"},
&cli.StringFlag{Name: "browser-profile", Aliases: []string{"bp"}, Usage: "Use a pre-existing profile in your browser", EnvVars: []string{"GRANTED_BROWSER_PROFILE"}},
&cli.StringFlag{Name: "sso-browser-profile", Usage: "Use a pre-existing profile in your browser for SSO login", EnvVars: []string{"GRANTED_SSO_BROWSER_PROFILE"}},
&cli.StringFlag{Name: "mfa-token", Usage: "Provide your current MFA token for the role you are assuming to skip being prompted"},
&cli.StringFlag{Name: "save-to", Usage: "Use this in conjunction with --sso, the profile name to save the role to in your AWS config file"},
&cli.BoolFlag{Name: "export-all-env-vars", Aliases: []string{"x"}, Usage: "Exports all available credentials to the terminal when used with a profile configured for credential-process. Without this flag, only the AWS_PROFILE will be configured"},
Expand Down
2 changes: 1 addition & 1 deletion pkg/cfaws/assumer_aws_sso.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func (c *Profile) SSOLogin(ctx context.Context, configOpts ConfigOpts) (aws.Cred
if cachedToken == nil && plainTextToken == nil {
newCfg := aws.NewConfig()
newCfg.Region = rootProfile.SSORegion()
newSSOToken, err := idclogin.Login(ctx, *newCfg, rootProfile.SSOStartURL(), rootProfile.SSOScopes())
newSSOToken, err := idclogin.Login(ctx, *newCfg, rootProfile.SSOStartURL(), rootProfile.SSOScopes(), configOpts.SSOBrowserProfile)
if err != nil {
return aws.Credentials{}, err
}
Expand Down
1 change: 1 addition & 0 deletions pkg/cfaws/profiles.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type ConfigOpts struct {
ShouldRetryAssuming *bool
MFATokenCode string
DisableCache bool
SSOBrowserProfile string
}

type Profile struct {
Expand Down
24 changes: 16 additions & 8 deletions pkg/granted/sso.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ var GenerateCommand = cli.Command{
&cli.StringFlag{Name: "sso-region", Usage: "Specify the SSO region"},
&cli.StringSliceFlag{Name: "source", Usage: "The sources to load AWS profiles from (valid values are: 'aws-sso')", Value: cli.NewStringSlice("aws-sso")},
&cli.BoolFlag{Name: "no-credential-process", Usage: "Generate profiles without the Granted credential-process integration"},
&cli.StringFlag{Name: "profile-template", Usage: "Specify profile name template", Value: awsconfigfile.DefaultProfileNameTemplate}},
&cli.StringFlag{Name: "profile-template", Usage: "Specify profile name template", Value: awsconfigfile.DefaultProfileNameTemplate},
&cli.StringFlag{Name: "sso-browser-profile", Usage: "Use a pre-existing profile in your browser for SSO login", EnvVars: []string{"GRANTED_SSO_BROWSER_PROFILE"}},
},
Action: func(c *cli.Context) error {
ctx := c.Context
fullCommand := fmt.Sprintf("%s %s", c.App.Name, c.Command.FullName()) // e.g. 'granted sso populate'
Expand Down Expand Up @@ -100,10 +102,11 @@ var GenerateCommand = cli.Command{
Prefix: prefix,
}

ssoBrowserProfile := c.String("sso-browser-profile")
for _, s := range c.StringSlice("source") {
switch s {
case "aws-sso":
g.AddSource(AWSSSOSource{SSORegion: ssoRegion, StartURL: startURL})
g.AddSource(AWSSSOSource{SSORegion: ssoRegion, StartURL: startURL, SSOBrowserProfile: ssoBrowserProfile})
case "commonfate", "common-fate", "cf":
return fmt.Errorf("the common fate profile source is no longer supported: https://www.commonfate.io/blog/winding-down")
default:
Expand Down Expand Up @@ -138,6 +141,7 @@ var PopulateCommand = cli.Command{
&cli.BoolFlag{Name: "prune", Usage: "Remove any generated profiles with the 'common_fate_generated_from' key which no longer exist"},
&cli.StringFlag{Name: "profile-template", Usage: "Specify profile name template", Value: awsconfigfile.DefaultProfileNameTemplate},
&cli.BoolFlag{Name: "no-credential-process", Usage: "Generate profiles without the Granted credential-process integration"},
&cli.StringFlag{Name: "sso-browser-profile", Usage: "Use a pre-existing profile in your browser for SSO login", EnvVars: []string{"GRANTED_SSO_BROWSER_PROFILE"}},
},
Action: func(c *cli.Context) error {
ctx := c.Context
Expand Down Expand Up @@ -214,10 +218,11 @@ var PopulateCommand = cli.Command{
PruneStartURLs: pruneStartURLs,
}

ssoBrowserProfile := c.String("sso-browser-profile")
for _, s := range c.StringSlice("source") {
switch s {
case "aws-sso":
g.AddSource(AWSSSOSource{SSORegion: ssoRegion, StartURL: startURL, SSOScopes: c.StringSlice("sso-scope")})
g.AddSource(AWSSSOSource{SSORegion: ssoRegion, StartURL: startURL, SSOScopes: c.StringSlice("sso-scope"), SSOBrowserProfile: ssoBrowserProfile})
case "commonfate", "common-fate", "cf":
return fmt.Errorf("the common fate profile source is no longer supported: https://www.commonfate.io/blog/winding-down")
default:
Expand Down Expand Up @@ -245,6 +250,7 @@ var LoginCommand = cli.Command{
&cli.StringFlag{Name: "sso-region", Usage: "Specify the SSO region"},
&cli.StringFlag{Name: "sso-start-url", Usage: "Specify the SSO start url"},
&cli.StringSliceFlag{Name: "sso-scope", Usage: "Specify the SSO scopes"},
&cli.StringFlag{Name: "sso-browser-profile", Usage: "Use a pre-existing profile in your browser for SSO login", EnvVars: []string{"GRANTED_SSO_BROWSER_PROFILE"}},
},
Action: func(c *cli.Context) error {
ctx := c.Context
Expand Down Expand Up @@ -291,13 +297,14 @@ var LoginCommand = cli.Command{
}

ssoScopes := c.StringSlice("sso-scope")
ssoBrowserProfile := c.String("sso-browser-profile")

cfg := aws.NewConfig()
cfg.Region = ssoRegion

secureSSOTokenStorage := securestorage.NewSecureSSOTokenStorage()

newSSOToken, err := idclogin.Login(ctx, *cfg, ssoStartUrl, ssoScopes)
newSSOToken, err := idclogin.Login(ctx, *cfg, ssoStartUrl, ssoScopes, ssoBrowserProfile)
if err != nil {
return err
}
Expand All @@ -311,9 +318,10 @@ var LoginCommand = cli.Command{
}

type AWSSSOSource struct {
SSORegion string
StartURL string
SSOScopes []string
SSORegion string
StartURL string
SSOScopes []string
SSOBrowserProfile string
}

func (s AWSSSOSource) GetProfiles(ctx context.Context) ([]awsconfigfile.SSOProfile, error) {
Expand Down Expand Up @@ -348,7 +356,7 @@ func (s AWSSSOSource) GetProfiles(ctx context.Context) ([]awsconfigfile.SSOProfi

if ssoTokenFromSecureCache == nil && ssoTokenFromPlainText == nil {
// otherwise, login with SSO
ssoTokenFromSecureCache, err = idclogin.Login(ctx, cfg, s.StartURL, s.SSOScopes)
ssoTokenFromSecureCache, err = idclogin.Login(ctx, cfg, s.StartURL, s.SSOScopes, s.SSOBrowserProfile)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/idclogin/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
)

// Login contains all the steps to complete a device code flow to retrieve an SSO token
func Login(ctx context.Context, cfg aws.Config, startUrl string, scopes []string) (*securestorage.SSOToken, error) {
func Login(ctx context.Context, cfg aws.Config, startUrl string, scopes []string, browserProfile string) (*securestorage.SSOToken, error) {
ssooidcClient := ssooidc.NewFromConfig(cfg)

// If scopes aren't provided, default to the legacy non-refreshable configuration
Expand Down Expand Up @@ -79,7 +79,7 @@ func Login(ctx context.Context, cfg aws.Config, startUrl string, scopes []string
}

// now build the actual command to run - e.g. 'firefox --new-tab <URL>'
args, err := l.LaunchCommand(url, "")
args, err := l.LaunchCommand(url, browserProfile)
if err != nil {
return nil, fmt.Errorf("error building browser launch command: %w", err)
}
Expand Down
11 changes: 11 additions & 0 deletions pkg/launcher/custom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ func TestCustom_LaunchCommand(t *testing.T) {
},
want: []string{"/usr/bin/firefox", "--url", "https://commonfate.io", "--profile", "example"},
},
{
name: "empty_profile",
fields: fields{
Command: "/usr/bin/firefox --url {{.URL}} --profile {{.Profile}}",
},
args: args{
url: "https://commonfate.io",
profile: "",
},
want: []string{"/usr/bin/firefox", "--url", "https://commonfate.io", "--profile", ""},
},
{
name: "with_args",
fields: fields{
Expand Down