@cloud-copilot/iam-collect
Version:
Collect IAM information from AWS Accounts
133 lines • 5.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.now = now;
exports.getNewCredentials = getNewCredentials;
exports.getNewInitialCredentials = getNewInitialCredentials;
exports.buildRoleArn = buildRoleArn;
const credential_providers_1 = require("@aws-sdk/credential-providers");
const log_1 = require("@cloud-copilot/log");
const strings_js_1 = require("../utils/strings.js");
const tokens_js_1 = require("./tokens.js");
/**
* What time is it now?
*
* This exists to make unit tests of caching behavior easier.
*
* @returns the current timestamp in milliseconds since the Unix epoch
*/
function now() {
return Date.now();
}
/**
* Get brand new credentials for the given account ID and auth configuration.
*
* DO NOT USE THIS DIRECTLY. Use `getCredentials` in `auth.ts` instead
*
* @param accountId the AWS account ID for which to get credentials
* @param authConfig the authentication configuration to use for the account
* @returns new credentials based on the provided account ID and auth configuration
*/
async function getNewCredentials(accountId, authConfig) {
const cacheKey = await (0, strings_js_1.shortHash)(JSON.stringify({ accountId, authConfig }));
const baseCredentials = await getNewInitialCredentials(authConfig, {
accountId
});
let credentials = baseCredentials;
if (authConfig?.role) {
const roleArn = buildRoleArn(baseCredentials.partition, accountId, authConfig.role.pathAndName);
log_1.log.trace({ accountId, roleArn, sourceAccount: baseCredentials.accountId }, 'Assuming role for account with credentials');
const roleProvider = (0, credential_providers_1.fromTemporaryCredentials)({
masterCredentials: baseCredentials.provider,
params: {
RoleArn: roleArn,
ExternalId: authConfig.role.externalId,
RoleSessionName: authConfig.role.sessionName || `iam-collect-${(0, strings_js_1.randomCharacters)()}`
}
});
credentials = {
cacheKey,
provider: roleProvider,
accountId: accountId,
partition: baseCredentials.partition
};
}
else if (baseCredentials.accountId != accountId) {
// If the account ID from the credentials doesn't match the expected account ID and no role is specified
// throw an error to indicate that the credentials do not match the expected account
log_1.log.error('Auth config, account mismatch', {
desiredAccountId: accountId,
currentAccountId: baseCredentials.accountId
});
throw new Error(`The credentials provided do not match the expected account ID ${accountId}. Found ${baseCredentials.accountId}. Please check your auth configuration.`);
}
return credentials;
}
/**
* This gets a new set of initial credentials for an auth configuration. These are the initial
* credentials that are the default credentials are used to then assume a role if one is specified.
* There are very few cases where this should be used directly, and in most cases you should use
* getNewCredentials instead.
*
* @param authConfig the authentication configuration to use
* @param logInfo any additional information to log while getting the credentials
* @returns new credentials based on the provided auth configuration
*/
async function getNewInitialCredentials(authConfig, logInfo = {}) {
let provider;
let credentials;
const cacheKey = await (0, strings_js_1.shortHash)(JSON.stringify({ authConfig }));
if (authConfig?.profile) {
log_1.log.trace({ ...logInfo, profile: authConfig.profile }, 'Using profile for credentials');
provider = (0, credential_providers_1.fromIni)({ profile: authConfig.profile });
credentials = await provider();
}
else {
log_1.log.trace(logInfo, 'Using default SDK credential chain');
provider = (0, credential_providers_1.fromNodeProviderChain)();
credentials = await provider();
}
let tokenInfo = await (0, tokens_js_1.getTokenInfo)(credentials);
log_1.log.trace('initial credentials', tokenInfo);
if (authConfig?.initialRole) {
let roleArn;
if ('arn' in authConfig?.initialRole) {
roleArn = authConfig.initialRole.arn;
}
else {
roleArn = buildRoleArn(tokenInfo.partition, tokenInfo.accountId, authConfig.initialRole.pathAndName);
}
log_1.log.trace({ roleArn, sourceAccount: tokenInfo.accountId, ...logInfo }, 'Assuming initial role for account with credentials');
const roleProvider = (0, credential_providers_1.fromTemporaryCredentials)({
masterCredentials: credentials,
params: {
RoleArn: roleArn,
ExternalId: authConfig.initialRole.externalId,
RoleSessionName: authConfig.initialRole.sessionName || `iam-collect-${(0, strings_js_1.randomCharacters)()}`
}
});
provider = roleProvider;
credentials = await roleProvider();
tokenInfo = await (0, tokens_js_1.getTokenInfo)(credentials);
}
return {
cacheKey,
provider,
accountId: tokenInfo.accountId,
partition: tokenInfo.partition
};
}
/**
* Get the ARN for an IAM role.
*
* @param partition The partition the role is in (e.g. "aws", "aws-us-gov", "aws-cn").
* @param accountId The ID of the account the role is in.
* @param rolePathAndName The path and name of the role.
* @returns The ARN of the role.
*/
function buildRoleArn(partition, accountId, rolePathAndName) {
if (!rolePathAndName.startsWith('/')) {
rolePathAndName = `/${rolePathAndName}`;
}
return `arn:${partition}:iam::${accountId}:role${rolePathAndName}`;
}
//# sourceMappingURL=coreAuth.js.map