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

feat(storage): SignedUrl can use existing creds to authenticate #4604

Merged
merged 33 commits into from Oct 8, 2021

Conversation

BrennaEpp
Copy link
Contributor

@BrennaEpp BrennaEpp commented Aug 12, 2021

Part of the effort to improve Signed URLs in the Go Storage Client.

Users can omit filling in GoogleAccessID, PrivateKey, and SignBytes if they are okay with default values for these.

Fixes #1130

@product-auto-label product-auto-label bot added the api: storage Issues related to the Cloud Storage API. label Aug 12, 2021
@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Aug 12, 2021
@BrennaEpp BrennaEpp marked this pull request as ready for review September 8, 2021 17:42
@BrennaEpp BrennaEpp requested a review from a team as a code owner September 8, 2021 17:42
Copy link
Contributor

@tritone tritone left a comment

Choose a reason for hiding this comment

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

Nice start on this! A few questions and comments, mainly around docs and error cases.

storage/bucket.go Show resolved Hide resolved
storage/bucket.go Show resolved Hide resolved
storage/bucket.go Outdated Show resolved Hide resolved
storage/bucket.go Outdated Show resolved Hide resolved
if len(newopts.PrivateKey) == 0 {
newopts.SignBytes = b.defaultSignBytesFunc(newopts.GoogleAccessID)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We probably want an error here if for whatever reason PrivateKey or SignBytes hasn't been populated at this point.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SignBytes should definitely be populated by b.defaultSignBytesFunc(newopts.GoogleAccessID), but I can guess an extra check wouldn't hurt?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm yeah I guess that's correct-- so then if there is an issue with signBytes, it will occur when it is called to do the signing. That seems fine. Can you verify that the error looks sensible if, for example, we don't have correct permissions and so signBytes fails?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Error if the service account email is not found by the IAM client (for example can occur if you use your email instead of a service account email or there's a typo in your email):
unable to sign bytes: googleapi: Error 404: Requested entity was not found.
This error isn't the best but it's what we receive from the IAM api: https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob

Error if the service account does not have permissions:
unable to sign bytes: googleapi: Error 403: The caller does not have permission

Error if the Service Account Credentials API is not enabled:

unable to sign bytes: googleapi: Error 403: IAM Service Account Credentials API has not been used in project 1074109021461 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/iamcredentials.googleapis.com/overview?project=1074109021461 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
Details:
[
  {
    "@type": "type.googleapis.com/google.rpc.Help",
    "links": [
      {
        "description": "Google developers console API activation",
        "url": "https://console.developers.google.com/apis/api/iamcredentials.googleapis.com/overview?project=1074109021461"
      }
    ]
  },
  {
    "@type": "type.googleapis.com/google.rpc.ErrorInfo",
    "domain": "googleapis.com",
    "metadata": {
      "consumer": "projects/1074109021461",
      "service": "iamcredentials.googleapis.com"
    },
    "reason": "SERVICE_DISABLED"
  }
]

storage/bucket.go Show resolved Hide resolved
storage/storage.go Show resolved Hide resolved
storage/bucket.go Show resolved Hide resolved
storage/integration_test.go Show resolved Hide resolved
if err != nil {
t.Fatalf("unable to find test credentials: %v", err)
}
client, err := newTestClient(ctx, option.WithCredentials(creds))
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this creds magic necessary? What happens if you run the tests with a test client as-is?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like it's fine without it as long as env variables are set correctly. @codyoss is there a reason we can't call newTestClient without passing the creds?

Copy link
Member

Choose a reason for hiding this comment

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

So here we are explicitly testing the SA use-case and signing with it IIRC. By default we are authed with a TS so don't have the context to read some of the fields from the keyfile. For completeness we could also have a test that does the iamcredentials flow where we auth like normal but set the email address field. Maybe this bit of code deserves a comment 😛

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 added a couple comments and the extra test case

@BrennaEpp BrennaEpp requested a review from a team as a code owner September 13, 2021 18:59
Copy link
Contributor

@tritone tritone left a comment

Choose a reason for hiding this comment

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

Looking good!

storage/bucket.go Show resolved Hide resolved
if len(newopts.PrivateKey) == 0 {
newopts.SignBytes = b.defaultSignBytesFunc(newopts.GoogleAccessID)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm yeah I guess that's correct-- so then if there is an issue with signBytes, it will occur when it is called to do the signing. That seems fine. Can you verify that the error looks sensible if, for example, we don't have correct permissions and so signBytes fails?

storage/bucket.go Outdated Show resolved Hide resolved
@BrennaEpp BrennaEpp requested a review from tritone October 6, 2021 17:25
Copy link
Contributor

@tritone tritone left a comment

Choose a reason for hiding this comment

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

This looks good to me. @codyoss can you give a final review before we merge?

Copy link
Member

@codyoss codyoss left a comment

Choose a reason for hiding this comment

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

LGTM!

@BrennaEpp BrennaEpp merged commit b824c89 into googleapis:master Oct 8, 2021
@mark-kubacki
Copy link

See also the Go CDK’s google/go-cloud#2800

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: storage Issues related to the Cloud Storage API. cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

storage: Make GoogleAccessID and PrivateKey optional
4 participants