Skip to content

Commit dc9f5cd

Browse files
chore: deprecate unsafe loads & client options, add warnings to risky methods (#2134)
* deprecate unsafe methods, add warnings to risky credential types, and update README instructions * remove message added in prev commit; it is not strictly required here. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * fix(docs): update README with secure credential loading example Updates .readme-partials.yaml with the secure JWT constructor example for loading credentials from environment variables. This resolves a Windy Eagle vulnerability mitigation concern and adheres to the synthtool workflow for documentation. * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * deprecate unsafe client options --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent 7f66dd1 commit dc9f5cd

File tree

5 files changed

+155
-16
lines changed

5 files changed

+155
-16
lines changed

.readme-partials.yaml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ body: |-
253253
The parameters for the JWT auth client including how to use it with a `.pem` file are explained in [samples/jwt.js](https://github.com/googleapis/google-auth-library-nodejs/blob/main/samples/jwt.js).
254254
255255
#### Loading credentials from environment variables
256-
Instead of loading credentials from a key file, you can also provide them using an environment variable and the `GoogleAuth.fromJSON()` method. This is particularly convenient for systems that deploy directly from source control (Heroku, App Engine, etc).
256+
Instead of loading credentials from a key file, you can also provide them using an environment variable. This is particularly convenient for systems that deploy directly from source control (Heroku, App Engine, etc).
257257
258258
Start by exporting your credentials:
259259
@@ -274,7 +274,7 @@ body: |-
274274
Now you can create a new client from the credentials:
275275
276276
```js
277-
const {auth} = require('google-auth-library');
277+
const {JWT} = require('google-auth-library');
278278
279279
// load the environment variable with our keys
280280
const keysEnvVar = process.env['CREDS'];
@@ -283,9 +283,12 @@ body: |-
283283
}
284284
const keys = JSON.parse(keysEnvVar);
285285
286-
// load the JWT or UserRefreshClient from the keys
287-
const client = auth.fromJSON(keys);
288-
client.scopes = ['https://www.googleapis.com/auth/cloud-platform'];
286+
// create a JWT client
287+
const client = new JWT({
288+
email: keys.client_email,
289+
key: keys.private_key,
290+
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
291+
});
289292
const url = `https://dns.googleapis.com/dns/v1/projects/${keys.project_id}`;
290293
const res = await client.fetch(url);
291294
console.log(res.data);

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ console.log(res.data);
297297
The parameters for the JWT auth client including how to use it with a `.pem` file are explained in [samples/jwt.js](https://github.com/googleapis/google-auth-library-nodejs/blob/main/samples/jwt.js).
298298

299299
#### Loading credentials from environment variables
300-
Instead of loading credentials from a key file, you can also provide them using an environment variable and the `GoogleAuth.fromJSON()` method. This is particularly convenient for systems that deploy directly from source control (Heroku, App Engine, etc).
300+
Instead of loading credentials from a key file, you can also provide them using an environment variable. This is particularly convenient for systems that deploy directly from source control (Heroku, App Engine, etc).
301301

302302
Start by exporting your credentials:
303303

@@ -318,7 +318,7 @@ $ export CREDS='{
318318
Now you can create a new client from the credentials:
319319

320320
```js
321-
const {auth} = require('google-auth-library');
321+
const {JWT} = require('google-auth-library');
322322

323323
// load the environment variable with our keys
324324
const keysEnvVar = process.env['CREDS'];
@@ -327,9 +327,12 @@ if (!keysEnvVar) {
327327
}
328328
const keys = JSON.parse(keysEnvVar);
329329

330-
// load the JWT or UserRefreshClient from the keys
331-
const client = auth.fromJSON(keys);
332-
client.scopes = ['https://www.googleapis.com/auth/cloud-platform'];
330+
// create a JWT client
331+
const client = new JWT({
332+
email: keys.client_email,
333+
key: keys.private_key,
334+
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
335+
});
333336
const url = `https://dns.googleapis.com/dns/v1/projects/${keys.project_id}`;
334337
const res = await client.fetch(url);
335338
console.log(res.data);

src/auth/externalclient.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ export class ExternalAccountClient {
5757
* This static method will instantiate the
5858
* corresponding type of external account credential depending on the
5959
* underlying credential source.
60+
*
61+
* **IMPORTANT**: This method does not validate the credential configuration.
62+
* A security risk occurs when a credential configuration configured with
63+
* malicious URLs is used. When the credential configuration is accepted from
64+
* an untrusted source, you should validate it before using it with this
65+
* method. For more details, see
66+
* https://cloud.google.com/docs/authentication/external/externally-sourced-credentials.
67+
*
6068
* @param options The external account options object typically loaded
6169
* from the external account JSON credential file.
6270
* @return A BaseExternalAccountClient instance or null if the options

src/auth/googleauth.ts

Lines changed: 124 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,33 @@ export interface GoogleAuthOptions<T extends AuthClient = AnyAuthClient> {
8484
*/
8585
authClient?: T;
8686
/**
87-
* Path to a .json, .pem, or .p12 key file
87+
* @deprecated This option is being deprecated because of a potential security risk.
88+
*
89+
* This option does not validate the credential configuration. The security
90+
* risk occurs when a credential configuration is accepted from a source that
91+
* is not under your control and used without validation on your side.
92+
*
93+
* The recommended way to provide credentials is to create an `auth` object
94+
* using `google-auth-library` and pass it to the client constructor.
95+
* This will ensure that unexpected credential types with potential for
96+
* malicious intent are not loaded unintentionally. For example:
97+
* ```
98+
* const {GoogleAuth} = require('google-auth-library');
99+
* const auth = new GoogleAuth({
100+
* // Scopes can be specified either as an array or as a single, space-delimited string.
101+
* scopes: 'https://www.googleapis.com/auth/cloud-platform'
102+
* });
103+
* const client = new MyClient({ auth: auth });
104+
* ```
105+
*
106+
* If you are loading your credential configuration from an untrusted source and have
107+
* not mitigated the risks (e.g. by validating the configuration yourself), make
108+
* these changes as soon as possible to prevent security risks to your environment.
109+
*
110+
* Regardless of the method used, it is always your responsibility to validate
111+
* configurations received from external sources.
112+
*
113+
* For more details, see https://cloud.google.com/docs/authentication/external/externally-sourced-credentials.
88114
*/
89115
keyFilename?: string;
90116

@@ -94,13 +120,33 @@ export interface GoogleAuthOptions<T extends AuthClient = AnyAuthClient> {
94120
keyFile?: string;
95121

96122
/**
97-
* Object containing client_email and private_key properties, or the
98-
* external account client options.
99-
* Cannot be used with {@link GoogleAuthOptions.apiKey `apiKey`}.
123+
* @deprecated This option is being deprecated because of a potential security risk.
100124
*
101-
* @remarks
125+
* This option does not validate the credential configuration. The security
126+
* risk occurs when a credential configuration is accepted from a source that
127+
* is not under your control and used without validation on your side.
102128
*
103-
* **Important**: If you accept a credential configuration (credential JSON/File/Stream) from an external source for authentication to Google Cloud, you must validate it before providing it to any Google API or library. Providing an unvalidated credential configuration to Google APIs can compromise the security of your systems and data. For more information, refer to {@link https://cloud.google.com/docs/authentication/external/externally-sourced-credentials Validate credential configurations from external sources}.
129+
* The recommended way to provide credentials is to create an `auth` object
130+
* using `google-auth-library` and pass it to the client constructor.
131+
* This will ensure that unexpected credential types with potential for
132+
* malicious intent are not loaded unintentionally. For example:
133+
* ```
134+
* const {GoogleAuth} = require('google-auth-library');
135+
* const auth = new GoogleAuth({
136+
* // Scopes can be specified either as an array or as a single, space-delimited string.
137+
* scopes: 'https://www.googleapis.com/auth/cloud-platform'
138+
* });
139+
* const client = new MyClient({ auth: auth });
140+
* ```
141+
*
142+
* If you are loading your credential configuration from an untrusted source and have
143+
* not mitigated the risks (e.g. by validating the configuration yourself), make
144+
* these changes as soon as possible to prevent security risks to your environment.
145+
*
146+
* Regardless of the method used, it is always your responsibility to validate
147+
* configurations received from external sources.
148+
*
149+
* For more details, see https://cloud.google.com/docs/authentication/external/externally-sourced-credentials.
104150
*/
105151
credentials?: JWTInput | ExternalAccountClientOptions;
106152

@@ -654,6 +700,38 @@ export class GoogleAuth<T extends AuthClient = AuthClient> {
654700
*
655701
* **Important**: If you accept a credential configuration (credential JSON/File/Stream) from an external source for authentication to Google Cloud, you must validate it before providing it to any Google API or library. Providing an unvalidated credential configuration to Google APIs can compromise the security of your systems and data. For more information, refer to {@link https://cloud.google.com/docs/authentication/external/externally-sourced-credentials Validate credential configurations from external sources}.
656702
*
703+
* @deprecated This method is being deprecated because of a potential security risk.
704+
*
705+
* This method does not validate the credential configuration. The security
706+
* risk occurs when a credential configuration is accepted from a source that
707+
* is not under your control and used without validation on your side.
708+
*
709+
* If you know that you will be loading credential configurations of a
710+
* specific type, it is recommended to use a credential-type-specific
711+
* constructor. This will ensure that an unexpected credential type with
712+
* potential for malicious intent is not loaded unintentionally. You might
713+
* still have to do validation for certain credential types. Please follow
714+
* the recommendation for that method. For example, if you want to load only
715+
* service accounts, you can use the `JWT` constructor:
716+
* ```
717+
* const {JWT} = require('google-auth-library');
718+
* const keys = require('/path/to/key.json');
719+
* const client = new JWT({
720+
* email: keys.client_email,
721+
* key: keys.private_key,
722+
* scopes: ['https://www.googleapis.com/auth/cloud-platform'],
723+
* });
724+
* ```
725+
*
726+
* If you are loading your credential configuration from an untrusted source and have
727+
* not mitigated the risks (e.g. by validating the configuration yourself), make
728+
* these changes as soon as possible to prevent security risks to your environment.
729+
*
730+
* Regardless of the method used, it is always your responsibility to validate
731+
* configurations received from external sources.
732+
*
733+
* For more details, see https://cloud.google.com/docs/authentication/external/externally-sourced-credentials.
734+
*
657735
* @param json The input object.
658736
* @param options The JWT or UserRefresh options for the client
659737
* @returns JWT or UserRefresh Client with data
@@ -719,6 +797,46 @@ export class GoogleAuth<T extends AuthClient = AuthClient> {
719797

720798
/**
721799
* Create a credentials instance using the given input stream.
800+
*
801+
* @deprecated This method is being deprecated because of a potential security risk.
802+
*
803+
* This method does not validate the credential configuration. The security
804+
* risk occurs when a credential configuration is accepted from a source that
805+
* is not under your control and used without validation on your side.
806+
*
807+
* If you know that you will be loading credential configurations of a
808+
* specific type, it is recommended to read and parse the stream, and then
809+
* use a credential-type-specific constructor. This will ensure that an
810+
* unexpected credential type with potential for malicious intent is not
811+
* loaded unintentionally. You might still have to do validation for certain
812+
* credential types. Please follow the recommendation for that method. For
813+
* example, if you want to load only service accounts, you can do:
814+
* ```
815+
* const {JWT} = require('google-auth-library');
816+
* const fs = require('fs');
817+
*
818+
* const stream = fs.createReadStream('path/to/key.json');
819+
* const chunks = [];
820+
* stream.on('data', (chunk) => chunks.push(chunk));
821+
* stream.on('end', () => {
822+
* const keys = JSON.parse(Buffer.concat(chunks).toString());
823+
* const client = new JWT({
824+
* email: keys.client_email,
825+
* key: keys.private_key,
826+
* scopes: ['https://www.googleapis.com/auth/cloud-platform'],
827+
* });
828+
* // use client
829+
* });
830+
* ```
831+
*
832+
* If you are loading your credential configuration from an untrusted source and have
833+
* not mitigated the risks (e.g. by validating the configuration yourself), make
834+
* these changes as soon as possible to prevent security risks to your environment.
835+
*
836+
* Regardless of the method used, it is always your responsibility to validate
837+
* configurations received from external sources.
838+
*
839+
* For more details, see https://cloud.google.com/docs/authentication/external/externally-sourced-credentials.
722840
* @param inputStream The input stream.
723841
* @param callback Optional callback.
724842
*/

src/auth/impersonated.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ export class Impersonated extends OAuth2Client implements IdTokenProvider {
9191
* Also, the target service account must grant the orginating principal
9292
* the "Service Account Token Creator" IAM role.
9393
*
94+
* **IMPORTANT**: This method does not validate the credential configuration.
95+
* A security risk occurs when a credential configuration configured with
96+
* malicious URLs is used. When the credential configuration is accepted from
97+
* an untrusted source, you should validate it before using it with this
98+
* method. For more details, see
99+
* https://cloud.google.com/docs/authentication/external/externally-sourced-credentials.
100+
*
94101
* @param {object} options - The configuration object.
95102
* @param {object} [options.sourceClient] the source credential used as to
96103
* acquire the impersonated credentials.

0 commit comments

Comments
 (0)