@backstage/integration-aws-node 0.0.0-nightly-20221213023404

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # @backstage/integration-aws-node
2
+
3
+ ## 0.0.0-nightly-20221213023404
4
+
5
+ ### Minor Changes
6
+
7
+ - 13278732f6: New package for AWS integration node library
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/config@0.0.0-nightly-20221213023404
13
+ - @backstage/errors@0.0.0-nightly-20221213023404
package/README.md ADDED
@@ -0,0 +1,162 @@
1
+ # @backstage/integration-aws-node
2
+
3
+ This package providers helpers for fetching AWS account credentials
4
+ to be used by AWS SDK clients in backend packages and plugins.
5
+
6
+ ## Backstage app configuration
7
+
8
+ Users of plugins and packages that use this library
9
+ will configure their AWS account information and credentials in their
10
+ Backstage app config.
11
+ Users can configure IAM user credentials, IAM roles, and profile names
12
+ for their AWS accounts in their Backstage config.
13
+
14
+ If the AWS integration configuration is missing, the credentials manager
15
+ from this package will fall back to the AWS SDK default credentials chain for
16
+ resources in the main AWS account.
17
+ The default credentials chain for Node resolves credentials in the
18
+ following order of precedence:
19
+
20
+ 1. Environment variables
21
+ 2. SSO credentials from token cache
22
+ 3. Web identity token credentials
23
+ 4. Shared credentials files
24
+ 5. The EC2/ECS Instance Metadata Service
25
+
26
+ See more about the AWS SDK default credentials chain in the
27
+ [AWS SDK for Javascript Developer Guide](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html).
28
+
29
+ Configuration examples:
30
+
31
+ ```yaml
32
+ aws:
33
+ # The main account is used as the source of credentials for calling
34
+ # the STS AssumeRole API to assume IAM roles in other AWS accounts.
35
+ # This section can be omitted to fall back to the AWS SDK's default creds chain.
36
+ mainAccount:
37
+ accessKeyId: ${MY_ACCESS_KEY_ID}
38
+ secretAccessKey: ${MY_SECRET_ACCESS_KEY}
39
+
40
+ # Account credentials can be configured individually per account
41
+ accounts:
42
+ # Credentials can come from a role in the account
43
+ - accountId: '111111111111'
44
+ roleName: 'my-iam-role-name'
45
+ externalId: 'my-external-id'
46
+
47
+ # Credentials can come from other AWS partitions
48
+ - accountId: '222222222222'
49
+ partition: 'aws-other'
50
+ roleName: 'my-iam-role-name'
51
+ # The STS region to use for the AssumeRole call
52
+ region: 'not-us-east-1'
53
+ # The creds to use when calling AssumeRole
54
+ accessKeyId: ${MY_ACCESS_KEY_ID_FOR_ANOTHER_PARTITION}
55
+ secretAccessKey: ${MY_SECRET_ACCESS_KEY_FOR_ANOTHER_PARTITION}
56
+
57
+ # Credentials can come from static credentials
58
+ - accountId: '333333333333'
59
+ accessKeyId: ${MY_OTHER_ACCESS_KEY_ID}
60
+ secretAccessKey: ${MY_OTHER_SECRET_ACCESS_KEY}
61
+
62
+ # Credentials can come from a profile in a shared config file on disk
63
+ - accountId: '444444444444'
64
+ profile: my-profile-name
65
+
66
+ # Credentials can come from the AWS SDK's default creds chain
67
+ - accountId: '555555555555'
68
+
69
+ # Credentials for accounts can fall back to a common role name.
70
+ # This is useful for account discovery use cases where the account
71
+ # IDs may not be known when writing the static config.
72
+ # If all accounts have a role with the same name, then the "accounts"
73
+ # section can be omitted entirely.
74
+ accountDefaults:
75
+ roleName: 'my-backstage-role'
76
+ externalId: 'my-id'
77
+ ```
78
+
79
+ ## Integrate new plugins
80
+
81
+ Backend plugins can provide an AWS ARN or account ID to this library in order to
82
+ retrieve a credential provider for the relevant account that can be fed directly
83
+ to an AWS SDK client.
84
+ The AWS SDK for Javascript V3 must be used.
85
+
86
+ ```typescript
87
+ const awsCredentialsManager = DefaultAwsCredentialsManager.fromConfig(config);
88
+
89
+ // provide the account ID explicitly
90
+ const credProvider = await awsCredentialsManager.getCredentialProvider({
91
+ accountId,
92
+ });
93
+ // OR extract the account ID from the ARN
94
+ const credProvider = await awsCredentialsManager.getCredentialProvider({ arn });
95
+ // OR provide neither to get main account's credentials
96
+ const credProvider = await awsCredentialsManager.getCredentialProvider({});
97
+
98
+ // Example constructing an AWS Proton client with the returned credential provider
99
+ const client = new ProtonClient({
100
+ region,
101
+ credentialDefaultProvider: () => credProvider.sdkCredentialProvider,
102
+ });
103
+ ```
104
+
105
+ Depending on the nature of your plugin, you may either have the user specify the
106
+ relevant ARN or account ID in a catalog entity annotation or in the static Backstage
107
+ app configuration for your plugin.
108
+
109
+ For example, you can create a new catalog entity annotation for your plugin containing
110
+ either an AWS account ID or ARN:
111
+
112
+ ```yaml
113
+ apiVersion: backstage.io/v1alpha1
114
+ kind: Component
115
+ metadata:
116
+ annotations:
117
+ # Plugin annotation to specify an AWS account ID
118
+ my-plugin.io/aws-account-id: '123456789012'
119
+ # Plugin annotation to specify the AWS ARN of a specific resource
120
+ my-other-plugin.io/aws-dynamodb-table: 'arn:aws:dynamodb:us-east-2:123456789012:table/example-table'
121
+ ```
122
+
123
+ In your plugin, read the annotation value so that you can retrieve the credential provider:
124
+
125
+ ```typescript
126
+ const MY_AWS_ACCOUNT_ID_ANNOTATION = 'my-plugin.io/aws-account-id';
127
+
128
+ const getAwsAccountId = (entity: Entity) =>
129
+ entity.metadata.annotations?.[MY_AWS_ACCOUNT_ID_ANNOTATION]);
130
+ ```
131
+
132
+ Alternatively, you can create a new Backstage app configuration field for your plugin:
133
+
134
+ ```yaml
135
+ # app-config.yaml
136
+ my-plugin:
137
+ # Statically configure the AWS account ID to use
138
+ awsAccountId: '123456789012'
139
+ my-other-plugin:
140
+ # Statically configure the AWS ARN of a specific resource
141
+ awsDynamoDbTable: 'arn:aws:dynamodb:us-east-2:123456789012:table/example-table'
142
+ ```
143
+
144
+ In your plugin, read the configuration value so that you can retrieve the credential provider:
145
+
146
+ ```typescript
147
+ // Read an account ID from your plugin's configuration
148
+ const awsCredentialsManager = DefaultAwsCredentialsManager.fromConfig(config);
149
+ const accountId = config.getOptionalString('my-plugin.awsAccountId');
150
+ const credProvider = await awsCredentialsManager.getCredentialProvider({
151
+ accountId,
152
+ });
153
+
154
+ // Or, read an AWS ARN from your plugin's configuration
155
+ const awsCredentialsManager = DefaultAwsCredentialsManager.fromConfig(config);
156
+ const arn = config.getString('my-other-plugin.awsDynamoDbTable');
157
+ const credProvider = await awsCredentialsManager.getCredentialProvider({ arn });
158
+ ```
159
+
160
+ ## Links
161
+
162
+ - [The Backstage homepage](https://backstage.io)
package/config.d.ts ADDED
@@ -0,0 +1,123 @@
1
+ /*
2
+ * Copyright 2022 The Backstage Authors
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.
15
+ */
16
+
17
+ export interface Config {
18
+ /** Configuration for access to AWS accounts */
19
+ aws?: {
20
+ /**
21
+ * Defaults for retrieving AWS account credentials
22
+ */
23
+ accountDefaults?: {
24
+ /**
25
+ * The IAM role to assume to retrieve temporary AWS credentials
26
+ */
27
+ roleName?: string;
28
+
29
+ /**
30
+ * The AWS partition of the IAM role, e.g. "aws", "aws-cn"
31
+ */
32
+ partition?: string;
33
+
34
+ /**
35
+ * The STS regional endpoint to use when retrieving temporary AWS credentials, e.g. "ap-northeast-1"
36
+ */
37
+ region?: string;
38
+
39
+ /**
40
+ * The unique identifier needed to assume the role to retrieve temporary AWS credentials
41
+ * @visibility secret
42
+ */
43
+ externalId?: string;
44
+ };
45
+
46
+ /**
47
+ * Main account to use for retrieving AWS account credentials
48
+ */
49
+ mainAccount?: {
50
+ /**
51
+ * The access key ID for a set of static AWS credentials
52
+ * @visibility secret
53
+ */
54
+ accessKeyId?: string;
55
+
56
+ /**
57
+ * The secret access key for a set of static AWS credentials
58
+ * @visibility secret
59
+ */
60
+ secretAccessKey?: string;
61
+
62
+ /**
63
+ * The configuration profile from a credentials file at ~/.aws/credentials and
64
+ * a configuration file at ~/.aws/config.
65
+ */
66
+ profile?: string;
67
+
68
+ /**
69
+ * The STS regional endpoint to use for the main account, e.g. "ap-northeast-1"
70
+ */
71
+ region?: string;
72
+ };
73
+
74
+ /**
75
+ * Configuration for retrieving AWS accounts credentials
76
+ */
77
+ accounts?: Array<{
78
+ /**
79
+ * The account ID of the target account that this matches on, e.g. "123456789012"
80
+ */
81
+ accountId: string;
82
+
83
+ /**
84
+ * The access key ID for a set of static AWS credentials
85
+ * @visibility secret
86
+ */
87
+ accessKeyId?: string;
88
+
89
+ /**
90
+ * The secret access key for a set of static AWS credentials
91
+ * @visibility secret
92
+ */
93
+ secretAccessKey?: string;
94
+
95
+ /**
96
+ * The configuration profile from a credentials file at ~/.aws/credentials and
97
+ * a configuration file at ~/.aws/config.
98
+ */
99
+ profile?: string;
100
+
101
+ /**
102
+ * The IAM role to assume to retrieve temporary AWS credentials
103
+ */
104
+ roleName?: string;
105
+
106
+ /**
107
+ * The AWS partition of the IAM role, e.g. "aws", "aws-cn"
108
+ */
109
+ partition?: string;
110
+
111
+ /**
112
+ * The STS regional endpoint to use when retrieving temporary AWS credentials, e.g. "ap-northeast-1"
113
+ */
114
+ region?: string;
115
+
116
+ /**
117
+ * The unique identifier needed to assume the role to retrieve temporary AWS credentials
118
+ * @visibility secret
119
+ */
120
+ externalId?: string;
121
+ }>;
122
+ };
123
+ }
@@ -0,0 +1,269 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var clientSts = require('@aws-sdk/client-sts');
6
+ var credentialProviders = require('@aws-sdk/credential-providers');
7
+ var utilArnParser = require('@aws-sdk/util-arn-parser');
8
+
9
+ function readAwsIntegrationAccountConfig(config) {
10
+ const accountConfig = {
11
+ accountId: config.getString("accountId"),
12
+ accessKeyId: config.getOptionalString("accessKeyId"),
13
+ secretAccessKey: config.getOptionalString("secretAccessKey"),
14
+ profile: config.getOptionalString("profile"),
15
+ roleName: config.getOptionalString("roleName"),
16
+ region: config.getOptionalString("region"),
17
+ partition: config.getOptionalString("partition"),
18
+ externalId: config.getOptionalString("externalId")
19
+ };
20
+ if (accountConfig.accessKeyId && !accountConfig.secretAccessKey) {
21
+ throw new Error(
22
+ `AWS integration account ${accountConfig.accountId} has an access key ID configured, but no secret access key.`
23
+ );
24
+ }
25
+ if (!accountConfig.accessKeyId && accountConfig.secretAccessKey) {
26
+ throw new Error(
27
+ `AWS integration account ${accountConfig.accountId} has a secret access key configured, but no access key ID`
28
+ );
29
+ }
30
+ if (accountConfig.profile && accountConfig.accessKeyId) {
31
+ throw new Error(
32
+ `AWS integration account ${accountConfig.accountId} has both an access key ID and a profile configured, but only one must be specified`
33
+ );
34
+ }
35
+ if (accountConfig.profile && accountConfig.roleName) {
36
+ throw new Error(
37
+ `AWS integration account ${accountConfig.accountId} has both an access key ID and a role name configured, but only one must be specified`
38
+ );
39
+ }
40
+ if (!accountConfig.roleName && accountConfig.externalId) {
41
+ throw new Error(
42
+ `AWS integration account ${accountConfig.accountId} has an external ID configured, but no role name.`
43
+ );
44
+ }
45
+ if (!accountConfig.roleName && accountConfig.region) {
46
+ throw new Error(
47
+ `AWS integration account ${accountConfig.accountId} has an STS region configured, but no role name.`
48
+ );
49
+ }
50
+ if (!accountConfig.roleName && accountConfig.partition) {
51
+ throw new Error(
52
+ `AWS integration account ${accountConfig.accountId} has an IAM partition configured, but no role name.`
53
+ );
54
+ }
55
+ return accountConfig;
56
+ }
57
+ function readMainAwsIntegrationAccountConfig(config) {
58
+ const mainAccountConfig = {
59
+ accessKeyId: config.getOptionalString("accessKeyId"),
60
+ secretAccessKey: config.getOptionalString("secretAccessKey"),
61
+ profile: config.getOptionalString("profile"),
62
+ region: config.getOptionalString("region")
63
+ };
64
+ if (mainAccountConfig.accessKeyId && !mainAccountConfig.secretAccessKey) {
65
+ throw new Error(
66
+ `The main AWS integration account has an access key ID configured, but no secret access key.`
67
+ );
68
+ }
69
+ if (!mainAccountConfig.accessKeyId && mainAccountConfig.secretAccessKey) {
70
+ throw new Error(
71
+ `The main AWS integration account has a secret access key configured, but no access key ID`
72
+ );
73
+ }
74
+ if (mainAccountConfig.profile && mainAccountConfig.accessKeyId) {
75
+ throw new Error(
76
+ `The main AWS integration account has both an access key ID and a profile configured, but only one must be specified`
77
+ );
78
+ }
79
+ return mainAccountConfig;
80
+ }
81
+ function readAwsIntegrationAccountDefaultsConfig(config) {
82
+ const defaultAccountConfig = {
83
+ roleName: config.getOptionalString("roleName"),
84
+ partition: config.getOptionalString("partition"),
85
+ region: config.getOptionalString("region"),
86
+ externalId: config.getOptionalString("externalId")
87
+ };
88
+ if (!defaultAccountConfig.roleName && defaultAccountConfig.externalId) {
89
+ throw new Error(
90
+ `AWS integration account default configuration has an external ID configured, but no role name.`
91
+ );
92
+ }
93
+ if (!defaultAccountConfig.roleName && defaultAccountConfig.region) {
94
+ throw new Error(
95
+ `AWS integration account default configuration has an STS region configured, but no role name.`
96
+ );
97
+ }
98
+ if (!defaultAccountConfig.roleName && defaultAccountConfig.partition) {
99
+ throw new Error(
100
+ `AWS integration account default configuration has an IAM partition configured, but no role name.`
101
+ );
102
+ }
103
+ return defaultAccountConfig;
104
+ }
105
+ function readAwsIntegrationConfig(config) {
106
+ var _a;
107
+ const accounts = (_a = config.getOptionalConfigArray("accounts")) == null ? void 0 : _a.map(readAwsIntegrationAccountConfig);
108
+ const mainAccount = config.has("mainAccount") ? readMainAwsIntegrationAccountConfig(config.getConfig("mainAccount")) : {};
109
+ const accountDefaults = config.has("accountDefaults") ? readAwsIntegrationAccountDefaultsConfig(
110
+ config.getConfig("accountDefaults")
111
+ ) : {};
112
+ return {
113
+ accounts: accounts != null ? accounts : [],
114
+ mainAccount,
115
+ accountDefaults
116
+ };
117
+ }
118
+
119
+ async function fillInAccountId(credProvider) {
120
+ if (credProvider.accountId) {
121
+ return;
122
+ }
123
+ const client = new clientSts.STSClient({
124
+ region: credProvider.stsRegion,
125
+ customUserAgent: "backstage-aws-credentials-manager",
126
+ credentialDefaultProvider: () => credProvider.sdkCredentialProvider
127
+ });
128
+ const resp = await client.send(new clientSts.GetCallerIdentityCommand({}));
129
+ credProvider.accountId = resp.Account;
130
+ }
131
+ function getStaticCredentials(accessKeyId, secretAccessKey) {
132
+ return async () => {
133
+ return Promise.resolve({
134
+ accessKeyId,
135
+ secretAccessKey
136
+ });
137
+ };
138
+ }
139
+ function getProfileCredentials(profile, region) {
140
+ return credentialProviders.fromIni({
141
+ profile,
142
+ clientConfig: {
143
+ region,
144
+ customUserAgent: "backstage-aws-credentials-manager"
145
+ }
146
+ });
147
+ }
148
+ function getDefaultCredentialsChain() {
149
+ return credentialProviders.fromNodeProviderChain();
150
+ }
151
+ function getSdkCredentialProvider(config, mainAccountCredProvider) {
152
+ var _a, _b;
153
+ if (config.roleName) {
154
+ const region = (_a = config.region) != null ? _a : "us-east-1";
155
+ const partition = (_b = config.partition) != null ? _b : "aws";
156
+ return credentialProviders.fromTemporaryCredentials({
157
+ masterCredentials: config.accessKeyId ? getStaticCredentials(config.accessKeyId, config.secretAccessKey) : mainAccountCredProvider,
158
+ params: {
159
+ RoleArn: `arn:${partition}:iam::${config.accountId}:role/${config.roleName}`,
160
+ RoleSessionName: "backstage",
161
+ ExternalId: config.externalId
162
+ },
163
+ clientConfig: {
164
+ region,
165
+ customUserAgent: "backstage-aws-credentials-manager"
166
+ }
167
+ });
168
+ }
169
+ if (config.accessKeyId) {
170
+ return getStaticCredentials(config.accessKeyId, config.secretAccessKey);
171
+ }
172
+ if (config.profile) {
173
+ return getProfileCredentials(config.profile, config.region);
174
+ }
175
+ return getDefaultCredentialsChain();
176
+ }
177
+ function getMainAccountSdkCredentialProvider(config) {
178
+ if (config.accessKeyId) {
179
+ return getStaticCredentials(config.accessKeyId, config.secretAccessKey);
180
+ }
181
+ if (config.profile) {
182
+ return getProfileCredentials(config.profile, config.region);
183
+ }
184
+ return getDefaultCredentialsChain();
185
+ }
186
+ class DefaultAwsCredentialsManager {
187
+ constructor(accountCredentialProviders, accountDefaults, mainAccountCredentialProvider) {
188
+ this.accountCredentialProviders = accountCredentialProviders;
189
+ this.accountDefaults = accountDefaults;
190
+ this.mainAccountCredentialProvider = mainAccountCredentialProvider;
191
+ }
192
+ static fromConfig(config) {
193
+ const awsConfig = config.has("aws") ? readAwsIntegrationConfig(config.getConfig("aws")) : {
194
+ accounts: [],
195
+ mainAccount: {},
196
+ accountDefaults: {}
197
+ };
198
+ const mainAccountSdkCredProvider = getMainAccountSdkCredentialProvider(
199
+ awsConfig.mainAccount
200
+ );
201
+ const mainAccountCredProvider = {
202
+ sdkCredentialProvider: mainAccountSdkCredProvider
203
+ };
204
+ const accountCredProviders = /* @__PURE__ */ new Map();
205
+ for (const accountConfig of awsConfig.accounts) {
206
+ const sdkCredentialProvider = getSdkCredentialProvider(
207
+ accountConfig,
208
+ mainAccountSdkCredProvider
209
+ );
210
+ accountCredProviders.set(accountConfig.accountId, {
211
+ accountId: accountConfig.accountId,
212
+ stsRegion: accountConfig.region,
213
+ sdkCredentialProvider
214
+ });
215
+ }
216
+ return new DefaultAwsCredentialsManager(
217
+ accountCredProviders,
218
+ awsConfig.accountDefaults,
219
+ mainAccountCredProvider
220
+ );
221
+ }
222
+ async getCredentialProvider(opts) {
223
+ if (!opts) {
224
+ await fillInAccountId(this.mainAccountCredentialProvider);
225
+ return this.mainAccountCredentialProvider;
226
+ }
227
+ let accountId = opts.accountId;
228
+ if (opts.arn && !accountId) {
229
+ const arnComponents = utilArnParser.parse(opts.arn);
230
+ accountId = arnComponents.accountId;
231
+ }
232
+ if (!accountId) {
233
+ await fillInAccountId(this.mainAccountCredentialProvider);
234
+ return this.mainAccountCredentialProvider;
235
+ }
236
+ if (this.accountCredentialProviders.has(accountId)) {
237
+ return this.accountCredentialProviders.get(accountId);
238
+ }
239
+ if (this.accountDefaults.roleName) {
240
+ const config = {
241
+ accountId,
242
+ roleName: this.accountDefaults.roleName,
243
+ partition: this.accountDefaults.partition,
244
+ region: this.accountDefaults.region,
245
+ externalId: this.accountDefaults.externalId
246
+ };
247
+ const sdkCredentialProvider = getSdkCredentialProvider(
248
+ config,
249
+ this.mainAccountCredentialProvider.sdkCredentialProvider
250
+ );
251
+ const credProvider = {
252
+ accountId,
253
+ sdkCredentialProvider
254
+ };
255
+ this.accountCredentialProviders.set(accountId, credProvider);
256
+ return credProvider;
257
+ }
258
+ await fillInAccountId(this.mainAccountCredentialProvider);
259
+ if (accountId === this.mainAccountCredentialProvider.accountId) {
260
+ return this.mainAccountCredentialProvider;
261
+ }
262
+ throw new Error(
263
+ `There is no AWS integration that matches ${accountId}. Please add a configuration for this AWS account.`
264
+ );
265
+ }
266
+ }
267
+
268
+ exports.DefaultAwsCredentialsManager = DefaultAwsCredentialsManager;
269
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/config.ts","../src/DefaultAwsCredentialsManager.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\n\n/**\n * The configuration parameters for a single AWS account for the AWS integration.\n *\n * @public\n */\nexport type AwsIntegrationAccountConfig = {\n /**\n * The account ID of the target account that this matches on, e.g. \"123456789012\"\n */\n accountId: string;\n\n /**\n * The access key ID for a set of static AWS credentials\n */\n accessKeyId?: string;\n\n /**\n * The secret access key for a set of static AWS credentials\n */\n secretAccessKey?: string;\n\n /**\n * The configuration profile from a credentials file at ~/.aws/credentials and\n * a configuration file at ~/.aws/config.\n */\n profile?: string;\n\n /**\n * The IAM role to assume to retrieve temporary AWS credentials\n */\n roleName?: string;\n\n /**\n * The AWS partition of the IAM role, e.g. \"aws\", \"aws-cn\"\n */\n partition?: string;\n\n /**\n * The STS regional endpoint to use when retrieving temporary AWS credentials, e.g. \"ap-northeast-1\"\n */\n region?: string;\n\n /**\n * The unique identifier needed to assume the role to retrieve temporary AWS credentials\n */\n externalId?: string;\n};\n\n/**\n * The configuration parameters for the main AWS account for the AWS integration.\n *\n * @public\n */\nexport type AwsIntegrationMainAccountConfig = {\n /**\n * The access key ID for a set of static AWS credentials\n */\n accessKeyId?: string;\n\n /**\n * The secret access key for a set of static AWS credentials\n */\n secretAccessKey?: string;\n\n /**\n * The configuration profile from a credentials file at ~/.aws/credentials and\n * a configuration file at ~/.aws/config.\n */\n profile?: string;\n\n /**\n * The STS regional endpoint to use for the main account, e.g. \"ap-northeast-1\"\n */\n region?: string;\n};\n\n/**\n * The default configuration parameters to use for accounts for the AWS integration.\n *\n * @public\n */\nexport type AwsIntegrationDefaultAccountConfig = {\n /**\n * The IAM role to assume to retrieve temporary AWS credentials\n */\n roleName?: string;\n\n /**\n * The AWS partition of the IAM role, e.g. \"aws\", \"aws-cn\"\n */\n partition?: string;\n\n /**\n * The STS regional endpoint to use when retrieving temporary AWS credentials, e.g. \"ap-northeast-1\"\n */\n region?: string;\n\n /**\n * The unique identifier needed to assume the role to retrieve temporary AWS credentials\n */\n externalId?: string;\n};\n\n/**\n * The configuration parameters for AWS account integration.\n *\n * @public\n */\nexport type AwsIntegrationConfig = {\n /**\n * Configuration for retrieving AWS accounts credentials\n */\n accounts: AwsIntegrationAccountConfig[];\n\n /**\n * Defaults for retrieving AWS account credentials\n */\n accountDefaults: AwsIntegrationDefaultAccountConfig;\n\n /**\n * Main account to use for retrieving AWS account credentials\n */\n mainAccount: AwsIntegrationMainAccountConfig;\n};\n\n/**\n * Reads an AWS integration account config.\n *\n * @param config - The config object of a single account\n */\nfunction readAwsIntegrationAccountConfig(\n config: Config,\n): AwsIntegrationAccountConfig {\n const accountConfig = {\n accountId: config.getString('accountId'),\n accessKeyId: config.getOptionalString('accessKeyId'),\n secretAccessKey: config.getOptionalString('secretAccessKey'),\n profile: config.getOptionalString('profile'),\n roleName: config.getOptionalString('roleName'),\n region: config.getOptionalString('region'),\n partition: config.getOptionalString('partition'),\n externalId: config.getOptionalString('externalId'),\n };\n\n // Validate that the account config has the right combination of attributes\n if (accountConfig.accessKeyId && !accountConfig.secretAccessKey) {\n throw new Error(\n `AWS integration account ${accountConfig.accountId} has an access key ID configured, but no secret access key.`,\n );\n }\n\n if (!accountConfig.accessKeyId && accountConfig.secretAccessKey) {\n throw new Error(\n `AWS integration account ${accountConfig.accountId} has a secret access key configured, but no access key ID`,\n );\n }\n\n if (accountConfig.profile && accountConfig.accessKeyId) {\n throw new Error(\n `AWS integration account ${accountConfig.accountId} has both an access key ID and a profile configured, but only one must be specified`,\n );\n }\n\n if (accountConfig.profile && accountConfig.roleName) {\n throw new Error(\n `AWS integration account ${accountConfig.accountId} has both an access key ID and a role name configured, but only one must be specified`,\n );\n }\n\n if (!accountConfig.roleName && accountConfig.externalId) {\n throw new Error(\n `AWS integration account ${accountConfig.accountId} has an external ID configured, but no role name.`,\n );\n }\n\n if (!accountConfig.roleName && accountConfig.region) {\n throw new Error(\n `AWS integration account ${accountConfig.accountId} has an STS region configured, but no role name.`,\n );\n }\n\n if (!accountConfig.roleName && accountConfig.partition) {\n throw new Error(\n `AWS integration account ${accountConfig.accountId} has an IAM partition configured, but no role name.`,\n );\n }\n\n return accountConfig;\n}\n\n/**\n * Reads the main AWS integration account config.\n *\n * @param config - The config object of the main account\n */\nfunction readMainAwsIntegrationAccountConfig(\n config: Config,\n): AwsIntegrationMainAccountConfig {\n const mainAccountConfig = {\n accessKeyId: config.getOptionalString('accessKeyId'),\n secretAccessKey: config.getOptionalString('secretAccessKey'),\n profile: config.getOptionalString('profile'),\n region: config.getOptionalString('region'),\n };\n\n // Validate that the account config has the right combination of attributes\n if (mainAccountConfig.accessKeyId && !mainAccountConfig.secretAccessKey) {\n throw new Error(\n `The main AWS integration account has an access key ID configured, but no secret access key.`,\n );\n }\n\n if (!mainAccountConfig.accessKeyId && mainAccountConfig.secretAccessKey) {\n throw new Error(\n `The main AWS integration account has a secret access key configured, but no access key ID`,\n );\n }\n\n if (mainAccountConfig.profile && mainAccountConfig.accessKeyId) {\n throw new Error(\n `The main AWS integration account has both an access key ID and a profile configured, but only one must be specified`,\n );\n }\n\n return mainAccountConfig;\n}\n\n/**\n * Reads the default settings for retrieving credentials from AWS integration accounts.\n *\n * @param config - The config object of the default account settings\n */\nfunction readAwsIntegrationAccountDefaultsConfig(\n config: Config,\n): AwsIntegrationDefaultAccountConfig {\n const defaultAccountConfig = {\n roleName: config.getOptionalString('roleName'),\n partition: config.getOptionalString('partition'),\n region: config.getOptionalString('region'),\n externalId: config.getOptionalString('externalId'),\n };\n\n // Validate that the account config has the right combination of attributes\n if (!defaultAccountConfig.roleName && defaultAccountConfig.externalId) {\n throw new Error(\n `AWS integration account default configuration has an external ID configured, but no role name.`,\n );\n }\n\n if (!defaultAccountConfig.roleName && defaultAccountConfig.region) {\n throw new Error(\n `AWS integration account default configuration has an STS region configured, but no role name.`,\n );\n }\n\n if (!defaultAccountConfig.roleName && defaultAccountConfig.partition) {\n throw new Error(\n `AWS integration account default configuration has an IAM partition configured, but no role name.`,\n );\n }\n\n return defaultAccountConfig;\n}\n\n/**\n * Reads an AWS integration configuration\n *\n * @param config - the integration config object\n * @public\n */\nexport function readAwsIntegrationConfig(config: Config): AwsIntegrationConfig {\n const accounts = config\n .getOptionalConfigArray('accounts')\n ?.map(readAwsIntegrationAccountConfig);\n const mainAccount = config.has('mainAccount')\n ? readMainAwsIntegrationAccountConfig(config.getConfig('mainAccount'))\n : {};\n const accountDefaults = config.has('accountDefaults')\n ? readAwsIntegrationAccountDefaultsConfig(\n config.getConfig('accountDefaults'),\n )\n : {};\n\n return {\n accounts: accounts ?? [],\n mainAccount,\n accountDefaults,\n };\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n readAwsIntegrationConfig,\n AwsIntegrationAccountConfig,\n AwsIntegrationDefaultAccountConfig,\n AwsIntegrationMainAccountConfig,\n} from './config';\nimport {\n AwsCredentialsManager,\n AwsCredentialProvider,\n AwsCredentialProviderOptions,\n} from './types';\nimport { GetCallerIdentityCommand, STSClient } from '@aws-sdk/client-sts';\nimport {\n fromIni,\n fromNodeProviderChain,\n fromTemporaryCredentials,\n} from '@aws-sdk/credential-providers';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { parse } from '@aws-sdk/util-arn-parser';\nimport { Config } from '@backstage/config';\n\n/**\n * Retrieves the account ID for the given credential provider from STS.\n */\nasync function fillInAccountId(credProvider: AwsCredentialProvider) {\n if (credProvider.accountId) {\n return;\n }\n\n const client = new STSClient({\n region: credProvider.stsRegion,\n customUserAgent: 'backstage-aws-credentials-manager',\n credentialDefaultProvider: () => credProvider.sdkCredentialProvider,\n });\n const resp = await client.send(new GetCallerIdentityCommand({}));\n credProvider.accountId = resp.Account!;\n}\n\nfunction getStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n): AwsCredentialIdentityProvider {\n return async () => {\n return Promise.resolve({\n accessKeyId: accessKeyId,\n secretAccessKey: secretAccessKey,\n });\n };\n}\n\nfunction getProfileCredentials(\n profile: string,\n region?: string,\n): AwsCredentialIdentityProvider {\n return fromIni({\n profile,\n clientConfig: {\n region,\n customUserAgent: 'backstage-aws-credentials-manager',\n },\n });\n}\n\nfunction getDefaultCredentialsChain(): AwsCredentialIdentityProvider {\n return fromNodeProviderChain();\n}\n\n/**\n * Constructs the credential provider needed by the AWS SDK from the given account config\n *\n * Order of precedence:\n * 1. Assume role with static creds\n * 2. Assume role with main account creds\n * 3. Static creds\n * 4. Profile creds\n * 5. Default AWS SDK creds chain\n */\nfunction getSdkCredentialProvider(\n config: AwsIntegrationAccountConfig,\n mainAccountCredProvider: AwsCredentialIdentityProvider,\n): AwsCredentialIdentityProvider {\n if (config.roleName) {\n const region = config.region ?? 'us-east-1';\n const partition = config.partition ?? 'aws';\n\n return fromTemporaryCredentials({\n masterCredentials: config.accessKeyId\n ? getStaticCredentials(config.accessKeyId!, config.secretAccessKey!)\n : mainAccountCredProvider,\n params: {\n RoleArn: `arn:${partition}:iam::${config.accountId}:role/${config.roleName}`,\n RoleSessionName: 'backstage',\n ExternalId: config.externalId,\n },\n clientConfig: {\n region,\n customUserAgent: 'backstage-aws-credentials-manager',\n },\n });\n }\n\n if (config.accessKeyId) {\n return getStaticCredentials(config.accessKeyId!, config.secretAccessKey!);\n }\n\n if (config.profile) {\n return getProfileCredentials(config.profile!, config.region);\n }\n\n return getDefaultCredentialsChain();\n}\n\n/**\n * Constructs the credential provider needed by the AWS SDK for the main account\n *\n * Order of precedence:\n * 1. Static creds\n * 2. Profile creds\n * 3. Default AWS SDK creds chain\n */\nfunction getMainAccountSdkCredentialProvider(\n config: AwsIntegrationMainAccountConfig,\n): AwsCredentialIdentityProvider {\n if (config.accessKeyId) {\n return getStaticCredentials(config.accessKeyId!, config.secretAccessKey!);\n }\n\n if (config.profile) {\n return getProfileCredentials(config.profile!, config.region);\n }\n\n return getDefaultCredentialsChain();\n}\n\n/**\n * Handles the creation and caching of credential providers for AWS accounts.\n *\n * @public\n */\nexport class DefaultAwsCredentialsManager implements AwsCredentialsManager {\n static fromConfig(config: Config): DefaultAwsCredentialsManager {\n const awsConfig = config.has('aws')\n ? readAwsIntegrationConfig(config.getConfig('aws'))\n : {\n accounts: [],\n mainAccount: {},\n accountDefaults: {},\n };\n\n const mainAccountSdkCredProvider = getMainAccountSdkCredentialProvider(\n awsConfig.mainAccount,\n );\n const mainAccountCredProvider: AwsCredentialProvider = {\n sdkCredentialProvider: mainAccountSdkCredProvider,\n };\n\n const accountCredProviders = new Map<string, AwsCredentialProvider>();\n for (const accountConfig of awsConfig.accounts) {\n const sdkCredentialProvider = getSdkCredentialProvider(\n accountConfig,\n mainAccountSdkCredProvider,\n );\n accountCredProviders.set(accountConfig.accountId, {\n accountId: accountConfig.accountId,\n stsRegion: accountConfig.region,\n sdkCredentialProvider,\n });\n }\n\n return new DefaultAwsCredentialsManager(\n accountCredProviders,\n awsConfig.accountDefaults,\n mainAccountCredProvider,\n );\n }\n\n private constructor(\n private readonly accountCredentialProviders: Map<\n string,\n AwsCredentialProvider\n >,\n private readonly accountDefaults: AwsIntegrationDefaultAccountConfig,\n private readonly mainAccountCredentialProvider: AwsCredentialProvider,\n ) {}\n\n /**\n * Returns an {@link AwsCredentialProvider} for a given AWS account.\n *\n * @example\n * ```ts\n * const { provider } = await getCredentialProvider({\n * accountId: '0123456789012',\n * })\n *\n * const { provider } = await getCredentialProvider({\n * arn: 'arn:aws:ecs:us-west-2:123456789012:service/my-http-service'\n * })\n * ```\n *\n * @param opts - the AWS account ID or AWS resource ARN\n * @returns A promise of {@link AwsCredentialProvider}.\n */\n async getCredentialProvider(\n opts?: AwsCredentialProviderOptions,\n ): Promise<AwsCredentialProvider> {\n // If no options provided, fall back to the main account\n if (!opts) {\n await fillInAccountId(this.mainAccountCredentialProvider);\n return this.mainAccountCredentialProvider;\n }\n\n // Determine the account ID: either explicitly provided or extracted from the provided ARN\n let accountId = opts.accountId;\n if (opts.arn && !accountId) {\n const arnComponents = parse(opts.arn);\n accountId = arnComponents.accountId;\n }\n\n // If the account ID was not provided (explicitly or in the ARN),\n // fall back to the main account\n if (!accountId) {\n await fillInAccountId(this.mainAccountCredentialProvider);\n return this.mainAccountCredentialProvider;\n }\n\n // Return a cached provider if available\n if (this.accountCredentialProviders.has(accountId)) {\n return this.accountCredentialProviders.get(accountId)!;\n }\n\n // First, fall back to using the account defaults\n if (this.accountDefaults.roleName) {\n const config: AwsIntegrationAccountConfig = {\n accountId,\n roleName: this.accountDefaults.roleName,\n partition: this.accountDefaults.partition,\n region: this.accountDefaults.region,\n externalId: this.accountDefaults.externalId,\n };\n const sdkCredentialProvider = getSdkCredentialProvider(\n config,\n this.mainAccountCredentialProvider.sdkCredentialProvider,\n );\n const credProvider: AwsCredentialProvider = {\n accountId,\n sdkCredentialProvider,\n };\n this.accountCredentialProviders.set(accountId, credProvider);\n return credProvider;\n }\n\n // Then, fall back to using the main account, but only\n // if the account requested matches the main account ID\n await fillInAccountId(this.mainAccountCredentialProvider);\n if (accountId === this.mainAccountCredentialProvider.accountId) {\n return this.mainAccountCredentialProvider;\n }\n\n // Otherwise, the account needs to be explicitly configured in Backstage\n throw new Error(\n `There is no AWS integration that matches ${accountId}. Please add a configuration for this AWS account.`,\n );\n }\n}\n"],"names":["STSClient","GetCallerIdentityCommand","fromIni","fromNodeProviderChain","fromTemporaryCredentials","parse"],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import { AwsCredentialIdentityProvider } from '@aws-sdk/types';
2
+ import { Config } from '@backstage/config';
3
+
4
+ /**
5
+ * A set of credentials information for an AWS account.
6
+ *
7
+ * @public
8
+ */
9
+ declare type AwsCredentialProvider = {
10
+ /**
11
+ * The AWS account ID of these credentials
12
+ */
13
+ accountId?: string;
14
+ /**
15
+ * The STS region used with these credentials
16
+ */
17
+ stsRegion?: string;
18
+ /**
19
+ * The credential identity provider to use when creating AWS SDK for Javascript V3 clients
20
+ */
21
+ sdkCredentialProvider: AwsCredentialIdentityProvider;
22
+ };
23
+ /**
24
+ * The options for specifying the AWS credentials to retrieve.
25
+ *
26
+ * @public
27
+ */
28
+ declare type AwsCredentialProviderOptions = {
29
+ /**
30
+ * The AWS account ID, e.g. '0123456789012'
31
+ */
32
+ accountId?: string;
33
+ /**
34
+ * The resource ARN that will be accessed with the returned credentials.
35
+ * If account ID or region are not specified, they will be inferred from the ARN.
36
+ */
37
+ arn?: string;
38
+ };
39
+ /**
40
+ * This allows implementations to be provided to retrieve AWS credentials.
41
+ *
42
+ * @public
43
+ */
44
+ interface AwsCredentialsManager {
45
+ /**
46
+ * Get credentials for an AWS account.
47
+ */
48
+ getCredentialProvider(opts?: AwsCredentialProviderOptions): Promise<AwsCredentialProvider>;
49
+ }
50
+
51
+ /**
52
+ * Handles the creation and caching of credential providers for AWS accounts.
53
+ *
54
+ * @public
55
+ */
56
+ declare class DefaultAwsCredentialsManager implements AwsCredentialsManager {
57
+ private readonly accountCredentialProviders;
58
+ private readonly accountDefaults;
59
+ private readonly mainAccountCredentialProvider;
60
+ static fromConfig(config: Config): DefaultAwsCredentialsManager;
61
+ private constructor();
62
+ /**
63
+ * Returns an {@link AwsCredentialProvider} for a given AWS account.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const { provider } = await getCredentialProvider({
68
+ * accountId: '0123456789012',
69
+ * })
70
+ *
71
+ * const { provider } = await getCredentialProvider({
72
+ * arn: 'arn:aws:ecs:us-west-2:123456789012:service/my-http-service'
73
+ * })
74
+ * ```
75
+ *
76
+ * @param opts - the AWS account ID or AWS resource ARN
77
+ * @returns A promise of {@link AwsCredentialProvider}.
78
+ */
79
+ getCredentialProvider(opts?: AwsCredentialProviderOptions): Promise<AwsCredentialProvider>;
80
+ }
81
+
82
+ export { AwsCredentialProvider, AwsCredentialProviderOptions, AwsCredentialsManager, DefaultAwsCredentialsManager };
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@backstage/integration-aws-node",
3
+ "description": "Helpers for fetching AWS account credentials",
4
+ "version": "0.0.0-nightly-20221213023404",
5
+ "main": "dist/index.cjs.js",
6
+ "types": "dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "main": "dist/index.cjs.js",
10
+ "module": "dist/index.esm.js",
11
+ "types": "dist/index.d.ts"
12
+ },
13
+ "backstage": {
14
+ "role": "node-library"
15
+ },
16
+ "homepage": "https://backstage.io",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/backstage/backstage",
20
+ "directory": "packages/integration-aws-node"
21
+ },
22
+ "keywords": [
23
+ "backstage"
24
+ ],
25
+ "license": "Apache-2.0",
26
+ "scripts": {
27
+ "build": "backstage-cli package build",
28
+ "lint": "backstage-cli package lint",
29
+ "test": "backstage-cli package test",
30
+ "prepack": "backstage-cli package prepack",
31
+ "postpack": "backstage-cli package postpack",
32
+ "clean": "backstage-cli package clean"
33
+ },
34
+ "dependencies": {
35
+ "@aws-sdk/client-sts": "^3.208.0",
36
+ "@aws-sdk/credential-provider-node": "^3.208.0",
37
+ "@aws-sdk/credential-providers": "^3.208.0",
38
+ "@aws-sdk/types": "^3.208.0",
39
+ "@aws-sdk/util-arn-parser": "^3.208.0",
40
+ "@backstage/config": "^0.0.0-nightly-20221213023404",
41
+ "@backstage/errors": "^0.0.0-nightly-20221213023404"
42
+ },
43
+ "devDependencies": {
44
+ "@backstage/cli": "^0.0.0-nightly-20221213023404",
45
+ "@backstage/config-loader": "^0.0.0-nightly-20221213023404",
46
+ "@backstage/test-utils": "^0.0.0-nightly-20221213023404",
47
+ "aws-sdk-client-mock": "^2.0.0",
48
+ "aws-sdk-client-mock-jest": "^2.0.0"
49
+ },
50
+ "files": [
51
+ "dist",
52
+ "config.d.ts"
53
+ ],
54
+ "configSchema": "config.d.ts",
55
+ "module": "dist/index.esm.js"
56
+ }