Implement proper AWS Credentials precedence
This properly configures the precedence for explicit assume-role ARNs, explicit AWS credentials (via access keys), and the default fallback for the AWS SDK. The general precedence of using: 1. explicitly provided credentials 2. AWS SDK config (AWS.config.credentials) 3. AWS SDK credentials provider chain (AWS.config.credentialProviders) has been respected. This removes the need to explicitly configure `AWS.config.credentials` in Backstage installations also. Signed-off-by: Joel Low <joel@joelsplace.sg>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/techdocs-common': patch
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Implement proper AWS Credentials precedence with assume-role and explicit credentials
|
||||
@@ -19,6 +19,8 @@ import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
export { Credentials } from 'aws-sdk';
|
||||
|
||||
const rootDir = os.platform() === 'win32' ? 'C:\\rootDir' : '/rootDir';
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,32 +63,7 @@ export class AwsS3Publish implements PublisherBase {
|
||||
const credentialsConfig = config.getOptionalConfig(
|
||||
'techdocs.publisher.awsS3.credentials',
|
||||
);
|
||||
let accessKeyId = undefined;
|
||||
let secretAccessKey = undefined;
|
||||
let credentials: Credentials | CredentialsOptions | undefined = undefined;
|
||||
if (credentialsConfig) {
|
||||
const roleArn = credentialsConfig.getOptionalString('roleArn');
|
||||
if (roleArn && aws.config.credentials instanceof Credentials) {
|
||||
credentials = new aws.ChainableTemporaryCredentials({
|
||||
masterCredentials: aws.config.credentials as Credentials,
|
||||
params: {
|
||||
RoleSessionName: 'backstage-aws-techdocs-s3-publisher',
|
||||
RoleArn: roleArn,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
accessKeyId = credentialsConfig.getOptionalString('accessKeyId');
|
||||
secretAccessKey = credentialsConfig.getOptionalString(
|
||||
'secretAccessKey',
|
||||
);
|
||||
if (accessKeyId && secretAccessKey) {
|
||||
credentials = {
|
||||
accessKeyId,
|
||||
secretAccessKey,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
const credentials = AwsS3Publish.buildCredentials(credentialsConfig);
|
||||
|
||||
// AWS Region is an optional config. If missing, default AWS env variable AWS_REGION
|
||||
// or AWS shared credentials file at ~/.aws/credentials will be used.
|
||||
@@ -133,6 +108,37 @@ export class AwsS3Publish implements PublisherBase {
|
||||
return new AwsS3Publish(storageClient, bucketName, logger);
|
||||
}
|
||||
|
||||
private static buildCredentials(
|
||||
config?: Config,
|
||||
): Credentials | CredentialsOptions | undefined {
|
||||
if (!config) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const accessKeyId = config.getOptionalString('accessKeyId');
|
||||
const secretAccessKey = config.getOptionalString('secretAccessKey');
|
||||
let explicitCredentials: Credentials | undefined;
|
||||
if (accessKeyId && secretAccessKey) {
|
||||
explicitCredentials = new Credentials({
|
||||
accessKeyId,
|
||||
secretAccessKey,
|
||||
});
|
||||
}
|
||||
|
||||
const roleArn = config.getOptionalString('roleArn');
|
||||
if (roleArn) {
|
||||
return new aws.ChainableTemporaryCredentials({
|
||||
masterCredentials: explicitCredentials,
|
||||
params: {
|
||||
RoleSessionName: 'backstage-aws-techdocs-s3-publisher',
|
||||
RoleArn: roleArn,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return explicitCredentials;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly storageClient: aws.S3,
|
||||
private readonly bucketName: string,
|
||||
|
||||
+19
-13
@@ -51,25 +51,31 @@ export class AwsOrganizationCloudAccountProcessor implements CatalogProcessor {
|
||||
});
|
||||
}
|
||||
|
||||
private static buildCredentials(
|
||||
config: AwsOrganizationProviderConfig,
|
||||
): Credentials | undefined {
|
||||
const roleArn = config.roleArn;
|
||||
if (!roleArn) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return new AWS.ChainableTemporaryCredentials({
|
||||
params: {
|
||||
RoleSessionName: 'backstage-aws-organization-processor',
|
||||
RoleArn: roleArn,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
constructor(options: {
|
||||
provider: AwsOrganizationProviderConfig;
|
||||
logger: Logger;
|
||||
}) {
|
||||
this.provider = options.provider;
|
||||
this.logger = options.logger;
|
||||
let credentials = undefined;
|
||||
if (
|
||||
this.provider.roleArn !== undefined &&
|
||||
AWS.config.credentials instanceof Credentials
|
||||
) {
|
||||
credentials = new AWS.ChainableTemporaryCredentials({
|
||||
masterCredentials: AWS.config.credentials as Credentials,
|
||||
params: {
|
||||
RoleSessionName: 'backstage-aws-organization-processor',
|
||||
RoleArn: this.provider.roleArn,
|
||||
},
|
||||
});
|
||||
}
|
||||
const credentials = AwsOrganizationCloudAccountProcessor.buildCredentials(
|
||||
this.provider,
|
||||
);
|
||||
this.organizations = new AWS.Organizations({
|
||||
credentials,
|
||||
region: AWS_ORGANIZATION_REGION,
|
||||
|
||||
Reference in New Issue
Block a user