Skip to content

Commit

Permalink
feat(timeout): Implement customizable timeout for Azure CLI token ret…
Browse files Browse the repository at this point in the history
…rieval in kubelogin

This commit introduces the ability to specify a custom timeout for Azure CLI token retrieval within the kubelogin package. The `AzureCLIToken` struct now includes a `timeout` field, allowing users to set a specific timeout duration.
  • Loading branch information
Aricg authored and Aric Gardner committed Nov 17, 2023
1 parent 369f19a commit d8cd938
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 23 deletions.
11 changes: 10 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@ package main
import (
"flag"
"os"
"time"

"github.com/Azure/kubelogin/pkg/cmd"
"github.com/spf13/pflag"
klog "k8s.io/klog/v2"
)

var timeoutDuration time.Duration

func main() {
klog.InitFlags(nil)

flag.DurationVar(&timeoutDuration, "timeout", 10*time.Second, "Timeout duration for Azure CLI token requests")

pflag.CommandLine.AddGoFlag(flag.CommandLine.Lookup("v"))
pflag.CommandLine.AddGoFlag(flag.CommandLine.Lookup("logtostderr"))
pflag.CommandLine.AddGoFlag(flag.CommandLine.Lookup("timeout"))
_ = pflag.CommandLine.Set("logtostderr", "true")
root := cmd.NewRootCmd(v.String())
pflag.Parse()

root := cmd.NewRootCmd(v.String(), timeoutDuration)
if err := root.Execute(); err != nil {
os.Exit(1)
}
Expand Down
6 changes: 4 additions & 2 deletions pkg/cmd/convert.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package cmd

import (
"time"

"github.com/Azure/kubelogin/pkg/converter"
"github.com/spf13/cobra"
"k8s.io/client-go/tools/clientcmd"
)

// NewConvertCmd provides a cobra command for convert sub command
func NewConvertCmd() *cobra.Command {
o := converter.New()
func NewConvertCmd(timeout time.Duration) *cobra.Command {
o := converter.New(timeout)

cmd := &cobra.Command{
Use: "convert-kubeconfig",
Expand Down
8 changes: 5 additions & 3 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package cmd

import (
"time"

"github.com/spf13/cobra"
)

// NewRootCmd provides a cobra root command
func NewRootCmd(version string) *cobra.Command {
func NewRootCmd(version string, timeout time.Duration) *cobra.Command {

cmd := &cobra.Command{
Use: "kubelogin",
Expand All @@ -17,8 +19,8 @@ func NewRootCmd(version string) *cobra.Command {
},
}

cmd.AddCommand(NewConvertCmd())
cmd.AddCommand(NewTokenCmd())
cmd.AddCommand(NewConvertCmd(timeout))
cmd.AddCommand(NewTokenCmd(timeout))
cmd.AddCommand(NewRemoveTokenCacheCmd())

return cmd
Expand Down
9 changes: 6 additions & 3 deletions pkg/cmd/token.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package cmd

import (
"time"

"github.com/Azure/kubelogin/pkg/token"
"github.com/spf13/cobra"
)

// NewTokenCmd provides a cobra command for convert sub command
func NewTokenCmd() *cobra.Command {
o := token.NewOptions()
// NewTokenCmd provides a cobra command for the get-token sub command
func NewTokenCmd(timeout time.Duration) *cobra.Command {
// Updated to pass the timeout directly to NewOptions
o := token.NewOptions(timeout)

cmd := &cobra.Command{
Use: "get-token",
Expand Down
9 changes: 6 additions & 3 deletions pkg/converter/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package converter

import (
"fmt"
"time"

"github.com/Azure/kubelogin/pkg/token"
"github.com/spf13/pflag"
Expand All @@ -19,15 +20,17 @@ type Options struct {

func stringptr(str string) *string { return &str }

func New() Options {
func New(timeout time.Duration) Options {
configFlags := &genericclioptions.ConfigFlags{
KubeConfig: stringptr(""),
}
return Options{configFlags: configFlags}
return Options{
configFlags: configFlags,
TokenOptions: token.NewOptions(timeout),
}
}

func (o *Options) AddFlags(fs *pflag.FlagSet) {
o.TokenOptions = token.NewOptions()
if cf, ok := o.configFlags.(*genericclioptions.ConfigFlags); ok {
cf.AddFlags(fs)
}
Expand Down
19 changes: 16 additions & 3 deletions pkg/token/azurecli.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"strconv"
"time"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
Expand All @@ -15,18 +16,26 @@ import (
type AzureCLIToken struct {
resourceID string
tenantID string
timeout time.Duration
}

const defaultTimeout = 30 * time.Second

// newAzureCLIToken returns a TokenProvider that will fetch a token for the user currently logged into the Azure CLI.
// Required arguments include an oAuthConfiguration object and the resourceID (which is used as the scope)
func newAzureCLIToken(resourceID string, tenantID string) (TokenProvider, error) {
func newAzureCLIToken(resourceID string, tenantID string, timeout time.Duration) (TokenProvider, error) {
if resourceID == "" {
return nil, errors.New("resourceID cannot be empty")
}

if timeout <= 0 {
timeout = defaultTimeout
}

return &AzureCLIToken{
resourceID: resourceID,
tenantID: tenantID,
timeout: timeout,
}, nil
}

Expand All @@ -42,11 +51,15 @@ func (p *AzureCLIToken) Token() (adal.Token, error) {
return emptyToken, fmt.Errorf("unable to create credential. Received: %v", err)
}

// Use the token provider to get a new token
cliAccessToken, err := cred.GetToken(context.Background(), policy.TokenRequestOptions{Scopes: []string{p.resourceID}})
ctx, cancel := context.WithTimeout(context.Background(), p.timeout)
defer cancel()

// Use the token provider to get a new token with the new context
cliAccessToken, err := cred.GetToken(ctx, policy.TokenRequestOptions{Scopes: []string{p.resourceID}})
if err != nil {
return emptyToken, fmt.Errorf("expected an empty error but received: %v", err)
}

if cliAccessToken.Token == "" {
return emptyToken, errors.New("did not receive a token")
}
Expand Down
4 changes: 3 additions & 1 deletion pkg/token/azurecli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package token

import (
"testing"
"time"

"github.com/Azure/kubelogin/pkg/testutils"
)

func TestNewAzureCLITokenEmpty(t *testing.T) {
_, err := newAzureCLIToken("", "")
// Using default timeout for testing
_, err := newAzureCLIToken("", "", defaultTimeout)

if !testutils.ErrorContains(err, "resourceID cannot be empty") {
t.Errorf("unexpected error: %v", err)
Expand Down
15 changes: 9 additions & 6 deletions pkg/token/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"strings"
"time"

"github.com/spf13/pflag"
"k8s.io/client-go/util/homedir"
Expand All @@ -22,6 +23,7 @@ type Options struct {
TenantID string
Environment string
IsLegacy bool
Timeout time.Duration
TokenCacheDir string
tokenCacheFile string
IdentityResourceID string
Expand Down Expand Up @@ -85,12 +87,13 @@ func GetSupportedLogins() string {
return strings.Join(supportedLogin, ", ")
}

func NewOptions() Options {
return Options{
LoginMethod: DeviceCodeLogin,
Environment: defaultEnvironmentName,
TokenCacheDir: DefaultTokenCacheDir,
}
func NewOptions(timeout time.Duration) Options {
return Options{
LoginMethod: DeviceCodeLogin,
Environment: defaultEnvironmentName,
TokenCacheDir: DefaultTokenCacheDir,
Timeout: timeout,
}
}

func (o *Options) AddFlags(fs *pflag.FlagSet) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/token/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func newTokenProvider(o *Options) (TokenProvider, error) {
case MSILogin:
return newManagedIdentityToken(o.ClientID, o.IdentityResourceID, o.ServerID)
case AzureCLILogin:
return newAzureCLIToken(o.ServerID, o.TenantID)
return newAzureCLIToken(o.ServerID, o.TenantID, defaultTimeout)
case WorkloadIdentityLogin:
return newWorkloadIdentityToken(o.ClientID, o.FederatedTokenFile, o.AuthorityHost, o.ServerID, o.TenantID)
}
Expand Down

0 comments on commit d8cd938

Please sign in to comment.