設定 CDK Toolkit 的外掛程式 - AWS 雲端開發套件 (AWS CDK) v2

這是 AWS CDK v2 開發人員指南。較舊的 CDK v1 已於 2022 年 6 月 1 日進入維護,並於 2023 年 6 月 1 日結束支援。

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

設定 CDK Toolkit 的外掛程式

AWS CDK Toolkit 支援將新功能新增至 CDK 工作流程的外掛程式。外掛程式主要設計用於 CDK 命令列界面 (CDK CLI),但也可以透過程式設計方式與 CDK Toolkit Library 搭配使用。它們提供標準化的方式來擴展功能,例如替代登入資料來源。

注意

雖然外掛程式系統同時適用於 CDK CLI 和 CDK Toolkit Library,但主要用於 CLI 使用。以程式設計方式使用 CDK Toolkit Library 時,通常有更簡單、更直接的方式來在沒有外掛程式的情況下完成相同的任務,特別是用於憑證管理。

目前,CDK Toolkit 支援一個外掛程式功能:

  • 自訂 AWS 登入資料提供者 - 建立替代方法,以取得內建機制以外的 AWS 登入資料。

如何建立外掛程式

若要建立 CDK Toolkit 外掛程式,請先建立以 TypeScript 或 JavaScript 撰寫的 Node.js 模組,該模組可由 CDK Toolkit 載入。本單元會匯出具有 CDK Toolkit 可辨識之特定結構的物件。至少,匯出的物件必須包含版本識別符和接收IPluginHost執行個體的初始化函數,外掛程式會使用它來註冊其功能。

TypeScript
CommonJS
// 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
CommonJS
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 Toolkit 外掛程式會載入為 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 Toolkit Library 將外掛程式載入程式碼

以程式設計方式使用 CDK Toolkit Library 時,您可以使用@aws-cdk/toolkit-lib套件中的PluginHost執行個體,直接將外掛程式載入程式碼中。PluginHost 提供依模組名稱或路徑載入外掛程式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 模組名稱。

  • JavaScript 或 TypeScript 模組的相對或絕對檔案路徑。

實作登入資料提供者外掛程式

外掛程式目前的主要使用案例是建立自訂 AWS 登入資料提供者。如同 AWS CLI,CDK CLI 需要 AWS 登入資料才能進行身分驗證和授權。不過,在下列幾種情況下,標準登入資料解析可能會失敗:

  • 無法取得初始的登入資料集。

  • 無法取得初始登入資料所屬的帳戶。

  • 與登入資料相關聯的帳戶與 CLI 嘗試操作的帳戶不同。

為了解決這些案例,CDK Toolkit 支援登入資料提供者外掛程式。這些外掛程式實作來自 @aws-cdk/cli-plugin-contract套件的 CredentialProviderSource 界面,並使用 registerCredentialProviderSource方法向 Toolkit 註冊。這可讓 CDK Toolkit 從非標準來源取得 AWS 登入資料,例如專門的身分驗證系統或自訂登入資料存放區。

若要實作自訂登入資料提供者,請建立實作所需界面的類別:

TypeScript
CommonJS
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
CommonJS
// 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 Toolkit 快取。強烈建議提供者傳回的登入資料物件進行自我重新整理,以防止長時間執行操作期間發生過期問題。如需詳細資訊,請參閱適用於 JavaScript v3 的 AWS SDK 文件中的登入資料。

進一步了解

若要進一步了解 CDK Toolkit 外掛程式,請參閱 aws-cdk-cli GitHub 儲存庫中的 AWS CDK Toolkit 外掛程式合約