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
2 changes: 1 addition & 1 deletion cmd/ocm-backplane/cloud/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func (cfg *QueryConfig) GetCloudConsole() (*ConsoleResponse, error) {
return nil, fmt.Errorf("failed to get signin token: %w", err)
}

signinFederationURL, err := awsutil.GetConsoleURL(resp.SigninToken, cfg.Cluster.Region().ID())
signinFederationURL, err := awsutil.GetConsoleURL(resp.SigninToken, cfg.Cluster.Region().ID(), cfg.SessionDurationMinutes)
if err != nil {
return nil, fmt.Errorf("failed to generate console url: %w", err)
}
Expand Down
28 changes: 25 additions & 3 deletions cmd/ocm-backplane/cloud/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ import (
)

var consoleArgs struct {
browser bool
backplaneURL string
output string
browser bool
backplaneURL string
output string
sessionDurationMinutes int
}

type ConsoleResponse struct {
Expand All @@ -37,6 +38,10 @@ func (r *ConsoleResponse) String() string {
// EnvBrowserDefault environment variable that indicates if open by browser is set as default
const EnvBrowserDefault = "BACKPLANE_DEFAULT_OPEN_BROWSER"

// MAX_SESSION_TIMEOUT_DURATION maximum session duration in minutes
// This is limited by AWS STS maximum duration for assumed roles of 60 minutes
const MAX_SESSION_TIMEOUT_DURATION = 60 // in minutes

// ConsoleCmd represents the cloud credentials command
var ConsoleCmd = &cobra.Command{
Use: "console [CLUSTERID|EXTERNAL_ID|CLUSTER_NAME|CLUSTER_NAME_SEARCH]",
Expand Down Expand Up @@ -74,6 +79,12 @@ func init() {
"text",
"Format the output of the console response.",
)
flags.IntVar(
&consoleArgs.sessionDurationMinutes,
"session-duration-minutes",
0,
"Duration in minutes for the cloud console session to remain active (cannot exceed underlying STS credential expiration 60m, default 15m).",
)
}

func runConsole(cmd *cobra.Command, argv []string) (err error) {
Expand Down Expand Up @@ -126,6 +137,17 @@ func runConsole(cmd *cobra.Command, argv []string) (err error) {
backplaneConfiguration.URL = consoleArgs.backplaneURL
}

// Only evaluate if the session duration is greater than the default of 15 minutes
// The default does not need to be configured anywhere
if consoleArgs.sessionDurationMinutes > 15 {
if consoleArgs.sessionDurationMinutes > MAX_SESSION_TIMEOUT_DURATION {
logger.Warnf("Session duration cannot exceed %d minutes, setting to maximum of %d minutes", MAX_SESSION_TIMEOUT_DURATION, MAX_SESSION_TIMEOUT_DURATION)
backplaneConfiguration.SessionDurationMinutes = MAX_SESSION_TIMEOUT_DURATION
} else {
backplaneConfiguration.SessionDurationMinutes = consoleArgs.sessionDurationMinutes
}
}

logger.Infof("Using backplane URL: %s\n", backplaneConfiguration.URL)

// Initialize OCM connection
Expand Down
17 changes: 16 additions & 1 deletion pkg/awsutil/sts.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io"
"net/http"
"net/url"
"strconv"
"time"

logger "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -82,6 +83,9 @@ func AssumeRoleWithJWT(jwt string, roleArn string, stsClient stscreds.AssumeRole
IdentityTokenValue(jwt),
func(options *stscreds.WebIdentityRoleOptions) {
options.RoleSessionName = email
// Explicitly request a 60 minute session duration
// it is the default, but being explicit here for clarity
options.Duration = 60 * time.Minute
},
))

Expand All @@ -102,6 +106,9 @@ func AssumeRole(
) (aws.Credentials, error) {
assumeRoleProvider := stscreds.NewAssumeRoleProvider(stsClient, roleArn, func(options *stscreds.AssumeRoleOptions) {
options.RoleSessionName = roleSessionName
// Explicitly request a 60 minute session duration
// it is the default, but being explicit here for clarity
options.Duration = 60 * time.Minute
if inlinePolicy != nil {
options.Policy = aws.String(inlinePolicy.String())
}
Expand Down Expand Up @@ -259,12 +266,20 @@ func GetSigninToken(awsCredentials aws.Credentials, region string) (*AWSSigninTo
return &resp, nil
}

func GetConsoleURL(signinToken string, region string) (*url.URL, error) {
func GetConsoleURL(signinToken string, region string, sessionDurationMinutes int) (*url.URL, error) {
signinParams := url.Values{}
signinParams.Add("Action", "login")
signinParams.Add("Destination", fmt.Sprintf(AwsConsoleURLTemplate, region))
signinParams.Add("Issuer", DefaultIssuer)
signinParams.Add("SigninToken", signinToken)
// Only include parameter if session duration is greater than AWS default of 15 minutes
// Explicitly set console session duration to requested time.
// This controls how long the federated console session remains active
// independent of the underlying STS credential expiration (cannot exceed 60 minutes)
if sessionDurationMinutes > 15 && sessionDurationMinutes <= 60 {
logger.Infof("sesstion_duration: %d minutes", sessionDurationMinutes)
signinParams.Add("SessionDuration", strconv.Itoa(sessionDurationMinutes*60))
}

signInFederationURL, err := url.Parse(fmt.Sprintf(AwsFederatedSigninEndpointTemplate, region))
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/awsutil/sts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ func TestGetConsoleUrl(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := GetConsoleURL(tt.signinToken, "us-east-1")
got, err := GetConsoleURL(tt.signinToken, "us-east-1", 0)
if (err != nil) != tt.wantErr {
t.Errorf("GetConsoleURL() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
1 change: 1 addition & 0 deletions pkg/cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type BackplaneConfiguration struct {
DisplayClusterInfo bool `json:"display-cluster-info"`
DisableKubePS1Warning bool `json:"disable-kube-ps1-warning"`
Govcloud bool `json:"govcloud"`
SessionDurationMinutes int `json:"session-duration-minutes"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shall we set up a default value for the SessionDurationMinutes ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I rely on default of 0 with the logic. I made it simpler realying on the fact that default in AWS is 15 minutes, and we want to input larger times, not smaller.

Should be much clearer now.

}

const (
Expand Down