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!: workload identity federation support #1131

Merged
merged 27 commits into from
Feb 6, 2021
Merged

feat!: workload identity federation support #1131

merged 27 commits into from
Feb 6, 2021

Conversation

bojeil-google
Copy link
Contributor

Using workload identity federation, applications can access Google Cloud resources from Amazon Web Services (AWS), Microsoft Azure or any identity provider that supports OpenID Connect (OIDC). Workload identity federation is recommended for non-Google Cloud environments as it avoids the need to download, manage and store service account private keys locally.

bojeil-google and others added 20 commits August 6, 2020 17:06
…#1022)

This defines internal utilities to handle:
- OAuth client authentication
- Standard OAuth response parsing into native Javascript errors.
@bojeil-google bojeil-google requested a review from a team as a code owner February 3, 2021 00:56
@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Feb 3, 2021
@codecov
Copy link

codecov bot commented Feb 3, 2021

Codecov Report

Merging #1131 (3c36a1b) into master (02d0d73) will increase coverage by 2.09%.
The diff coverage is 97.75%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1131      +/-   ##
==========================================
+ Coverage   91.65%   93.74%   +2.09%     
==========================================
  Files          21       28       +7     
  Lines        4157     6253    +2096     
  Branches      430      654     +224     
==========================================
+ Hits         3810     5862    +2052     
- Misses        347      391      +44     
Impacted Files Coverage Δ
src/crypto/browser/crypto.ts 30.69% <31.66%> (-0.08%) ⬇️
src/auth/identitypoolclient.ts 98.63% <98.63%> (ø)
src/auth/oauth2common.ts 98.68% <98.68%> (ø)
src/auth/googleauth.ts 97.61% <98.82%> (+0.26%) ⬆️
src/auth/authclient.ts 100.00% <100.00%> (ø)
src/auth/awsclient.ts 100.00% <100.00%> (ø)
src/auth/awsrequestsigner.ts 100.00% <100.00%> (ø)
src/auth/baseexternalclient.ts 100.00% <100.00%> (ø)
src/auth/externalclient.ts 100.00% <100.00%> (ø)
src/auth/stscredentials.ts 100.00% <100.00%> (ø)
... and 12 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 02d0d73...dfb68ea. Read the comment docs.

