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

Use gcloud oauth token before trying application default credentials #198

Merged
merged 3 commits into from
Aug 9, 2018

Conversation

hfwang
Copy link
Contributor

@hfwang hfwang commented Aug 8, 2018

gcloud and application default credentials use different GCP projects for API quota purposes. Generally for development, or if customers want to use their own credentials for audit logging purposes, we want customers to use the auth token that is setup with gcloud auth login, and in particular we want to recommend that application default credentials be associated with service accounts as opposed to personal identities.

There are a couple of changes to how we detect and use the gcloud active project in this PR as well:

  • Use LookupPath to determine if gcloud is not in the path instead of looking for an error message in the string
  • Detect the case where gcloud is set up, but has no active project
  • Add support for windows, where the gcloud command is gcloud.cmd
  • Errors when invoking gcloud to get the active project immediately exit instead of setting sentinel values for later.

@hfwang hfwang requested a review from easwars August 8, 2018 01:52
… before trying application default credentials.
cmd.Stdout = buf

if err := cmd.Run(); err != nil {
if strings.Contains(err.Error(), "executable file not found") {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you still need this check, given that you have already called exec.LookPath()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I initially figured it was easier to leave it in place. But it feels like its more likely to hide bugs in the future, so removing it...

}

data := &GcloudConfigData{}

Copy link
Contributor

Choose a reason for hiding this comment

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

Nix newline.

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

"golang.org/x/oauth2"
)

// GcloudConfigData represents the data returned by `gcloud config config-helper`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the format of this output can change anytime, is there something that we can do to guard against that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this case, the gcloud config config-helper is effectively a supported API, so luckily we can depend on the format of the output.

)

type GcloudError struct {
GcloudError error
Copy link
Contributor

Choose a reason for hiding this comment

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

Do these two members need to be exported? Could we instead have a Status() method on the GcloudError type which returns the status. I don't see the underlying error object directly used anywhere.

data := &GcloudConfigData{}

if err := json.Unmarshal(buf.Bytes(), data); err != nil {
logging.Errorf("Failed to unmarshal bytes from gcloud: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

There's a tott about logging errors or returning them, not both. It's called like "contextful logs", and suggests annotating errors you return rather than printing and returning errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, agreed.

In this case this function is an extraction of the function that invoked gcloud before, so I left the logging/return error behavior as is.

hfwang added 2 commits August 8, 2018 23:28
The intent here is that its likely reasonable for individuals to run the proxy, but if they are using the proxy as a library, we do still want to encourage them to use a service account, since that is more reliable for production configurations
@hfwang
Copy link
Contributor Author

hfwang commented Aug 9, 2018

Submitting

@hfwang hfwang merged commit ec8f5ac into GoogleCloudPlatform:master Aug 9, 2018
}

buf := new(bytes.Buffer)
cmd := exec.Command(gcloudCmd, "--format", "json", "config", "config-helper")
Copy link

Choose a reason for hiding this comment

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

Found some issue of this.

This gcloud command doesn't seem to respect GOOGLE_APPLICATION_CREDENTIALS. I have Google Cloud SDK 221.0.0.

So assuming the following setup: user starts the proxy in GCE/GKE with GOOGLE_APPLICATION_CREDENTIALS set and that points to a service account in a different project; user does not use -credential_file because according to https://cloud.google.com/sql/docs/mysql/sql-proxy#environment, it is identical to supplying a credential file on the command line. However in this case GCE default service account will be used to start the proxy and it may not have proper permission of the cloud sql instance.

Either this is an unintended result, or documentation needs to be adapted.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was unintended, but I'll update the documentation instead of reverting it.

Copy link

Choose a reason for hiding this comment

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

It seems the order described in doc is still not reflecting code:

Credentials supplied in the proxy invocation command
Credentials supplied by the local environment
Credentials associated with the Compute Engine instance
Credentials from an authenticated Cloud SDK client

Choose a reason for hiding this comment

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

We've just hit the same bug @honnix is talking about. I was about to raise an issue for it as it caused us quite a bit of time loss to figure out what was going on. Especially as in our scenario we cloud_sql_proxy first then about 2 seconds later in another command we're doing gcloud auth login, but that still seems to impact and cause the proxy to fail

Copy link
Contributor

Choose a reason for hiding this comment

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

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.

6 participants