Skip to content

Commit 0aaf11f

Browse files
committed
add documentation on cdk plugins
1 parent 387cc82 commit 0aaf11f

File tree

2 files changed

+308
-0
lines changed

2 files changed

+308
-0
lines changed

v2/guide/book.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ include::chapter-deploy.adoc[leveloffset=+1]
5555

5656
include::blueprints.adoc[leveloffset=+1]
5757

58+
include::plugins.adoc[leveloffset=+1]
59+
5860
include::toolkit-library.adoc[leveloffset=+1]
5961

6062
include::testing.adoc[leveloffset=+1]

v2/guide/plugins.adoc

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
include::attributes.txt[]
2+
3+
// Attributes
4+
5+
[.topic]
6+
[#plugins]
7+
= Configure plugins for the CDK Toolkit
8+
:info_titleabbrev: Configure plugins
9+
:keywords: CDK Command Line Interface, CDK CLI, {aws} CDK, {aws} Cloud Development Kit ({aws} CDK), credentials, plugins, CDK Toolkit, CDK Toolkit Library
10+
11+
[abstract]
12+
--
13+
The {aws} CDK Toolkit provides a plugin system that enables developers to extend its functionality.
14+
--
15+
16+
// Content start
17+
18+
The {aws} CDK Toolkit supports plugins that add new capabilities to your CDK workflows. Plugins are primarily designed for use with the CDK Command Line Interface (CDK CLI), though they can also be used with the CDK Toolkit Library programmatically. They provide a standardized way to extend functionality, such as alternative credential sources.
19+
20+
[NOTE]
21+
====
22+
While the plugin system works with both the CDK CLI and CDK Toolkit Library, it is primarily intended for CLI usage. When using the CDK Toolkit Library programmatically, there are often simpler, more direct ways to accomplish the same tasks without plugins, particularly for credential management.
23+
====
24+
25+
Currently, the CDK Toolkit supports one plugin capability:
26+
27+
* *Custom {aws} credential providers* - Create alternative methods to obtain {aws} credentials beyond the built-in mechanisms.
28+
29+
[#plugins-create]
30+
== How to create plugins
31+
32+
To create a CDK Toolkit plugin, you first create a Node.js module, authored in TypeScript or JavaScript, that can be loaded by the CDK Toolkit. This module exports an object with a specific structure that the CDK Toolkit can recognize. At minimum, the exported object must include a version identifier and an initialization function that receives an `IPluginHost` instance, which the plugin uses to register its capabilities.
33+
34+
====
35+
[role="tablist"]
36+
TypeScript::
37+
+
38+
[source,typescript,subs="verbatim,attributes"]
39+
----
40+
// Example plugin structure
41+
import type { IPluginHost } from '@aws-cdk/cli-plugin-contract';
42+
43+
export = {
44+
// Version of the plugin infrastructure (currently always '1')
45+
version: '1',
46+
47+
// Initialization function called when the plugin is loaded
48+
init(host: IPluginHost): void {
49+
// Register your plugin functionality with the host
50+
// For example, register a custom credential provider
51+
}
52+
};
53+
----
54+
55+
JavaScript::
56+
+
57+
[source,javascript,subs="verbatim,attributes"]
58+
----
59+
module.exports = {
60+
// Version of the plugin infrastructure (currently always '1')
61+
version: '1',
62+
63+
// Initialization function called when the plugin is loaded
64+
init(host) {
65+
// Register your plugin functionality with the host
66+
// For example, register a custom credential provider
67+
}
68+
};
69+
----
70+
====
71+
72+
[#plugins-load-cli]
73+
== How to load plugins with the CDK CLI
74+
75+
You have two options to specify plugins:
76+
77+
*Option 1: Use the `--plugin` command line option*::
78+
+
79+
[source,bash,subs="verbatim,attributes"]
80+
----
81+
# Load a single plugin
82+
$ cdk list --plugin=my-custom-plugin
83+
84+
# Load multiple plugins
85+
$ cdk deploy --plugin=custom-plugin-1 --plugin=custom-plugin-2
86+
----
87+
+
88+
The value of the `--plugin` argument should be a JavaScript file that, when imported via the Node.js `require()` function, returns an object implementing the `Plugin` interface.
89+
90+
*Option 2: Add entries to configuration files*::
91+
+
92+
You can add plugin specifications to the project-specific `cdk.json` file or the `~/.cdk.json` global configuration file:
93+
+
94+
[source,json,subs="verbatim,attributes"]
95+
----
96+
{
97+
"plugin": [
98+
"custom-plugin-1",
99+
"custom-plugin-2"
100+
]
101+
}
102+
----
103+
+
104+
With either approach, the CDK CLI will load the specified plugins before running commands.
105+
106+
[#plugins-load-library]
107+
=== Load plugins in code with the CDK Toolkit Library
108+
109+
When working with the CDK Toolkit Library programmatically, you can load plugins directly in your code using the `PluginHost` instance from the `@aws-cdk/toolkit-lib` package. The `PluginHost` provides a `load()` method for loading plugins by module name or path.
110+
111+
====
112+
[role="tablist"]
113+
TypeScript::
114+
+
115+
[source,typescript,subs="verbatim,attributes"]
116+
----
117+
import { Toolkit } from '@aws-cdk/toolkit-lib';
118+
119+
// Create a Toolkit instance
120+
const toolkit = new Toolkit();
121+
122+
// Load a plugin by module name or path
123+
// The module must export an object matching the Plugin interface
124+
await toolkit.pluginHost.load('my-custom-plugin');
125+
126+
// You can load multiple plugins if needed
127+
await toolkit.pluginHost.load('./path/to/another-plugin');
128+
129+
// Now proceed with other CDK Toolkit Library operations
130+
// The plugin's functionality will be available to the toolkit
131+
----
132+
133+
JavaScript::
134+
+
135+
[source,javascript,subs="verbatim,attributes"]
136+
----
137+
const { Toolkit } = require('@aws-cdk/toolkit-lib');
138+
139+
// Create a Toolkit instance
140+
const toolkit = new Toolkit();
141+
142+
// Load a plugin by module name or path
143+
// The module must export an object matching the Plugin interface
144+
await toolkit.pluginHost.load('my-custom-plugin');
145+
146+
// You can load multiple plugins if needed
147+
await toolkit.pluginHost.load('./path/to/another-plugin');
148+
149+
// Now proceed with other CDK Toolkit Library operations
150+
// The plugin's functionality will be available to the toolkit
151+
----
152+
====
153+
154+
The `load()` method takes a single parameter, `moduleSpec`, which is the name or path of the plugin module to load. This can be either:
155+
156+
* A Node.js module name installed in the `node_modules` directory.
157+
* A relative or absolute file path to a JavaScript or TypeScript module.
158+
159+
[#plugins-credentials]
160+
== Implementing credential provider plugins
161+
162+
The current primary use case for plugins is to create custom {aws} credential providers. Like the {aws} CLI, the CDK CLI needs {aws} credentials for authentication and authorization. However, there are several scenarios where the standard credential resolution might fail:
163+
164+
* The initial set of credentials cannot be obtained.
165+
* The account to which the initial credentials belong cannot be obtained.
166+
* The account associated with the credentials is different from the account on which the CLI is trying to operate.
167+
168+
To address these scenarios, the CDK Toolkit supports credential provider plugins. These plugins implement the `CredentialProviderSource` interface from the `@aws-cdk/cli-plugin-contract` package and are registered to the Toolkit using the `registerCredentialProviderSource` method. This enables the CDK Toolkit to obtain {aws} credentials from non-standard sources like specialized authentication systems or custom credential stores.
169+
170+
To implement a custom credential provider, create a class that implements the required interface:
171+
172+
====
173+
[role="tablist"]
174+
TypeScript::
175+
+
176+
[source,typescript,subs="verbatim,attributes"]
177+
----
178+
import type { IPluginHost } from '@aws-cdk/cli-plugin-contract';
179+
import { registerCredentialProviderSource, Mode, CredentialProviderSource } from '@aws-cdk/cli-plugin-contract';
180+
import { Credentials } from '@aws-sdk/client-sts';
181+
182+
class CustomCredentialProviderSource implements CredentialProviderSource {
183+
// Friendly name for the provider, used in error messages
184+
public readonly name: string = 'custom-credential-provider';
185+
186+
// Check if this provider is available on the current system
187+
public async isAvailable(): Promise<boolean> {
188+
// Return false if the plugin cannot be used
189+
// For example, if it depends on files not present on the host
190+
return true;
191+
}
192+
193+
// Check if this provider can provide credentials for a specific account
194+
public async canProvideCredentials(accountId: string): Promise<boolean> {
195+
// Return false if the plugin cannot provide credentials for this account
196+
// For example, if the account is not managed by this credential system
197+
return true;
198+
// You can use patterns to filter specific accounts
199+
// return accountId.startsWith('123456');
200+
}
201+
202+
// Get credentials for the specified account and access mode
203+
// Returns PluginProviderResult which can be one of:
204+
// - SDKv2CompatibleCredentials (AWS SDK v2 entered maintenance on Sept 8, 2024 and will reach end-of-life on Sept 8, 2025)
205+
// - SDKv3CompatibleCredentialProvider
206+
// - SDKv3CompatibleCredentials
207+
public async getProvider(accountId: string, mode: Mode): Promise<PluginProviderResult> {
208+
// The access mode can be used to provide different credential sets
209+
const readOnly = mode === Mode.ForReading;
210+
211+
// Create appropriate credentials based on your authentication mechanism
212+
// In this example we're using AWS SDK v3 credentials
213+
const credentials = new Credentials({
214+
accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
215+
secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
216+
// Add sessionToken if using temporary credentials
217+
// sessionToken: 'AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4Olgk',
218+
// expireTime: new Date(Date.now() + 3600 * 1000), // 1 hour from now
219+
});
220+
221+
return credentials;
222+
}
223+
}
224+
225+
export = {
226+
version = '1',
227+
init(host: IPluginHost): void {
228+
// Register the credential provider to the PluginHost.
229+
host.registerCredentialProviderSource(new CustomCredentialProviderSource());
230+
}
231+
};
232+
----
233+
234+
JavaScript::
235+
+
236+
[source,javascript,subs="verbatim,attributes"]
237+
----
238+
const { Mode, registerCredentialProviderSource, CredentialProviderSource } = require('@aws-cdk/cli-plugin-contract');
239+
const { Credentials } = require('@aws-sdk/client-sts');
240+
241+
// Implement the CredentialProviderSource interface
242+
class CustomCredentialProviderSource extends CredentialProviderSource {
243+
constructor() {
244+
super();
245+
// Friendly name for the provider, used in error messages
246+
this.name = 'custom-credential-provider';
247+
}
248+
249+
// Check if this provider is available on the current system
250+
async isAvailable() {
251+
// Return false if the plugin cannot be used
252+
// For example, if it depends on files not present on the host
253+
return true;
254+
}
255+
256+
// Check if this provider can provide credentials for a specific account
257+
async canProvideCredentials(accountId) {
258+
// Return false if the plugin cannot provide credentials for this account
259+
// For example, if the account is not managed by this credential system
260+
return true;
261+
// You can use patterns to filter specific accounts
262+
// return accountId.startsWith('123456');
263+
}
264+
265+
// Get credentials for the specified account and access mode
266+
// Returns PluginProviderResult which can be one of:
267+
// - SDKv2CompatibleCredentials (AWS SDK v2 entered maintenance on Sept 8, 2024 and will reach end-of-life on Sept 8, 2025)
268+
// - SDKv3CompatibleCredentialProvider
269+
// - SDKv3CompatibleCredentials
270+
async getProvider(accountId, mode) {
271+
// The access mode can be used to provide different credential sets
272+
const readOnly = mode === Mode.ForReading;
273+
274+
// Create appropriate credentials based on your authentication mechanism
275+
// In this example we're using AWS SDK v3 credentials
276+
const credentials = new Credentials({
277+
accessKeyId: 'ASIAIOSFODNN7EXAMPLE',
278+
secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
279+
// Add sessionToken if using temporary credentials
280+
// sessionToken: 'AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4Olgk',
281+
// expireTime: new Date(Date.now() + 3600 * 1000), // 1 hour from now
282+
});
283+
284+
return credentials;
285+
}
286+
}
287+
288+
module.exports = {
289+
version = '1',
290+
init(host) {
291+
// Register the credential provider to the PluginHost.
292+
host.registerCredentialProviderSource(new CustomCredentialProviderSource());
293+
}
294+
};
295+
----
296+
====
297+
298+
[IMPORTANT]
299+
====
300+
Credentials obtained from providers are cached by the CDK Toolkit. It's strongly recommended that credential objects returned by your provider are self-refreshing to prevent expiration issues during long-running operations. For more information, see link:https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-sts/Interface/Credentials/[Credentials] in the _{aws} SDK for JavaScript v3 documentation_.
301+
====
302+
303+
[#plugins-learn]
304+
== Learn more
305+
306+
To learn more about CDK Toolkit plugins, see the link:https://github.com/aws/aws-cdk-cli/tree/main/packages/%40aws-cdk/cli-plugin-contract[{aws} CDK Toolkit Plugin Contract] in the _aws-cdk-cli GitHub repository_.

0 commit comments

Comments
 (0)