@@ -363,6 +366,213 @@ async function main() {
main().catch(console.error);
```

## Workload Identity Federation
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a massive addition to the README, and I worry a little about the size. I am ok keeping it here for now (non-blocking feedback), but we need a better documentation strategy for auth. @tbpg

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bcoe also pointed out the same issue which I agree with. There are larger plans to update the official authentication docs: https://cloud.google.com/docs/authentication. Though this could be delayed until Q3. Currently, they are only updating the workload identity federation docs:

It would be a good idea to align with the overall documentation effort in the cloud docs and the GitHub repos.

package.json Outdated Show resolved Hide resolved
* @param {number} length The length of the string to generate.
* @return {string} A random string of the provided length.
*/
const generateRandomString = length => {
Copy link
Contributor

Choose a reason for hiding this comment

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

As a general rule, I try to avoid mutating a variable passed into a function. Since this is a primitive I think? it's passed by value and shouldn't matter, but a for loop is generally easier to rationalize. Also, why wouldn't this be a regular function?

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:

  • Used regular function.
  • Used for loop.
  • Stopped mutating input variable.

scopes: 'https://www.googleapis.com/auth/cloud-platform',
});

// TODO: switch to using IAM client SDK once v1 API has all the v1beta
Copy link
Contributor

Choose a reason for hiding this comment

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

Please make sure we're filing issues on GitHub for any TODOs so we don't lose them.

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: #1132

package.json Outdated Show resolved Hide resolved
@@ -84,6 +84,7 @@
"fix": "gts fix",
"pretest": "npm run compile",
"docs": "compodoc src/",
"samples-setup": "cd samples/ && npm link ../ && npm run setup && cd ../",
Copy link
Contributor

Choose a reason for hiding this comment

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

this seems like a reasonable addition to the script, presumably so that you could setup the sample environment outside of running tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes that is correct. This is very useful if you want to set up the sample environment in a different project or locally.

@bcoe bcoe requested a review from JustinBeckwith February 5, 2021 01:07

/**
* The main authentication interface. It takes an optional url which when
* present is the endpoint> being accessed, and returns a Promise which
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: extra >

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

export interface AwsClientOptions extends BaseExternalAccountClientOptions {
credential_source: {
environment_id: string;
// Region can also be determine from the AWS_REGION environment variable.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: be determined

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

private getProjectNumber(audience: string): string | null {
// STS audience pattern:
// //iam.googleapis.com/projects/$PROJECT_NUMBER/locations/...
const components = audience.split('/');
Copy link
Contributor

Choose a reason for hiding this comment

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

[style] I would prefer a simple regex here:

const match = audience.match(/^\/\/iam.googleapis.com\/projects\/([^\/]+)/);
if (!match) {
  return null;
}
return match[1];

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

* Gets the project ID from external account client if available.
*/
private async getExternalAccountClientProjectId(): Promise<string | null> {
if (this.jsonContent && this.jsonContent.type === EXTERNAL_ACCOUNT_TYPE) {
Copy link
Contributor

Choose a reason for hiding this comment

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

[style, optional] invert the condition to reduce nesting of the code

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

this.formatType,
this.formatSubjectTokenFieldName
);
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

else not needed.

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

try {
// Resolve path to actual file in case of symlink. Expect a thrown error
// if not resolvable.
filePath = fs.realpathSync(filePath);
Copy link
Contributor

Choose a reason for hiding this comment

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

using sync fs API in an async function does not seem right. On a network filesystem, these calls can block for considerable amount of time. Can we replace with async API e.g. fs.realpath, fs.lstat?

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

* @param buffer The Buffer input to covert.
* @return The ArrayBuffer representation of the input.
*/
function toArrayBuffer(buffer: Buffer): ArrayBuffer {
Copy link
Contributor

Choose a reason for hiding this comment

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

I like this answer more - just slice the proper part of buffer.buffer without any iteration.

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

* @param arrayBuffer The ArrayBuffer input to covert.
* @return The Buffer representation of the input.
*/
function toBuffer(arrayBuffer: ArrayBuffer): Buffer {
Copy link
Contributor

Choose a reason for hiding this comment

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

Buffer.from(arrayBuffer) will do it

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

"SecretAccessKey" : "Y8AfSaucF37G4PpvfguKZ3/l7Id4uocLXxX0+VTx",
"Token" : "IQoJb3JpZ2luX2VjEIz//////////wEaCXVzLWVhc3QtMiJGMEQCIH7MHX/Oy/OB8OlLQa9GrqU1B914+iMikqWQW7vPCKlgAiA/Lsv8Jcafn14owfxXn95FURZNKaaphj0ykpmS+Ki+CSq0AwhlEAAaDDA3NzA3MTM5MTk5NiIMx9sAeP1ovlMTMKLjKpEDwuJQg41/QUKx0laTZYjPlQvjwSqS3OB9P1KAXPWSLkliVMMqaHqelvMF/WO/glv3KwuTfQsavRNs3v5pcSEm4SPO3l7mCs7KrQUHwGP0neZhIKxEXy+Ls//1C/Bqt53NL+LSbaGv6RPHaX82laz2qElphg95aVLdYgIFY6JWV5fzyjgnhz0DQmy62/Vi8pNcM2/VnxeCQ8CC8dRDSt52ry2v+nc77vstuI9xV5k8mPtnaPoJDRANh0bjwY5Sdwkbp+mGRUJBAQRlNgHUJusefXQgVKBCiyJY4w3Csd8Bgj9IyDV+Azuy1jQqfFZWgP68LSz5bURyIjlWDQunO82stZ0BgplKKAa/KJHBPCp8Qi6i99uy7qh76FQAqgVTsnDuU6fGpHDcsDSGoCls2HgZjZFPeOj8mmRhFk1Xqvkbjuz8V1cJk54d3gIJvQt8gD2D6yJQZecnuGWd5K2e2HohvCc8Fc9kBl1300nUJPV+k4tr/A5R/0QfEKOZL1/k5lf1g9CREnrM8LVkGxCgdYMxLQow1uTL+QU67AHRRSp5PhhGX4Rek+01vdYSnJCMaPhSEgcLqDlQkhk6MPsyT91QMXcWmyO+cAZwUPwnRamFepuP4K8k2KVXs/LIJHLELwAZ0ekyaS7CptgOqS7uaSTFG3U+vzFZLEnGvWQ7y9IPNQZ+Dffgh4p3vF4J68y9049sI6Sr5d5wbKkcbm8hdCDHZcv4lnqohquPirLiFQ3q7B17V9krMPu3mz1cg4Ekgcrn/E09NTsxAqD8NcZ7C7ECom9r+X3zkDOxaajW6hu3Az8hGlyylDaMiFfRbBJpTIlxp7jfa7CxikNgNtEKLH9iCzvuSg2vhA==",
"Expiration" : "2020-08-11T07:35:49Z"
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add \n

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

"credential_source": {
"file": "./test/fixtures/external-subject-token.txt"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

\n

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

@@ -0,0 +1,3 @@
{
"access_token": "HEADER.SIMULATED_JWT_PAYLOAD.SIGNATURE"
}
Copy link
Contributor

Choose a reason for hiding this comment

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

\n

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

Copy link
Contributor

@alexander-fenster alexander-fenster left a comment

Choose a reason for hiding this comment

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

LGTM with small nits

Copy link
Contributor Author

@bojeil-google bojeil-google left a comment

Choose a reason for hiding this comment

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

Thanks for the through review @alexander-fenster! I made all the requested changes.

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

Successfully merging this pull request may close these issues.

6 participants