UNPKG

8.41 kBJavaScriptView Raw
1"use strict";
2// Copyright 2021 Google LLC
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
16 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
17 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");
18 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
19};
20var _a, _AwsClient_DEFAULT_AWS_REGIONAL_CREDENTIAL_VERIFICATION_URL;
21Object.defineProperty(exports, "__esModule", { value: true });
22exports.AwsClient = void 0;
23const awsrequestsigner_1 = require("./awsrequestsigner");
24const baseexternalclient_1 = require("./baseexternalclient");
25const defaultawssecuritycredentialssupplier_1 = require("./defaultawssecuritycredentialssupplier");
26const util_1 = require("../util");
27/**
28 * AWS external account client. This is used for AWS workloads, where
29 * AWS STS GetCallerIdentity serialized signed requests are exchanged for
30 * GCP access token.
31 */
32class AwsClient extends baseexternalclient_1.BaseExternalAccountClient {
33 /**
34 * Instantiates an AwsClient instance using the provided JSON
35 * object loaded from an external account credentials file.
36 * An error is thrown if the credential is not a valid AWS credential.
37 * @param options The external account options object typically loaded
38 * from the external account JSON credential file.
39 * @param additionalOptions **DEPRECATED, all options are available in the
40 * `options` parameter.** Optional additional behavior customization options.
41 * These currently customize expiration threshold time and whether to retry
42 * on 401/403 API request errors.
43 */
44 constructor(options, additionalOptions) {
45 super(options, additionalOptions);
46 const opts = (0, util_1.originalOrCamelOptions)(options);
47 const credentialSource = opts.get('credential_source');
48 const awsSecurityCredentialsSupplier = opts.get('aws_security_credentials_supplier');
49 // Validate credential sourcing configuration.
50 if (!credentialSource && !awsSecurityCredentialsSupplier) {
51 throw new Error('A credential source or AWS security credentials supplier must be specified.');
52 }
53 if (credentialSource && awsSecurityCredentialsSupplier) {
54 throw new Error('Only one of credential source or AWS security credentials supplier can be specified.');
55 }
56 if (awsSecurityCredentialsSupplier) {
57 this.awsSecurityCredentialsSupplier = awsSecurityCredentialsSupplier;
58 this.regionalCredVerificationUrl =
59 __classPrivateFieldGet(_a, _a, "f", _AwsClient_DEFAULT_AWS_REGIONAL_CREDENTIAL_VERIFICATION_URL);
60 this.credentialSourceType = 'programmatic';
61 }
62 else {
63 const credentialSourceOpts = (0, util_1.originalOrCamelOptions)(credentialSource);
64 this.environmentId = credentialSourceOpts.get('environment_id');
65 // This is only required if the AWS region is not available in the
66 // AWS_REGION or AWS_DEFAULT_REGION environment variables.
67 const regionUrl = credentialSourceOpts.get('region_url');
68 // This is only required if AWS security credentials are not available in
69 // environment variables.
70 const securityCredentialsUrl = credentialSourceOpts.get('url');
71 const imdsV2SessionTokenUrl = credentialSourceOpts.get('imdsv2_session_token_url');
72 this.awsSecurityCredentialsSupplier =
73 new defaultawssecuritycredentialssupplier_1.DefaultAwsSecurityCredentialsSupplier({
74 regionUrl: regionUrl,
75 securityCredentialsUrl: securityCredentialsUrl,
76 imdsV2SessionTokenUrl: imdsV2SessionTokenUrl,
77 });
78 this.regionalCredVerificationUrl = credentialSourceOpts.get('regional_cred_verification_url');
79 this.credentialSourceType = 'aws';
80 // Data validators.
81 this.validateEnvironmentId();
82 }
83 this.awsRequestSigner = null;
84 this.region = '';
85 }
86 validateEnvironmentId() {
87 var _b;
88 const match = (_b = this.environmentId) === null || _b === void 0 ? void 0 : _b.match(/^(aws)(\d+)$/);
89 if (!match || !this.regionalCredVerificationUrl) {
90 throw new Error('No valid AWS "credential_source" provided');
91 }
92 else if (parseInt(match[2], 10) !== 1) {
93 throw new Error(`aws version "${match[2]}" is not supported in the current build.`);
94 }
95 }
96 /**
97 * Triggered when an external subject token is needed to be exchanged for a
98 * GCP access token via GCP STS endpoint. This will call the
99 * {@link AwsSecurityCredentialsSupplier} to retrieve an AWS region and AWS
100 * Security Credentials, then use them to create a signed AWS STS request that
101 * can be exchanged for a GCP access token.
102 * @return A promise that resolves with the external subject token.
103 */
104 async retrieveSubjectToken() {
105 // Initialize AWS request signer if not already initialized.
106 if (!this.awsRequestSigner) {
107 this.region = await this.awsSecurityCredentialsSupplier.getAwsRegion(this.supplierContext);
108 this.awsRequestSigner = new awsrequestsigner_1.AwsRequestSigner(async () => {
109 return this.awsSecurityCredentialsSupplier.getAwsSecurityCredentials(this.supplierContext);
110 }, this.region);
111 }
112 // Generate signed request to AWS STS GetCallerIdentity API.
113 // Use the required regional endpoint. Otherwise, the request will fail.
114 const options = await this.awsRequestSigner.getRequestOptions({
115 ..._a.RETRY_CONFIG,
116 url: this.regionalCredVerificationUrl.replace('{region}', this.region),
117 method: 'POST',
118 });
119 // The GCP STS endpoint expects the headers to be formatted as:
120 // [
121 // {key: 'x-amz-date', value: '...'},
122 // {key: 'Authorization', value: '...'},
123 // ...
124 // ]
125 // And then serialized as:
126 // encodeURIComponent(JSON.stringify({
127 // url: '...',
128 // method: 'POST',
129 // headers: [{key: 'x-amz-date', value: '...'}, ...]
130 // }))
131 const reformattedHeader = [];
132 const extendedHeaders = Object.assign({
133 // The full, canonical resource name of the workload identity pool
134 // provider, with or without the HTTPS prefix.
135 // Including this header as part of the signature is recommended to
136 // ensure data integrity.
137 'x-goog-cloud-target-resource': this.audience,
138 }, options.headers);
139 // Reformat header to GCP STS expected format.
140 for (const key in extendedHeaders) {
141 reformattedHeader.push({
142 key,
143 value: extendedHeaders[key],
144 });
145 }
146 // Serialize the reformatted signed request.
147 return encodeURIComponent(JSON.stringify({
148 url: options.url,
149 method: options.method,
150 headers: reformattedHeader,
151 }));
152 }
153}
154exports.AwsClient = AwsClient;
155_a = AwsClient;
156_AwsClient_DEFAULT_AWS_REGIONAL_CREDENTIAL_VERIFICATION_URL = { value: 'https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15' };
157/**
158 * @deprecated AWS client no validates the EC2 metadata address.
159 **/
160AwsClient.AWS_EC2_METADATA_IPV4_ADDRESS = '169.254.169.254';
161/**
162 * @deprecated AWS client no validates the EC2 metadata address.
163 **/
164AwsClient.AWS_EC2_METADATA_IPV6_ADDRESS = 'fd00:ec2::254';