UNPKG

google-auth-library

Version:
197 lines (196 loc) 11.2 kB
"use strict"; // Copyright 2024 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _DefaultAwsSecurityCredentialsSupplier_instances, _DefaultAwsSecurityCredentialsSupplier_getImdsV2SessionToken, _DefaultAwsSecurityCredentialsSupplier_getAwsRoleName, _DefaultAwsSecurityCredentialsSupplier_retrieveAwsSecurityCredentials, _DefaultAwsSecurityCredentialsSupplier_regionFromEnv_get, _DefaultAwsSecurityCredentialsSupplier_securityCredentialsFromEnv_get; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultAwsSecurityCredentialsSupplier = void 0; /** * Internal AWS security credentials supplier implementation used by {@link AwsClient} * when a credential source is provided instead of a user defined supplier. * The logic is summarized as: * 1. If imdsv2_session_token_url is provided in the credential source, then * fetch the aws session token and include it in the headers of the * metadata requests. This is a requirement for IDMSv2 but optional * for IDMSv1. * 2. Retrieve AWS region from availability-zone. * 3a. Check AWS credentials in environment variables. If not found, get * from security-credentials endpoint. * 3b. Get AWS credentials from security-credentials endpoint. In order * to retrieve this, the AWS role needs to be determined by calling * security-credentials endpoint without any argument. Then the * credentials can be retrieved via: security-credentials/role_name * 4. Generate the signed request to AWS STS GetCallerIdentity action. * 5. Inject x-goog-cloud-target-resource into header and serialize the * signed request. This will be the subject-token to pass to GCP STS. */ class DefaultAwsSecurityCredentialsSupplier { /** * Instantiates a new DefaultAwsSecurityCredentialsSupplier using information * from the credential_source stored in the ADC file. * @param opts The default aws security credentials supplier options object to * build the supplier with. */ constructor(opts) { _DefaultAwsSecurityCredentialsSupplier_instances.add(this); this.regionUrl = opts.regionUrl; this.securityCredentialsUrl = opts.securityCredentialsUrl; this.imdsV2SessionTokenUrl = opts.imdsV2SessionTokenUrl; this.additionalGaxiosOptions = opts.additionalGaxiosOptions; } /** * Returns the active AWS region. This first checks to see if the region * is available as an environment variable. If it is not, then the supplier * will call the region URL. * @param context {@link ExternalAccountSupplierContext} from the calling * {@link AwsClient}, contains the requested audience and subject token type * for the external account identity. * @return A promise that resolves with the AWS region string. */ async getAwsRegion(context) { // Priority order for region determination: // AWS_REGION > AWS_DEFAULT_REGION > metadata server. if (__classPrivateFieldGet(this, _DefaultAwsSecurityCredentialsSupplier_instances, "a", _DefaultAwsSecurityCredentialsSupplier_regionFromEnv_get)) { return __classPrivateFieldGet(this, _DefaultAwsSecurityCredentialsSupplier_instances, "a", _DefaultAwsSecurityCredentialsSupplier_regionFromEnv_get); } const metadataHeaders = {}; if (!__classPrivateFieldGet(this, _DefaultAwsSecurityCredentialsSupplier_instances, "a", _DefaultAwsSecurityCredentialsSupplier_regionFromEnv_get) && this.imdsV2SessionTokenUrl) { metadataHeaders['x-aws-ec2-metadata-token'] = await __classPrivateFieldGet(this, _DefaultAwsSecurityCredentialsSupplier_instances, "m", _DefaultAwsSecurityCredentialsSupplier_getImdsV2SessionToken).call(this, context.transporter); } if (!this.regionUrl) { throw new Error('Unable to determine AWS region due to missing ' + '"options.credential_source.region_url"'); } const opts = { ...this.additionalGaxiosOptions, url: this.regionUrl, method: 'GET', responseType: 'text', headers: metadataHeaders, }; const response = await context.transporter.request(opts); // Remove last character. For example, if us-east-2b is returned, // the region would be us-east-2. return response.data.substr(0, response.data.length - 1); } /** * Returns AWS security credentials. This first checks to see if the credentials * is available as environment variables. If it is not, then the supplier * will call the security credentials URL. * @param context {@link ExternalAccountSupplierContext} from the calling * {@link AwsClient}, contains the requested audience and subject token type * for the external account identity. * @return A promise that resolves with the AWS security credentials. */ async getAwsSecurityCredentials(context) { // Check environment variables for permanent credentials first. // https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html if (__classPrivateFieldGet(this, _DefaultAwsSecurityCredentialsSupplier_instances, "a", _DefaultAwsSecurityCredentialsSupplier_securityCredentialsFromEnv_get)) { return __classPrivateFieldGet(this, _DefaultAwsSecurityCredentialsSupplier_instances, "a", _DefaultAwsSecurityCredentialsSupplier_securityCredentialsFromEnv_get); } const metadataHeaders = {}; if (this.imdsV2SessionTokenUrl) { metadataHeaders['x-aws-ec2-metadata-token'] = await __classPrivateFieldGet(this, _DefaultAwsSecurityCredentialsSupplier_instances, "m", _DefaultAwsSecurityCredentialsSupplier_getImdsV2SessionToken).call(this, context.transporter); } // Since the role on a VM can change, we don't need to cache it. const roleName = await __classPrivateFieldGet(this, _DefaultAwsSecurityCredentialsSupplier_instances, "m", _DefaultAwsSecurityCredentialsSupplier_getAwsRoleName).call(this, metadataHeaders, context.transporter); // Temporary credentials typically last for several hours. // Expiration is returned in response. // Consider future optimization of this logic to cache AWS tokens // until their natural expiration. const awsCreds = await __classPrivateFieldGet(this, _DefaultAwsSecurityCredentialsSupplier_instances, "m", _DefaultAwsSecurityCredentialsSupplier_retrieveAwsSecurityCredentials).call(this, roleName, metadataHeaders, context.transporter); return { accessKeyId: awsCreds.AccessKeyId, secretAccessKey: awsCreds.SecretAccessKey, token: awsCreds.Token, }; } } exports.DefaultAwsSecurityCredentialsSupplier = DefaultAwsSecurityCredentialsSupplier; _DefaultAwsSecurityCredentialsSupplier_instances = new WeakSet(), _DefaultAwsSecurityCredentialsSupplier_getImdsV2SessionToken = /** * @param transporter The transporter to use for requests. * @return A promise that resolves with the IMDSv2 Session Token. */ async function _DefaultAwsSecurityCredentialsSupplier_getImdsV2SessionToken(transporter) { const opts = { ...this.additionalGaxiosOptions, url: this.imdsV2SessionTokenUrl, method: 'PUT', responseType: 'text', headers: { 'x-aws-ec2-metadata-token-ttl-seconds': '300' }, }; const response = await transporter.request(opts); return response.data; }, _DefaultAwsSecurityCredentialsSupplier_getAwsRoleName = /** * @param headers The headers to be used in the metadata request. * @param transporter The transporter to use for requests. * @return A promise that resolves with the assigned role to the current * AWS VM. This is needed for calling the security-credentials endpoint. */ async function _DefaultAwsSecurityCredentialsSupplier_getAwsRoleName(headers, transporter) { if (!this.securityCredentialsUrl) { throw new Error('Unable to determine AWS role name due to missing ' + '"options.credential_source.url"'); } const opts = { ...this.additionalGaxiosOptions, url: this.securityCredentialsUrl, method: 'GET', responseType: 'text', headers: headers, }; const response = await transporter.request(opts); return response.data; }, _DefaultAwsSecurityCredentialsSupplier_retrieveAwsSecurityCredentials = /** * Retrieves the temporary AWS credentials by calling the security-credentials * endpoint as specified in the `credential_source` object. * @param roleName The role attached to the current VM. * @param headers The headers to be used in the metadata request. * @param transporter The transporter to use for requests. * @return A promise that resolves with the temporary AWS credentials * needed for creating the GetCallerIdentity signed request. */ async function _DefaultAwsSecurityCredentialsSupplier_retrieveAwsSecurityCredentials(roleName, headers, transporter) { const response = await transporter.request({ ...this.additionalGaxiosOptions, url: `${this.securityCredentialsUrl}/${roleName}`, responseType: 'json', headers: headers, }); return response.data; }, _DefaultAwsSecurityCredentialsSupplier_regionFromEnv_get = function _DefaultAwsSecurityCredentialsSupplier_regionFromEnv_get() { // The AWS region can be provided through AWS_REGION or AWS_DEFAULT_REGION. // Only one is required. return (process.env['AWS_REGION'] || process.env['AWS_DEFAULT_REGION'] || null); }, _DefaultAwsSecurityCredentialsSupplier_securityCredentialsFromEnv_get = function _DefaultAwsSecurityCredentialsSupplier_securityCredentialsFromEnv_get() { // Both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are required. if (process.env['AWS_ACCESS_KEY_ID'] && process.env['AWS_SECRET_ACCESS_KEY']) { return { accessKeyId: process.env['AWS_ACCESS_KEY_ID'], secretAccessKey: process.env['AWS_SECRET_ACCESS_KEY'], token: process.env['AWS_SESSION_TOKEN'], }; } return null; };