Skip to content

Commit

Permalink
Add credshelper flags (#579)
Browse files Browse the repository at this point in the history
Adding the credentials helper flags and using them in NewClientFromFlags
to get tokensource
  • Loading branch information
banikharbanda committed Jun 11, 2024
1 parent 2c59ceb commit 4706165
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 13 deletions.
2 changes: 1 addition & 1 deletion go/pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (a AuthType) String() string {
case NoAuth:
return "no authentication"
case ExternalTokenAuth:
return "external authentication token (gcert?)"
return "external authentication token (credentials helper)"
case CredsFileAuth:
return "credentials file"
case ApplicationDefaultCredsAuth:
Expand Down
2 changes: 1 addition & 1 deletion go/pkg/credshelper/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ go_library(
"cache.go",
],
importpath = "github.com/bazelbuild/remote-apis-sdks/go/pkg/credshelper",
visibility = ["//:__subpackages__"],
visibility = ["//visibility:public"],
deps = [
"//go/api/credshelper",
"//go/pkg/digest",
Expand Down
20 changes: 12 additions & 8 deletions go/pkg/credshelper/credshelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const (
CredshelperPathFlag = "credentials_helper"
// CredshelperArgsFlag is the flag used to pass in the arguments to the credentials helper binary.
CredshelperArgsFlag = "credentials_helper_args"
// CredsFileFlag is the flag used to pass in the path of the file where credentials should be cached.
CredsFileFlag = "creds_file"
// ExperimentalCredsCachePathFlag is the flag used to pass in the path of the file where credentials should be cached.
ExperimentalCredsCachePathFlag = "experimental_creds_cache_file"

expiryBuffer = 5 * time.Minute
)
Expand Down Expand Up @@ -95,6 +95,14 @@ type externalTokenSource struct {
headersLock sync.RWMutex
}

// TokenSource returns a token source for this credentials instance.
func (c *Credentials) TokenSource() *grpcOauth.TokenSource {
if c == nil {
return nil
}
return c.tokenSource
}

func buildExternalCredentials(baseCreds cachedCredentials, credsFile string, credsHelperCmd *reusableCmd) *Credentials {
c := &Credentials{
credsHelperCmd: credsHelperCmd,
Expand Down Expand Up @@ -168,8 +176,8 @@ func (c *Credentials) RemoveFromDisk() {
}
}

// refreshStatus checks refresh expiry of credentials in case a manual refresh is required.
func (c *Credentials) refreshStatus() error {
// RefreshStatus checks refresh expiry of credentials in case a manual refresh is required.
func (c *Credentials) RefreshStatus() error {
if !c.refreshExp.IsZero() && c.refreshExp.Before(nowFn()) {
return fmt.Errorf("credentials cannot be refreshed automatically, manual re-authentication required")
}
Expand Down Expand Up @@ -225,10 +233,6 @@ func NewExternalCredentials(credshelper string, credshelperArgs []string, credsF
return creds, nil
}
log.Warningf("Failed to use cached credentials: %v", err)
if err = creds.refreshStatus(); err != nil {
creds.RemoveFromDisk()
return nil, err
}
}
credsOut, err := runCredsHelperCmd(credsHelperCmd)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions go/pkg/credshelper/credshelper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,15 +320,15 @@ func TestGetRequestMetadata(t *testing.T) {

func TestRefreshStatus(t *testing.T) {
c := Credentials{refreshExp: time.Time{}}
if err := c.refreshStatus(); err != nil {
if err := c.RefreshStatus(); err != nil {
t.Errorf("RefreshStatus returned an error when refreshExpiry is zero")
}
c.refreshExp = time.Now().Add(time.Hour)
if err := c.refreshStatus(); err != nil {
if err := c.RefreshStatus(); err != nil {
t.Errorf("RefreshStatus returned an error when refreshExpiry has not passed")
}
c.refreshExp = time.Now().Add(-time.Hour)
if err := c.refreshStatus(); err == nil {
if err := c.RefreshStatus(); err == nil {
t.Errorf("RefreshStatus did not return an error when refreshExpiry when it has passed")
}
}
Expand Down
1 change: 1 addition & 0 deletions go/pkg/flags/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//go/pkg/client",
"//go/pkg/credshelper",
"//go/pkg/moreflag",
"@com_github_golang_glog//:glog",
"@org_golang_google_grpc//:go_default_library",
Expand Down
16 changes: 16 additions & 0 deletions go/pkg/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ package flags
import (
"context"
"flag"
"fmt"
"strings"
"time"

"github.com/bazelbuild/remote-apis-sdks/go/pkg/client"
"github.com/bazelbuild/remote-apis-sdks/go/pkg/credshelper"
"github.com/bazelbuild/remote-apis-sdks/go/pkg/moreflag"
"google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
Expand Down Expand Up @@ -34,6 +37,12 @@ var (
// UseGCECredentials is whether to use the default GCE credentials to authenticate with remote
// execution. --use_application_default_credentials must be false.
UseGCECredentials = flag.Bool("use_gce_credentials", false, "If true (and --use_application_default_credentials is false), use the default GCE credentials to authenticate with remote execution.")
// CredentialsHelper specifies a path to a credentials helper binary which should be used to fetch credentials.
CredentialsHelper = flag.String(credshelper.CredshelperPathFlag, "", "Path to the credentials helper binary. If given execrell://, looks for the `credshelper` binary in the same folder as the current executable.")
// CredentialsHelperArgs specifies arguments for the credentials helper binary,
CredentialsHelperArgs = flag.String(credshelper.CredshelperArgsFlag, "", "Arguments for the credentials helper, separated by space.")
// CredsCache specifies the file path where credentials recieved from the credentials helper are cached. If no file is provided then no credentials are cached.
CredsCache = flag.String(credshelper.ExperimentalCredsCachePathFlag, "", "Path of the file where credentials should be cached. Credentials are not cached if no file path is provided.")
// UseRPCCredentials can be set to false to disable all per-RPC credentials.
UseRPCCredentials = flag.Bool("use_rpc_credentials", true, "If false, no per-RPC credentials will be used (disables --credential_file, --use_application_default_credentials, and --use_gce_credentials.")
// UseExternalAuthToken specifies whether to use an externally provided auth token, given via PerRPCCreds dial option, should be used.
Expand Down Expand Up @@ -109,6 +118,13 @@ func NewClientFromFlags(ctx context.Context, opts ...client.Opt) (*client.Client
tOpts = append(tOpts, opt)
}
}
if *CredentialsHelper != "" && perRPCCreds == nil {
creds, err := credshelper.NewExternalCredentials(*CredentialsHelper, strings.Fields(*CredentialsHelperArgs), *CredsCache)
if err != nil {
return nil, fmt.Errorf("credentials helper failed. Please try again or use another method of authentication:%v", err)
}
perRPCCreds = &client.PerRPCCreds{Creds: creds.TokenSource()}
}
opts = tOpts

dialOpts := make([]grpc.DialOption, 0)
Expand Down

0 comments on commit 4706165

Please sign in to comment.