为 CDK 工具包配置插件 - AWS Cloud Development Kit (AWS CDK) v2

这是 AWS CDK v2 开发者指南。旧版 CDK v1 于 2022 年 6 月 1 日进入维护阶段,并于 2023 年 6 月 1 日终止支持。

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

为 CDK 工具包配置插件

AWS CDK 工具包支持为你的 CDK 工作流程添加新功能的插件。插件主要是为与 CDK 命令行界面 (CDK CLI) 配合使用而设计的,但它们也可以通过编程方式与 CDK 工具包库一起使用。它们提供了一种扩展功能的标准化方法,例如备用凭证来源。

注意

虽然插件系统可与 CDK CLI 和 CDK 工具包库配合使用,但它主要用于 CLI。以编程方式使用 CDK Toolkit 库时,通常有更简单、更直接的方法可以在不使用插件的情况下完成同样的任务,尤其是在凭据管理方面。

目前,CDK 工具包支持一种插件功能:

  • 自定义 AWS 凭证提供商-创建替代方法来获取内置机制之外的 AWS 凭证。

如何创建插件

要创建 CDK Toolkit 插件,首先要创建一个 Node.js 模块,该模块是在 TypeScript 或中创作的 JavaScript,可以由 CDK 工具包加载。该模块导出一个具有 CDK 工具包可以识别的特定结构的对象。导出的对象必须至少包含版本标识符和用于接收实例的初始化函数,插件使用该IPluginHost实例来注册其功能。

