Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .projenrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,6 @@ const toolkitLib = configureProject(
`@aws-sdk/ec2-metadata-service@${CLI_SDK_V3_RANGE}`,
`@aws-sdk/lib-storage@${CLI_SDK_V3_RANGE}`,
'@smithy/middleware-endpoint',
'@smithy/node-http-handler',
'@smithy/property-provider',
'@smithy/shared-ini-file-loader',
'@smithy/util-retry',
Expand Down Expand Up @@ -872,7 +871,7 @@ new pj.JsonFile(toolkitLib, 'api-extractor.json', {
logLevel: 'none',
},
'ae-forgotten-export': {
logLevel: 'warning', // @todo fix issues and change to error
logLevel: 'error',
},
},
tsdocMessageReporting: {
Expand Down
4 changes: 0 additions & 4 deletions packages/@aws-cdk/toolkit-lib/.projen/deps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@aws-cdk/toolkit-lib/.projen/tasks.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/@aws-cdk/toolkit-lib/api-extractor.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { format } from 'node:util';
import type { SDKv3CompatibleCredentialProvider } from '@aws-cdk/cli-plugin-contract';
import { createCredentialChain, fromEnv, fromIni, fromNodeProviderChain } from '@aws-sdk/credential-providers';
import { MetadataService } from '@aws-sdk/ec2-metadata-service';
import type { NodeHttpHandlerOptions } from '@smithy/node-http-handler';
import { loadSharedConfigFiles } from '@smithy/shared-ini-file-loader';
import type { RequestHandlerSettings } from './base-credentials';
import { makeCachingProvider } from './provider-caching';
import type { ISdkLogger } from './sdk-logger';
import { AuthenticationError } from '../../toolkit/toolkit-error';
Expand All @@ -23,10 +23,10 @@ const DEFAULT_TIMEOUT = 300000;
*/
export class AwsCliCompatible {
private readonly ioHelper: IoHelper;
private readonly requestHandler: NodeHttpHandlerOptions;
private readonly requestHandler: RequestHandlerSettings;
private readonly logger?: ISdkLogger;

public constructor(ioHelper: IoHelper, requestHandler: NodeHttpHandlerOptions, logger?: ISdkLogger) {
public constructor(ioHelper: IoHelper, requestHandler: RequestHandlerSettings, logger?: ISdkLogger) {
this.ioHelper = ioHelper;
this.requestHandler = requestHandler;
this.logger = logger;
Expand Down Expand Up @@ -269,7 +269,7 @@ export interface CredentialChainOptions {
readonly logger?: ISdkLogger;
}

export function sdkRequestHandler(agent?: Agent): NodeHttpHandlerOptions {
export function sdkRequestHandler(agent?: Agent): RequestHandlerSettings {
return {
connectionTimeout: DEFAULT_CONNECTION_TIMEOUT,
requestTimeout: DEFAULT_TIMEOUT,
Expand Down
165 changes: 165 additions & 0 deletions packages/@aws-cdk/toolkit-lib/lib/api/aws-auth/base-credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import type * as http from 'node:http';
import type * as https from 'node:https';
import type { SDKv3CompatibleCredentialProvider } from '@aws-cdk/cli-plugin-contract';
import { AwsCliCompatible } from './awscli-compatible';
import { AuthenticationError } from '../../toolkit/toolkit-error';
import type { IActionAwareIoHost } from '../io';
import { IoHostSdkLogger } from './sdk-logger';
import { IoHelper } from '../io/private';

/**
* Settings for the request handle
*/
export interface RequestHandlerSettings {
/**
* The maximum time in milliseconds that the connection phase of a request
* may take before the connection attempt is abandoned.
*
* Defaults to 0, which disables the timeout.
*/
connectionTimeout?: number;
/**
* The number of milliseconds a request can take before automatically being terminated.
* Defaults to 0, which disables the timeout.
*/
requestTimeout?: number;
/**
* An http.Agent to be used
*/
httpAgent?: http.Agent;
/**
* An https.Agent to be used
*/
httpsAgent?: https.Agent;
}

/**
* An SDK config that
*/
export interface SdkBaseConfig {
/**
* The credential provider to use for SDK calls.
*/
readonly credentialProvider: SDKv3CompatibleCredentialProvider;
/**
* The default region to use for SDK calls.
*/
readonly defaultRegion?: string;
}

export interface SdkBaseClientConfig {
requestHandler?: RequestHandlerSettings;
}

export interface IBaseCredentialsProvider {
sdkBaseConfig(ioHost: IActionAwareIoHost, clientConfig: SdkBaseClientConfig): Promise<SdkBaseConfig>;
}

export class BaseCredentials {
/**
* Use no base credentials
*
* There will be no current account and no current region during synthesis. To
* successfully deploy with this set of base credentials:
*
* - The CDK app must provide concrete accounts and regions during synthesis
* - Credential plugins must be installed to provide credentials for those
* accounts.
*/
public static none(): IBaseCredentialsProvider {
return new class implements IBaseCredentialsProvider {
public async sdkBaseConfig() {
return {
credentialProvider: () => {
throw new AuthenticationError('No credentials available due to BaseCredentials.none()');
},
};
}

public toString() {
return 'BaseCredentials.none()';
}
};
}

/**
* Obtain base credentials and base region the same way the AWS CLI would
*
* Credentials and region will be read from the environment first, falling back
* to INI files or other sources if available.
*
* The profile name is configurable.
*/
public static awsCliCompatible(options: AwsCliCompatibleOptions = {}): IBaseCredentialsProvider {
return new class implements IBaseCredentialsProvider {
public sdkBaseConfig(ioHost: IActionAwareIoHost, clientConfig: SdkBaseClientConfig) {
const ioHelper = IoHelper.fromActionAwareIoHost(ioHost);
const awsCli = new AwsCliCompatible(ioHelper, clientConfig.requestHandler ?? {}, new IoHostSdkLogger(ioHelper));
return awsCli.baseConfig(options.profile);
}

public toString() {
return `BaseCredentials.awsCliCompatible(${JSON.stringify(options)})`;
}
};
}

/**
* Use a custom SDK identity provider for the base credentials
*
* If your provider uses STS calls to obtain base credentials, you must make
* sure to also configure the necessary HTTP options (like proxy and user
* agent) and the region on the STS client directly; the toolkit code cannot
* do this for you.
*/
public static custom(options: CustomBaseCredentialsOption): IBaseCredentialsProvider {
return new class implements IBaseCredentialsProvider {
public sdkBaseConfig(): Promise<SdkBaseConfig> {
return Promise.resolve({
credentialProvider: options.provider,
defaultRegion: options.region,
});
}

public toString() {
return `BaseCredentials.custom(${JSON.stringify({
...options,
provider: '...',
})})`;
}
};
}
}

export interface AwsCliCompatibleOptions {
/**
* The profile to read from `~/.aws/credentials`.
*
* If not supplied the environment variable AWS_PROFILE will be used.
*
* @default - Use environment variable if set.
*/
readonly profile?: string;
}

export interface CustomBaseCredentialsOption {
/**
* The credentials provider to use to obtain base credentials
*
* If your provider uses STS calls to obtain base credentials, you must make
* sure to also configure the necessary HTTP options (like proxy and user
* agent) on the STS client directly; the toolkit code cannot do this for you.
*/
readonly provider: SDKv3CompatibleCredentialProvider;

/**
* The default region to synthesize for
*
* CDK applications can override this region. NOTE: this region will *not*
* affect any STS calls made by the given provider, if any. You need to configure
* your credential provider separately.
*
* @default 'us-east-1'
*/
readonly region?: string;
}
1 change: 1 addition & 0 deletions packages/@aws-cdk/toolkit-lib/lib/api/aws-auth/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './types';
export * from './base-credentials';
67 changes: 31 additions & 36 deletions packages/@aws-cdk/toolkit-lib/lib/api/aws-auth/sdk-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import type { Environment } from '@aws-cdk/cx-api';
import { EnvironmentUtils, UNKNOWN_ACCOUNT, UNKNOWN_REGION } from '@aws-cdk/cx-api';
import type { AssumeRoleCommandInput } from '@aws-sdk/client-sts';
import { fromTemporaryCredentials } from '@aws-sdk/credential-providers';
import type { NodeHttpHandlerOptions } from '@smithy/node-http-handler';
import { AwsCliCompatible } from './awscli-compatible';
import type { RequestHandlerSettings } from './base-credentials';
import { cached } from './cached';
import { CredentialPlugins } from './credential-plugins';
import { makeCachingProvider } from './provider-caching';
Expand All @@ -23,13 +23,26 @@ export type AssumeRoleAdditionalOptions = Partial<Omit<AssumeRoleCommandInput, '
/**
* Options for the default SDK provider
*/
export interface SdkProviderOptions extends SdkProviderServices {
export interface SdkProviderOptions {
/**
* Profile to read from ~/.aws
*
* @default - No profile
* An IO helper for emitting messages
*/
readonly ioHelper: IoHelper;

/**
* The request handler settings
*/
readonly profile?: string;
readonly requestHandler?: RequestHandlerSettings;

/**
* A plugin host
*/
readonly pluginHost?: PluginHost;

/**
* An SDK logger
*/
readonly logger?: ISdkLogger;
}

const CACHED_ACCOUNT = Symbol('cached_account');
Expand Down Expand Up @@ -91,31 +104,35 @@ export class SdkProvider {
*
* The AWS SDK for JS behaves slightly differently from the AWS CLI in a number of ways; see the
* class `AwsCliCompatible` for the details.
*
* @param options - Options for the default SDK provider
* @param profile - Profile to read from ~/.aws
* @returns a configured SdkProvider
*/
public static async withAwsCliCompatibleDefaults(options: SdkProviderOptions) {
public static async withAwsCliCompatibleDefaults(options: SdkProviderOptions, profile?: string) {
callTrace(SdkProvider.withAwsCliCompatibleDefaults.name, SdkProvider.constructor.name, options.logger);
const config = await new AwsCliCompatible(options.ioHelper, options.requestHandler ?? {}, options.logger).baseConfig(options.profile);
const config = await new AwsCliCompatible(options.ioHelper, options.requestHandler ?? {}, options.logger).baseConfig(profile);
return new SdkProvider(config.credentialProvider, config.defaultRegion, options);
}

public readonly defaultRegion: string;
private readonly defaultCredentialProvider: SDKv3CompatibleCredentialProvider;
private readonly plugins;
private readonly requestHandler: NodeHttpHandlerOptions;
private readonly requestHandler: RequestHandlerSettings;
private readonly ioHelper: IoHelper;
private readonly logger?: ISdkLogger;

public constructor(
defaultCredentialProvider: SDKv3CompatibleCredentialProvider,
defaultRegion: string | undefined,
services: SdkProviderServices,
options: SdkProviderOptions,
) {
this.defaultCredentialProvider = defaultCredentialProvider;
this.defaultRegion = defaultRegion ?? 'us-east-1';
this.requestHandler = services.requestHandler ?? {};
this.ioHelper = services.ioHelper;
this.logger = services.logger;
this.plugins = new CredentialPlugins(services.pluginHost ?? new PluginHost(), this.ioHelper);
this.requestHandler = options.requestHandler ?? {};
this.ioHelper = options.ioHelper;
this.logger = options.logger;
this.plugins = new CredentialPlugins(options.pluginHost ?? new PluginHost(), this.ioHelper);
}

/**
Expand Down Expand Up @@ -528,25 +545,3 @@ export async function initContextProviderSdk(aws: SdkProvider, options: ContextL

return (await aws.forEnvironment(EnvironmentUtils.make(account, region), Mode.ForReading, creds)).sdk;
}

export interface SdkProviderServices {
/**
* An IO helper for emitting messages
*/
readonly ioHelper: IoHelper;

/**
* The request handler settings
*/
readonly requestHandler?: NodeHttpHandlerOptions;

/**
* A plugin host
*/
readonly pluginHost?: PluginHost;

/**
* An SDK logger
*/
readonly logger?: ISdkLogger;
}
6 changes: 3 additions & 3 deletions packages/@aws-cdk/toolkit-lib/lib/api/aws-auth/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,10 +352,10 @@ import {
import { GetCallerIdentityCommand, STSClient } from '@aws-sdk/client-sts';
import { Upload } from '@aws-sdk/lib-storage';
import { getEndpointFromInstructions } from '@smithy/middleware-endpoint';
import type { NodeHttpHandlerOptions } from '@smithy/node-http-handler';
import { ConfiguredRetryStrategy } from '@smithy/util-retry';
import type { WaiterResult } from '@smithy/util-waiter';
import { AccountAccessKeyCache } from './account-cache';
import type { RequestHandlerSettings } from './base-credentials';
import { cachedAsync } from './cached';
import type { ISdkLogger } from './sdk-logger';
import type { Account } from './sdk-provider';
Expand Down Expand Up @@ -395,7 +395,7 @@ export interface SdkOptions {
export interface ConfigurationOptions {
region: string;
credentials: SDKv3CompatibleCredentialProvider;
requestHandler: NodeHttpHandlerOptions;
requestHandler: RequestHandlerSettings;
retryStrategy: ConfiguredRetryStrategy;
customUserAgent: string;
logger?: ISdkLogger;
Expand Down Expand Up @@ -605,7 +605,7 @@ export class SDK {
constructor(
private readonly credProvider: SDKv3CompatibleCredentialProvider,
region: string,
requestHandler: NodeHttpHandlerOptions,
requestHandler: RequestHandlerSettings,
ioHelper: IoHelper,
logger?: ISdkLogger,
) {
Expand Down
Loading