Skip to content
This repository was archived by the owner on Nov 20, 2025. It is now read-only.

feat!: workload identity federation support#1131

Merged
bcoe merged 27 commits into
googleapis:masterfrom
bojeil-google:master
Feb 6, 2021
Merged

feat!: workload identity federation support#1131
bcoe merged 27 commits into
googleapis:masterfrom
bojeil-google:master

Conversation

@bojeil-google

Copy link
Copy Markdown
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 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

codecov Bot commented Feb 3, 2021

Copy link
Copy Markdown

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.

Comment thread README.md
main().catch(console.error);
```

## Workload Identity Federation

Copy link
Copy Markdown
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
Copy Markdown
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.

Comment thread package.json Outdated
Comment thread samples/scripts/externalclient-setup.js Outdated
* @param {number} length The length of the string to generate.
* @return {string} A random string of the provided length.
*/
const generateRandomString = length => {

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done: #1132

Comment thread package.json Outdated
Comment thread package.json
"fix": "gts fix",
"pretest": "npm run compile",
"docs": "compodoc src/",
"samples-setup": "cd samples/ && npm link ../ && npm run setup && cd ../",

Copy link
Copy Markdown

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
Copy Markdown
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
Comment thread browser-test/test.crypto.ts Outdated
Comment thread samples/scripts/externalclient-setup.js
Comment thread src/auth/authclient.ts Outdated

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

Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread src/auth/authclient.ts Outdated
Comment thread src/auth/awsclient.ts Outdated
export interface AwsClientOptions extends BaseExternalAccountClientOptions {
credential_source: {
environment_id: string;
// Region can also be determine from the AWS_REGION environment variable.

Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread src/auth/awsclient.ts Outdated
Comment thread src/auth/awsclient.ts Outdated
Comment thread src/auth/awsrequestsigner.ts
Comment thread src/auth/baseexternalclient.ts Outdated
Comment thread src/auth/baseexternalclient.ts Outdated
Comment thread src/auth/baseexternalclient.ts Outdated
private getProjectNumber(audience: string): string | null {
// STS audience pattern:
// //iam.googleapis.com/projects/$PROJECT_NUMBER/locations/...
const components = audience.split('/');

Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread src/auth/googleauth.ts Outdated
* 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
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread src/auth/identitypoolclient.ts Outdated
this.formatType,
this.formatSubjectTokenFieldName
);
} else {

Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread src/auth/identitypoolclient.ts Outdated
try {
// Resolve path to actual file in case of symlink. Expect a thrown error
// if not resolvable.
filePath = fs.realpathSync(filePath);

Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread src/crypto/node/crypto.ts
* @param buffer The Buffer input to covert.
* @return The ArrayBuffer representation of the input.
*/
function toArrayBuffer(buffer: Buffer): ArrayBuffer {

Copy link
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread src/crypto/node/crypto.ts
* @param arrayBuffer The ArrayBuffer input to covert.
* @return The Buffer representation of the input.
*/
function toBuffer(arrayBuffer: ArrayBuffer): Buffer {

Copy link
Copy Markdown
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
Copy Markdown
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"
} No newline at end of file

Copy link
Copy Markdown
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
Copy Markdown
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"
}
} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

\n

Copy link
Copy Markdown
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"
} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

\n

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

@alexander-fenster alexander-fenster left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM with small nits

@bojeil-google bojeil-google left a comment

Copy link
Copy Markdown
Contributor Author

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 subscribe to this conversation on GitHub. Already have an account? Sign in.

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