TypeScript
CommonJ
// Example plugin structure import type { IPluginHost, Plugin } from '@aws-cdk/cli-plugin-contract'; const plugin: Plugin = { // Version of the plugin infrastructure (currently always '1') version: '1', // Initialization function called when the plugin is loaded init(host: IPluginHost): void { // Register your plugin functionality with the host // For example, register a custom credential provider } }; export = plugin;
ESM
// Example plugin structure import type { IPluginHost, Plugin } from '@aws-cdk/cli-plugin-contract'; const plugin: Plugin = { // Version of the plugin infrastructure (currently always '1') version: '1', // Initialization function called when the plugin is loaded init(host: IPluginHost): void { // Register your plugin functionality with the host // For example, register a custom credential provider } }; export { plugin as 'module.exports' };
JavaScript
CommonJ
const plugin = { // Version of the plugin infrastructure (currently always '1') version: '1', // Initialization function called when the plugin is loaded init(host) { // Register your plugin functionality with the host // For example, register a custom credential provider } }; module.exports = plugin;
ESM
const plugin = { // Version of the plugin infrastructure (currently always '1') version: '1', // Initialization function called when the plugin is loaded init(host) { // Register your plugin functionality with the host // For example, register a custom credential provider } }; export { plugin as 'module.exports' };
注意

CDK 工具包插件作为 CommonJS 模块加载。你可以将你的插件构建为一个 ECMAScript 模块 (ESM),但必须遵守一些限制

  • 该模块不能包含顶级模块await,也不能导入任何包含顶层的模块await

  • 该模块必须通过导出名称module.exports导出插件对象来确保兼容性:export { plugin as 'module.exports' }

如何使用 CDK CLI 加载插件

您可以通过两个选项来指定插件:

选项 1:使用--plugin命令行选项
# Load a single plugin $ cdk list --plugin=my-custom-plugin # Load multiple plugins $ cdk deploy --plugin=custom-plugin-1 --plugin=custom-plugin-2

--plugin参数的值应该是一个 JavaScript 文件,当通过 Node.js require() 函数导入时,该文件会返回一个实现该Plugin接口的对象。

选项 2:向配置文件添加条目

您可以将插件规范添加到项目特定的cdk.json文件或~/.cdk.json全局配置文件中:

{ "plugin": [ "custom-plugin-1", "custom-plugin-2" ] }

无论采用哪种方法,CDK CLI 都将在运行命令之前加载指定的插件。

使用 CDK 工具包库在代码中加载插件

以编程方式使用 CDK Toolkit 库时,您可以使用软件包中的PluginHost实例直接在代码中加载插件。@aws-cdk/toolkit-libPluginHost提供了一种按模块名称或路径加载插件load()的方法。

TypeScript
import { Toolkit } from '@aws-cdk/toolkit-lib'; // Create a Toolkit instance const toolkit = new Toolkit(); // Load a plugin by module name or path // The module must export an object matching the Plugin interface await toolkit.pluginHost.load('my-custom-plugin'); // You can load multiple plugins if needed await toolkit.pluginHost.load('./path/to/another-plugin'); // Now proceed with other CDK Toolkit Library operations // The plugin's functionality will be available to the toolkit
JavaScript
const { Toolkit } = require('@aws-cdk/toolkit-lib'); // Create a Toolkit instance const toolkit = new Toolkit(); // Load a plugin by module name or path // The module must export an object matching the Plugin interface await toolkit.pluginHost.load('my-custom-plugin'); // You can load multiple plugins if needed await toolkit.pluginHost.load('./path/to/another-plugin'); // Now proceed with other CDK Toolkit Library operations // The plugin's functionality will be available to the toolkit

load()方法采用单个参数moduleSpec,即要加载的插件模块的名称或路径。这可以是:

  • node_modules目录中安装的 Node.js 模块名称。

  • 或 TypeScript 模块的相对或绝对文件路径。 JavaScript

实现凭证提供者插件

插件当前的主要用例是创建自定义 AWS 凭证提供程序。与 AWS CLI 一样,CDK CLI 需要 AWS 凭据进行身份验证和授权。但是,在某些情况下,标准凭证解析可能会失败:

  • 无法获取初始凭证集。

  • 无法获取初始证书所属的账户。

  • 与凭证关联的账户与 CLI 尝试操作的账户不同。

为了解决这些情况,CDK 工具包支持凭证提供程序插件。这些插件实现了@aws-cdk/cli-plugin-contract软件包中的CredentialProviderSource接口,并使用registerCredentialProviderSource方法注册到工具包中。这使得 AWS CDK Toolkit 能够从非标准来源(例如专门的身份验证系统或自定义凭据存储)获取证书。

要实现自定义凭证提供程序,请创建一个实现所需接口的类:

TypeScript
CommonJ
import type { CredentialProviderSource, ForReading, ForWriting, IPluginHost, Plugin, PluginProviderResult, SDKv3CompatibleCredentials } from '@aws-cdk/cli-plugin-contract'; class CustomCredentialProviderSource implements CredentialProviderSource { // Friendly name for the provider, used in error messages public readonly name: string = 'custom-credential-provider'; // Check if this provider is available on the current system public async isAvailable(): Promise<boolean> { // Return false if the plugin cannot be used // For example, if it depends on files not present on the host return true; } // Check if this provider can provide credentials for a specific account public async canProvideCredentials(accountId: string): Promise<boolean> { // Return false if the plugin cannot provide credentials for this account // For example, if the account is not managed by this credential system return true; // You can use patterns to filter specific accounts // return accountId.startsWith('123456'); } // Get credentials for the specified account and access mode // Returns PluginProviderResult which can be one of: // - SDKv2CompatibleCredentials (AWS SDK v2 entered maintenance on Sept 8, 2024 and will reach end-of-life on Sept 8, 2025) // - SDKv3CompatibleCredentialProvider // - SDKv3CompatibleCredentials public async getProvider(accountId: string, mode: ForReading | ForWriting): Promise<PluginProviderResult> { // The access mode can be used to provide different credential sets const readOnly = mode === 0 satisfies ForReading; // Create appropriate credentials based on your authentication mechanism const credentials: SDKv3CompatibleCredentials = { accessKeyId: 'AKIAIOSFODNN7EXAMPLE', secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', // Add sessionToken if using temporary credentials // sessionToken: 'AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4Olgk', // expireTime: new Date(Date.now() + 3600 * 1000), // 1 hour from now }; return credentials; } } const plugin: Plugin = { version: '1', init(host: IPluginHost): void { // Register the credential provider to the PluginHost. host.registerCredentialProviderSource(new CustomCredentialProviderSource()); } }; export = plugin;
ESM
import type { CredentialProviderSource, ForReading, ForWriting, IPluginHost, Plugin, PluginProviderResult, SDKv3CompatibleCredentials } from '@aws-cdk/cli-plugin-contract'; class CustomCredentialProviderSource implements CredentialProviderSource { // Friendly name for the provider, used in error messages public readonly name: string = 'custom-credential-provider'; // Check if this provider is available on the current system public async isAvailable(): Promise<boolean> { // Return false if the plugin cannot be used // For example, if it depends on files not present on the host return true; } // Check if this provider can provide credentials for a specific account public async canProvideCredentials(accountId: string): Promise<boolean> { // Return false if the plugin cannot provide credentials for this account // For example, if the account is not managed by this credential system return true; // You can use patterns to filter specific accounts // return accountId.startsWith('123456'); } // Get credentials for the specified account and access mode // Returns PluginProviderResult which can be one of: // - SDKv2CompatibleCredentials (AWS SDK v2 entered maintenance on Sept 8, 2024 and will reach end-of-life on Sept 8, 2025) // - SDKv3CompatibleCredentialProvider // - SDKv3CompatibleCredentials public async getProvider(accountId: string, mode: ForReading | ForWriting): Promise<PluginProviderResult> { // The access mode can be used to provide different credential sets const readOnly = mode === 0 satisfies ForReading; // Create appropriate credentials based on your authentication mechanism const credentials: SDKv3CompatibleCredentials = { accessKeyId: 'AKIAIOSFODNN7EXAMPLE', secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', // Add sessionToken if using temporary credentials // sessionToken: 'AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4Olgk', // expireTime: new Date(Date.now() + 3600 * 1000), // 1 hour from now }; return credentials; } } const plugin: Plugin = { version: '1', init(host: IPluginHost): void { // Register the credential provider to the PluginHost. host.registerCredentialProviderSource(new CustomCredentialProviderSource()); } }; export { plugin as 'module.exports' };
JavaScript
CommonJ
// Implement the CredentialProviderSource interface class CustomCredentialProviderSource { constructor() { // Friendly name for the provider, used in error messages this.name = 'custom-credential-provider'; } // Check if this provider is available on the current system async isAvailable() { // Return false if the plugin cannot be used // For example, if it depends on files not present on the host return true; } // Check if this provider can provide credentials for a specific account async canProvideCredentials(accountId) { // Return false if the plugin cannot provide credentials for this account // For example, if the account is not managed by this credential system return true; // You can use patterns to filter specific accounts // return accountId.startsWith('123456'); } // Get credentials for the specified account and access mode // Returns PluginProviderResult which can be one of: // - SDKv2CompatibleCredentials (AWS SDK v2 entered maintenance on Sept 8, 2024 and will reach end-of-life on Sept 8, 2025) // - SDKv3CompatibleCredentialProvider // - SDKv3CompatibleCredentials async getProvider(accountId, mode) { // The access mode can be used to provide different credential sets const readOnly = mode === 0; // 0 indicates ForReading; 1 indicates ForWriting // Create appropriate credentials based on your authentication mechanism const credentials = { accessKeyId: 'ASIAIOSFODNN7EXAMPLE', secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', // Add sessionToken if using temporary credentials // sessionToken: 'AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4Olgk', // expireTime: new Date(Date.now() + 3600 * 1000), // 1 hour from now }; return credentials; } } const plugin = { version: '1', init(host) { // Register the credential provider to the PluginHost. host.registerCredentialProviderSource(new CustomCredentialProviderSource()); } }; module.exports = plugin;
ESM
// Implement the CredentialProviderSource interface class CustomCredentialProviderSource { constructor() { // Friendly name for the provider, used in error messages this.name = 'custom-credential-provider'; } // Check if this provider is available on the current system async isAvailable() { // Return false if the plugin cannot be used // For example, if it depends on files not present on the host return true; } // Check if this provider can provide credentials for a specific account async canProvideCredentials(accountId) { // Return false if the plugin cannot provide credentials for this account // For example, if the account is not managed by this credential system return true; // You can use patterns to filter specific accounts // return accountId.startsWith('123456'); } // Get credentials for the specified account and access mode // Returns PluginProviderResult which can be one of: // - SDKv2CompatibleCredentials (AWS SDK v2 entered maintenance on Sept 8, 2024 and will reach end-of-life on Sept 8, 2025) // - SDKv3CompatibleCredentialProvider // - SDKv3CompatibleCredentials async getProvider(accountId, mode) { // The access mode can be used to provide different credential sets const readOnly = mode === 0; // 0 indicates ForReading; 1 indicates ForWriting // Create appropriate credentials based on your authentication mechanism const credentials = { accessKeyId: 'ASIAIOSFODNN7EXAMPLE', secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', // Add sessionToken if using temporary credentials // sessionToken: 'AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4Olgk', // expireTime: new Date(Date.now() + 3600 * 1000), // 1 hour from now }; return credentials; } } const plugin = { version: '1', init(host) { // Register the credential provider to the PluginHost. host.registerCredentialProviderSource(new CustomCredentialProviderSource()); } }; export { plugin as 'module.exports' };
重要

CDK 工具包会缓存从提供商处获得的证书。强烈建议您的提供商返回的凭证对象可以自动刷新,以防止在长时间运行的操作中出现过期问题。有关更多信息,请参阅适用于 JavaScript v3 的 AWS SDK 文档中的凭证

了解更多

要了解有关 CDK 工具包插件的更多信息,请参阅存储库中的 AWS CDK 工具包插件合同。aws-cdk-cli GitHub