aws-cdk-lib


Nameaws-cdk-lib JSON
Version 2.170.0 PyPI version JSON
download
home_pagehttps://github.com/aws/aws-cdk
SummaryVersion 2 of the AWS Cloud Development Kit library
upload_time2024-11-22 04:42:53
maintainerNone
docs_urlNone
authorAmazon Web Services
requires_python~=3.8
licenseApache-2.0
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # AWS Cloud Development Kit Library

The AWS CDK construct library provides APIs to define your CDK application and add
CDK constructs to the application.

## Usage

### Upgrade from CDK 1.x

When upgrading from CDK 1.x, remove all dependencies to individual CDK packages
from your dependencies file and follow the rest of the sections.

### Installation

To use this package, you need to declare this package and the `constructs` package as
dependencies.

According to the kind of project you are developing:

For projects that are CDK libraries in NPM, declare them both under the `devDependencies` **and** `peerDependencies` sections.
To make sure your library is compatible with the widest range of CDK versions: pick the minimum `aws-cdk-lib` version
that your library requires; declare a range dependency with a caret on that version in peerDependencies, and declare a
point version dependency on that version in devDependencies.

For example, let's say the minimum version your library needs is `2.38.0`. Your `package.json` should look like this:

```javascript
{
  "peerDependencies": {
    "aws-cdk-lib": "^2.38.0",
    "constructs": "^10.0.0"
  },
  "devDependencies": {
    /* Install the oldest version for testing so we don't accidentally use features from a newer version than we declare */
    "aws-cdk-lib": "2.38.0"
  }
}
```

For CDK apps, declare them under the `dependencies` section. Use a caret so you always get the latest version:

```json
{
  "dependencies": {
    "aws-cdk-lib": "^2.38.0",
    "constructs": "^10.0.0"
  }
}
```

### Use in your code

#### Classic import

You can use a classic import to get access to each service namespaces:

```python
from aws_cdk import Stack, App, aws_s3 as s3

app = App()
stack = Stack(app, "TestStack")

s3.Bucket(stack, "TestBucket")
```

#### Barrel import

Alternatively, you can use "barrel" imports:

```python
from aws_cdk import App, Stack
from aws_cdk.aws_s3 import Bucket

app = App()
stack = Stack(app, "TestStack")

Bucket(stack, "TestBucket")
```

<!--BEGIN CORE DOCUMENTATION-->

## Stacks and Stages

A `Stack` is the smallest physical unit of deployment, and maps directly onto
a CloudFormation Stack. You define a Stack by defining a subclass of `Stack`
-- let's call it `MyStack` -- and instantiating the constructs that make up
your application in `MyStack`'s constructor. You then instantiate this stack
one or more times to define different instances of your application. For example,
you can instantiate it once using few and cheap EC2 instances for testing,
and once again using more and bigger EC2 instances for production.

When your application grows, you may decide that it makes more sense to split it
out across multiple `Stack` classes. This can happen for a number of reasons:

* You could be starting to reach the maximum number of resources allowed in a single
  stack (this is currently 500).
* You could decide you want to separate out stateful resources and stateless resources
  into separate stacks, so that it becomes easy to tear down and recreate the stacks
  that don't have stateful resources.
* There could be a single stack with resources (like a VPC) that are shared
  between multiple instances of other stacks containing your applications.

As soon as your conceptual application starts to encompass multiple stacks,
it is convenient to wrap them in another construct that represents your
logical application. You can then treat that new unit the same way you used
to be able to treat a single stack: by instantiating it multiple times
for different instances of your application.

You can define a custom subclass of `Stage`, holding one or more
`Stack`s, to represent a single logical instance of your application.

As a final note: `Stack`s are not a unit of reuse. They describe physical
deployment layouts, and as such are best left to application builders to
organize their deployments with. If you want to vend a reusable construct,
define it as a subclasses of `Construct`: the consumers of your construct
will decide where to place it in their own stacks.

## Stack Synthesizers

Each Stack has a *synthesizer*, an object that determines how and where
the Stack should be synthesized and deployed. The synthesizer controls
aspects like:

* How does the stack reference assets? (Either through CloudFormation
  parameters the CLI supplies, or because the Stack knows a predefined
  location where assets will be uploaded).
* What roles are used to deploy the stack? These can be bootstrapped
  roles, roles created in some other way, or just the CLI's current
  credentials.

The following synthesizers are available:

* `DefaultStackSynthesizer`: recommended. Uses predefined asset locations and
  roles created by the modern bootstrap template. Access control is done by
  controlling who can assume the deploy role. This is the default stack
  synthesizer in CDKv2.
* `LegacyStackSynthesizer`: Uses CloudFormation parameters to communicate
  asset locations, and the CLI's current permissions to deploy stacks. This
  is the default stack synthesizer in CDKv1.
* `CliCredentialsStackSynthesizer`: Uses predefined asset locations, and the
  CLI's current permissions.

Each of these synthesizers takes configuration arguments. To configure
a stack with a synthesizer, pass it as one of its properties:

```python
MyStack(app, "MyStack",
    synthesizer=DefaultStackSynthesizer(
        file_assets_bucket_name="amzn-s3-demo-bucket"
    )
)
```

For more information on bootstrapping accounts and customizing synthesis,
see [Bootstrapping in the CDK Developer Guide](https://docs.aws.amazon.com/cdk/latest/guide/bootstrapping.html).

## Nested Stacks

[Nested stacks](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html) are stacks created as part of other stacks. You create a nested stack within another stack by using the `NestedStack` construct.

As your infrastructure grows, common patterns can emerge in which you declare the same components in multiple templates. You can separate out these common components and create dedicated templates for them. Then use the resource in your template to reference other templates, creating nested stacks.

For example, assume that you have a load balancer configuration that you use for most of your stacks. Instead of copying and pasting the same configurations into your templates, you can create a dedicated template for the load balancer. Then, you just use the resource to reference that template from within other templates.

The following example will define a single top-level stack that contains two nested stacks: each one with a single Amazon S3 bucket:

```python
class MyNestedStack(cfn.NestedStack):
    def __init__(self, scope, id, *, parameters=None, timeout=None, notifications=None):
        super().__init__(scope, id, parameters=parameters, timeout=timeout, notifications=notifications)

        s3.Bucket(self, "NestedBucket")

class MyParentStack(Stack):
    def __init__(self, scope, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None):
        super().__init__(scope, id, description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation)

        MyNestedStack(self, "Nested1")
        MyNestedStack(self, "Nested2")
```

Resources references across nested/parent boundaries (even with multiple levels of nesting) will be wired by the AWS CDK
through CloudFormation parameters and outputs. When a resource from a parent stack is referenced by a nested stack,
a CloudFormation parameter will automatically be added to the nested stack and assigned from the parent; when a resource
from a nested stack is referenced by a parent stack, a CloudFormation output will be automatically be added to the
nested stack and referenced using `Fn::GetAtt "Outputs.Xxx"` from the parent.

Nested stacks also support the use of Docker image and file assets.

## Accessing resources in a different stack

You can access resources in a different stack, as long as they are in the
same account and AWS Region (see [next section](#accessing-resources-in-a-different-stack-and-region) for an exception).
The following example defines the stack `stack1`,
which defines an Amazon S3 bucket. Then it defines a second stack, `stack2`,
which takes the bucket from stack1 as a constructor property.

```python
prod = {"account": "123456789012", "region": "us-east-1"}

stack1 = StackThatProvidesABucket(app, "Stack1", env=prod)

# stack2 will take a property { bucket: IBucket }
stack2 = StackThatExpectsABucket(app, "Stack2",
    bucket=stack1.bucket,
    env=prod
)
```

If the AWS CDK determines that the resource is in the same account and
Region, but in a different stack, it automatically synthesizes AWS
CloudFormation
[Exports](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-exports.html)
in the producing stack and an
[Fn::ImportValue](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-importvalue.html)
in the consuming stack to transfer that information from one stack to the
other.

## Accessing resources in a different stack and region

> **This feature is currently experimental**

You can enable the Stack property `crossRegionReferences`
in order to access resources in a different stack *and* region. With this feature flag
enabled it is possible to do something like creating a CloudFront distribution in `us-east-2` and
an ACM certificate in `us-east-1`.

```python
stack1 = Stack(app, "Stack1",
    env=Environment(
        region="us-east-1"
    ),
    cross_region_references=True
)
cert = acm.Certificate(stack1, "Cert",
    domain_name="*.example.com",
    validation=acm.CertificateValidation.from_dns(route53.PublicHostedZone.from_hosted_zone_id(stack1, "Zone", "Z0329774B51CGXTDQV3X"))
)

stack2 = Stack(app, "Stack2",
    env=Environment(
        region="us-east-2"
    ),
    cross_region_references=True
)
cloudfront.Distribution(stack2, "Distribution",
    default_behavior=cloudfront.BehaviorOptions(
        origin=origins.HttpOrigin("example.com")
    ),
    domain_names=["dev.example.com"],
    certificate=cert
)
```

When the AWS CDK determines that the resource is in a different stack *and* is in a different
region, it will "export" the value by creating a custom resource in the producing stack which
creates SSM Parameters in the consuming region for each exported value. The parameters will be
created with the name '/cdk/exports/${consumingStackName}/${export-name}'.
In order to "import" the exports into the consuming stack a [SSM Dynamic reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#dynamic-references-ssm)
is used to reference the SSM parameter which was created.

In order to mimic strong references, a Custom Resource is also created in the consuming
stack which marks the SSM parameters as being "imported". When a parameter has been successfully
imported, the producing stack cannot update the value.

> [!NOTE]
> As a consequence of this feature being built on a Custom Resource, we are restricted to a
> CloudFormation response body size limitation of [4096 bytes](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html).
> To prevent deployment errors related to the Custom Resource Provider response body being too
> large, we recommend limiting the use of nested stacks and minimizing the length of stack names.
> Doing this will prevent SSM parameter names from becoming too long which will reduce the size of the
> response body.

See the [adr](https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/core/adr/cross-region-stack-references.md)
for more details on this feature.

### Removing automatic cross-stack references

The automatic references created by CDK when you use resources across stacks
are convenient, but may block your deployments if you want to remove the
resources that are referenced in this way. You will see an error like:

```text
Export Stack1:ExportsOutputFnGetAtt-****** cannot be deleted as it is in use by Stack1
```

Let's say there is a Bucket in the `stack1`, and the `stack2` references its
`bucket.bucketName`. You now want to remove the bucket and run into the error above.

It's not safe to remove `stack1.bucket` while `stack2` is still using it, so
unblocking yourself from this is a two-step process. This is how it works:

DEPLOYMENT 1: break the relationship

* Make sure `stack2` no longer references `bucket.bucketName` (maybe the consumer
  stack now uses its own bucket, or it writes to an AWS DynamoDB table, or maybe you just
  remove the Lambda Function altogether).
* In the `stack1` class, call `this.exportValue(this.bucket.bucketName)`. This
  will make sure the CloudFormation Export continues to exist while the relationship
  between the two stacks is being broken.
* Deploy (this will effectively only change the `stack2`, but it's safe to deploy both).

DEPLOYMENT 2: remove the resource

* You are now free to remove the `bucket` resource from `stack1`.
* Don't forget to remove the `exportValue()` call as well.
* Deploy again (this time only the `stack1` will be changed -- the bucket will be deleted).

## Durations

To make specifications of time intervals unambiguous, a single class called
`Duration` is used throughout the AWS Construct Library by all constructs
that that take a time interval as a parameter (be it for a timeout, a
rate, or something else).

An instance of Duration is constructed by using one of the static factory
methods on it:

```python
Duration.seconds(300) # 5 minutes
Duration.minutes(5) # 5 minutes
Duration.hours(1) # 1 hour
Duration.days(7) # 7 days
Duration.parse("PT5M")
```

Durations can be added or subtracted together:

```python
Duration.minutes(1).plus(Duration.seconds(60)) # 2 minutes
Duration.minutes(5).minus(Duration.seconds(10))
```

## Size (Digital Information Quantity)

To make specification of digital storage quantities unambiguous, a class called
`Size` is available.

An instance of `Size` is initialized through one of its static factory methods:

```python
Size.kibibytes(200) # 200 KiB
Size.mebibytes(5) # 5 MiB
Size.gibibytes(40) # 40 GiB
Size.tebibytes(200) # 200 TiB
Size.pebibytes(3)
```

Instances of `Size` created with one of the units can be converted into others.
By default, conversion to a higher unit will fail if the conversion does not produce
a whole number. This can be overridden by unsetting `integral` property.

```python
Size.mebibytes(2).to_kibibytes() # yields 2048
Size.kibibytes(2050).to_mebibytes(rounding=SizeRoundingBehavior.FLOOR)
```

## Secrets

To help avoid accidental storage of secrets as plain text, we use the `SecretValue` type to
represent secrets. Any construct that takes a value that should be a secret (such as
a password or an access key) will take a parameter of type `SecretValue`.

The best practice is to store secrets in AWS Secrets Manager and reference them using `SecretValue.secretsManager`:

```python
secret = SecretValue.secrets_manager("secretId",
    json_field="password",  # optional: key of a JSON field to retrieve (defaults to all content),
    version_id="id",  # optional: id of the version (default AWSCURRENT)
    version_stage="stage"
)
```

Using AWS Secrets Manager is the recommended way to reference secrets in a CDK app.
`SecretValue` also supports the following secret sources:

* `SecretValue.unsafePlainText(secret)`: stores the secret as plain text in your app and the resulting template (not recommended).
* `SecretValue.secretsManager(secret)`: refers to a secret stored in Secrets Manager
* `SecretValue.ssmSecure(param, version)`: refers to a secret stored as a SecureString in the SSM
  Parameter Store. If you don't specify the exact version, AWS CloudFormation uses the latest
  version of the parameter.
* `SecretValue.cfnParameter(param)`: refers to a secret passed through a CloudFormation parameter (must have `NoEcho: true`).
* `SecretValue.cfnDynamicReference(dynref)`: refers to a secret described by a CloudFormation dynamic reference (used by `ssmSecure` and `secretsManager`).
* `SecretValue.resourceAttribute(attr)`: refers to a secret returned from a CloudFormation resource creation.

`SecretValue`s should only be passed to constructs that accept properties of type
`SecretValue`. These constructs are written to ensure your secrets will not be
exposed where they shouldn't be. If you try to use a `SecretValue` in a
different location, an error about unsafe secret usage will be thrown at
synthesis time.

If you rotate the secret's value in Secrets Manager, you must also change at
least one property on the resource where you are using the secret, to force
CloudFormation to re-read the secret.

`SecretValue.ssmSecure()` is only supported for a limited set of resources.
[Click here for a list of supported resources and properties](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#template-parameters-dynamic-patterns-resources).

## ARN manipulation

Sometimes you will need to put together or pick apart Amazon Resource Names
(ARNs). The functions `stack.formatArn()` and `stack.splitArn()` exist for
this purpose.

`formatArn()` can be used to build an ARN from components. It will automatically
use the region and account of the stack you're calling it on:

```python
# stack: Stack


# Builds "arn:<PARTITION>:lambda:<REGION>:<ACCOUNT>:function:MyFunction"
stack.format_arn(
    service="lambda",
    resource="function",
    arn_format=ArnFormat.COLON_RESOURCE_NAME,
    resource_name="MyFunction"
)
```

`splitArn()` can be used to get a single component from an ARN. `splitArn()`
will correctly deal with both literal ARNs and deploy-time values (tokens),
but in case of a deploy-time value be aware that the result will be another
deploy-time value which cannot be inspected in the CDK application.

```python
# stack: Stack


# Extracts the function name out of an AWS Lambda Function ARN
arn_components = stack.split_arn(arn, ArnFormat.COLON_RESOURCE_NAME)
function_name = arn_components.resource_name
```

Note that the format of the resource separator depends on the service and
may be any of the values supported by `ArnFormat`. When dealing with these
functions, it is important to know the format of the ARN you are dealing with.

For an exhaustive list of ARN formats used in AWS, see [AWS ARNs and
Namespaces](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)
in the AWS General Reference.

## Dependencies

### Construct Dependencies

Sometimes AWS resources depend on other resources, and the creation of one
resource must be completed before the next one can be started.

In general, CloudFormation will correctly infer the dependency relationship
between resources based on the property values that are used. In the cases where
it doesn't, the AWS Construct Library will add the dependency relationship for
you.

If you need to add an ordering dependency that is not automatically inferred,
you do so by adding a dependency relationship using
`constructA.node.addDependency(constructB)`. This will add a dependency
relationship between all resources in the scope of `constructA` and all
resources in the scope of `constructB`.

If you want a single object to represent a set of constructs that are not
necessarily in the same scope, you can use a `DependencyGroup`. The
following creates a single object that represents a dependency on two
constructs, `constructB` and `constructC`:

```python
# Declare the dependable object
b_and_c = DependencyGroup()
b_and_c.add(construct_b)
b_and_c.add(construct_c)

# Take the dependency
construct_a.node.add_dependency(b_and_c)
```

### Stack Dependencies

Two different stack instances can have a dependency on one another. This
happens when an resource from one stack is referenced in another stack. In
that case, CDK records the cross-stack referencing of resources,
automatically produces the right CloudFormation primitives, and adds a
dependency between the two stacks. You can also manually add a dependency
between two stacks by using the `stackA.addDependency(stackB)` method.

A stack dependency has the following implications:

* Cyclic dependencies are not allowed, so if `stackA` is using resources from
  `stackB`, the reverse is not possible anymore.
* Stacks with dependencies between them are treated specially by the CDK
  toolkit:

  * If `stackA` depends on `stackB`, running `cdk deploy stackA` will also
    automatically deploy `stackB`.
  * `stackB`'s deployment will be performed *before* `stackA`'s deployment.

### CfnResource Dependencies

To make declaring dependencies between `CfnResource` objects easier, you can declare dependencies from one `CfnResource` object on another by using the `cfnResource1.addDependency(cfnResource2)` method. This method will work for resources both within the same stack and across stacks as it detects the relative location of the two resources and adds the dependency either to the resource or between the relevant stacks, as appropriate. If more complex logic is in needed, you can similarly remove, replace, or view dependencies between `CfnResource` objects with the `CfnResource` `removeDependency`, `replaceDependency`, and `obtainDependencies` methods, respectively.

## Custom Resources

Custom Resources are CloudFormation resources that are implemented by arbitrary
user code. They can do arbitrary lookups or modifications during a
CloudFormation deployment.

Custom resources are backed by *custom resource providers*. Commonly, these are
Lambda Functions that are deployed in the same deployment as the one that
defines the custom resource itself, but they can also be backed by Lambda
Functions deployed previously, or code responding to SNS Topic events running on
EC2 instances in a completely different account. For more information on custom
resource providers, see the next section.

Once you have a provider, each definition of a `CustomResource` construct
represents one invocation. A single provider can be used for the implementation
of arbitrarily many custom resource definitions. A single definition looks like
this:

```python
CustomResource(self, "MyMagicalResource",
    resource_type="Custom::MyCustomResource",  # must start with 'Custom::'

    # the resource properties
    properties={
        "Property1": "foo",
        "Property2": "bar"
    },

    # the ARN of the provider (SNS/Lambda) which handles
    # CREATE, UPDATE or DELETE events for this resource type
    # see next section for details
    service_token="ARN"
)
```

### Custom Resource Providers

Custom resources are backed by a **custom resource provider** which can be
implemented in one of the following ways. The following table compares the
various provider types (ordered from low-level to high-level):

| Provider                                                             | Compute Type | Error Handling | Submit to CloudFormation |   Max Timeout   | Language | Footprint |
| -------------------------------------------------------------------- | :----------: | :------------: | :----------------------: | :-------------: | :------: | :-------: |
| [sns.Topic](#amazon-sns-topic)                                       | Self-managed |     Manual     |          Manual          |    Unlimited    |   Any    |  Depends  |
| [lambda.Function](#aws-lambda-function)                              |  AWS Lambda  |     Manual     |          Manual          |      15min      |   Any    |   Small   |
| [core.CustomResourceProvider](#the-corecustomresourceprovider-class) |  AWS Lambda  |      Auto      |           Auto           |      15min      | Node.js  |   Small   |
| [custom-resources.Provider](#the-custom-resource-provider-framework) |  AWS Lambda  |      Auto      |           Auto           | Unlimited Async |   Any    |   Large   |

Legend:

* **Compute type**: which type of compute can be used to execute the handler.
* **Error Handling**: whether errors thrown by handler code are automatically
  trapped and a FAILED response is submitted to CloudFormation. If this is
  "Manual", developers must take care of trapping errors. Otherwise, events
  could cause stacks to hang.
* **Submit to CloudFormation**: whether the framework takes care of submitting
  SUCCESS/FAILED responses to CloudFormation through the event's response URL.
* **Max Timeout**: maximum allows/possible timeout.
* **Language**: which programming languages can be used to implement handlers.
* **Footprint**: how many resources are used by the provider framework itself.

**A NOTE ABOUT SINGLETONS**

When defining resources for a custom resource provider, you will likely want to
define them as a *stack singleton* so that only a single instance of the
provider is created in your stack and which is used by all custom resources of
that type.

Here is a basic pattern for defining stack singletons in the CDK. The following
examples ensures that only a single SNS topic is defined:

```python
def get_or_create(self, scope):
    stack = Stack.of(scope)
    uniqueid = "GloballyUniqueIdForSingleton" # For example, a UUID from `uuidgen`
    existing = stack.node.try_find_child(uniqueid)
    if existing:
        return existing
    return sns.Topic(stack, uniqueid)
```

#### Amazon SNS Topic

Every time a resource event occurs (CREATE/UPDATE/DELETE), an SNS notification
is sent to the SNS topic. Users must process these notifications (e.g. through a
fleet of worker hosts) and submit success/failure responses to the
CloudFormation service.

> You only need to use this type of provider if your custom resource cannot run on AWS Lambda, for reasons other than the 15
> minute timeout. If you are considering using this type of provider because you want to write a custom resource provider that may need
> to wait for more than 15 minutes for the API calls to stabilize, have a look at the [`custom-resources`](#the-custom-resource-provider-framework) module first.
>
> Refer to the [CloudFormation Custom Resource documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) for information on the contract your custom resource needs to adhere to.

Set `serviceToken` to `topic.topicArn`  in order to use this provider:

```python
topic = sns.Topic(self, "MyProvider")

CustomResource(self, "MyResource",
    service_token=topic.topic_arn
)
```

#### AWS Lambda Function

An AWS lambda function is called *directly* by CloudFormation for all resource
events. The handler must take care of explicitly submitting a success/failure
response to the CloudFormation service and handle various error cases.

> **We do not recommend you use this provider type.** The CDK has wrappers around Lambda Functions that make them easier to work with.
>
> If you do want to use this provider, refer to the [CloudFormation Custom Resource documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) for information on the contract your custom resource needs to adhere to.

Set `serviceToken` to `lambda.functionArn` to use this provider:

```python
fn = lambda_.SingletonFunction(self, "MyProvider", function_props)

CustomResource(self, "MyResource",
    service_token=fn.function_arn
)
```

#### The `core.CustomResourceProvider` class

The class [`@aws-cdk/core.CustomResourceProvider`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.CustomResourceProvider.html) offers a basic low-level
framework designed to implement simple and slim custom resource providers. It
currently only supports Node.js-based user handlers, represents permissions as raw
JSON blobs instead of `iam.PolicyStatement` objects, and it does not have
support for asynchronous waiting (handler cannot exceed the 15min lambda
timeout). The `CustomResourceProviderRuntime` supports runtime `nodejs12.x`,
`nodejs14.x`, `nodejs16.x`, `nodejs18.x`.

> **As an application builder, we do not recommend you use this provider type.** This provider exists purely for custom resources that are part of the AWS Construct Library.
>
> The [`custom-resources`](#the-custom-resource-provider-framework) provider is more convenient to work with and more fully-featured.

The provider has a built-in singleton method which uses the resource type as a
stack-unique identifier and returns the service token:

```python
service_token = CustomResourceProvider.get_or_create(self, "Custom::MyCustomResourceType",
    code_directory=f"{__dirname}/my-handler",
    runtime=CustomResourceProviderRuntime.NODEJS_18_X,
    description="Lambda function created by the custom resource provider"
)

CustomResource(self, "MyResource",
    resource_type="Custom::MyCustomResourceType",
    service_token=service_token
)
```

The directory (`my-handler` in the above example) must include an `index.js` file. It cannot import
external dependencies or files outside this directory. It must export an async
function named `handler`. This function accepts the CloudFormation resource
event object and returns an object with the following structure:

```js
exports.handler = async function(event) {
  const id = event.PhysicalResourceId; // only for "Update" and "Delete"
  const props = event.ResourceProperties;
  const oldProps = event.OldResourceProperties; // only for "Update"s

  switch (event.RequestType) {
    case "Create":
      // ...

    case "Update":
      // ...

      // if an error is thrown, a FAILED response will be submitted to CFN
      throw new Error('Failed!');

    case "Delete":
      // ...
  }

  return {
    // (optional) the value resolved from `resource.ref`
    // defaults to "event.PhysicalResourceId" or "event.RequestId"
    PhysicalResourceId: "REF",

    // (optional) calling `resource.getAtt("Att1")` on the custom resource in the CDK app
    // will return the value "BAR".
    Data: {
      Att1: "BAR",
      Att2: "BAZ"
    },

    // (optional) user-visible message
    Reason: "User-visible message",

    // (optional) hides values from the console
    NoEcho: true
  };
}
```

Here is an complete example of a custom resource that summarizes two numbers:

`sum-handler/index.js`:

```js
exports.handler = async (e) => {
  return {
    Data: {
      Result: e.ResourceProperties.lhs + e.ResourceProperties.rhs,
    },
  };
};
```

`sum.ts`:

```python
from constructs import Construct
from aws_cdk import CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, Token

class Sum(Construct):

    def __init__(self, scope, id, *, lhs, rhs):
        super().__init__(scope, id)

        resource_type = "Custom::Sum"
        service_token = CustomResourceProvider.get_or_create(self, resource_type,
            code_directory=f"{__dirname}/sum-handler",
            runtime=CustomResourceProviderRuntime.NODEJS_18_X
        )

        resource = CustomResource(self, "Resource",
            resource_type=resource_type,
            service_token=service_token,
            properties={
                "lhs": lhs,
                "rhs": rhs
            }
        )

        self.result = Token.as_number(resource.get_att("Result"))
```

Usage will look like this:

```python
sum = Sum(self, "MySum", lhs=40, rhs=2)
CfnOutput(self, "Result", value=Token.as_string(sum.result))
```

To access the ARN of the provider's AWS Lambda function role, use the `getOrCreateProvider()`
built-in singleton method:

```python
provider = CustomResourceProvider.get_or_create_provider(self, "Custom::MyCustomResourceType",
    code_directory=f"{__dirname}/my-handler",
    runtime=CustomResourceProviderRuntime.NODEJS_18_X
)

role_arn = provider.role_arn
```

This role ARN can then be used in resource-based IAM policies.

To add IAM policy statements to this role, use `addToRolePolicy()`:

```python
provider = CustomResourceProvider.get_or_create_provider(self, "Custom::MyCustomResourceType",
    code_directory=f"{__dirname}/my-handler",
    runtime=CustomResourceProviderRuntime.NODEJS_18_X
)
provider.add_to_role_policy({
    "Effect": "Allow",
    "Action": "s3:GetObject",
    "Resource": "*"
})
```

Note that `addToRolePolicy()` uses direct IAM JSON policy blobs, *not* a
`iam.PolicyStatement` object like you will see in the rest of the CDK.

#### The Custom Resource Provider Framework

The [`@aws-cdk/custom-resources`](https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html) module includes an advanced framework for
implementing custom resource providers.

Handlers are implemented as AWS Lambda functions, which means that they can be
implemented in any Lambda-supported runtime. Furthermore, this provider has an
asynchronous mode, which means that users can provide an `isComplete` lambda
function which is called periodically until the operation is complete. This
allows implementing providers that can take up to two hours to stabilize.

Set `serviceToken` to `provider.serviceToken` to use this type of provider:

```python
provider = customresources.Provider(self, "MyProvider",
    on_event_handler=on_event_handler,
    is_complete_handler=is_complete_handler
)

CustomResource(self, "MyResource",
    service_token=provider.service_token
)
```

See the [documentation](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-cdk-lib.custom_resources-readme.html) for more details.

## AWS CloudFormation features

A CDK stack synthesizes to an AWS CloudFormation Template. This section
explains how this module allows users to access low-level CloudFormation
features when needed.

### Stack Outputs

CloudFormation [stack outputs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html) and exports are created using
the `CfnOutput` class:

```python
CfnOutput(self, "OutputName",
    value=my_bucket.bucket_name,
    description="The name of an S3 bucket",  # Optional
    export_name="TheAwesomeBucket"
)
```

### Parameters

CloudFormation templates support the use of [Parameters](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html) to
customize a template. They enable CloudFormation users to input custom values to
a template each time a stack is created or updated. While the CDK design
philosophy favors using build-time parameterization, users may need to use
CloudFormation in a number of cases (for example, when migrating an existing
stack to the AWS CDK).

Template parameters can be added to a stack by using the `CfnParameter` class:

```python
CfnParameter(self, "MyParameter",
    type="Number",
    default=1337
)
```

The value of parameters can then be obtained using one of the `value` methods.
As parameters are only resolved at deployment time, the values obtained are
placeholder tokens for the real value (`Token.isUnresolved()` would return `true`
for those):

```python
param = CfnParameter(self, "ParameterName")

# If the parameter is a String
param.value_as_string

# If the parameter is a Number
param.value_as_number

# If the parameter is a List
param.value_as_list
```

### Pseudo Parameters

CloudFormation supports a number of [pseudo parameters](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html),
which resolve to useful values at deployment time. CloudFormation pseudo
parameters can be obtained from static members of the `Aws` class.

It is generally recommended to access pseudo parameters from the scope's `stack`
instead, which guarantees the values produced are qualifying the designated
stack, which is essential in cases where resources are shared cross-stack:

```python
# "this" is the current construct
stack = Stack.of(self)

stack.account # Returns the AWS::AccountId for this stack (or the literal value if known)
stack.region # Returns the AWS::Region for this stack (or the literal value if known)
stack.partition
```

### Resource Options

CloudFormation resources can also specify [resource
attributes](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-product-attribute-reference.html). The `CfnResource` class allows
accessing those through the `cfnOptions` property:

```python
raw_bucket = s3.CfnBucket(self, "Bucket")
# -or-
raw_bucket_alt = my_bucket.node.default_child

# then
raw_bucket.cfn_options.condition = CfnCondition(self, "EnableBucket")
raw_bucket.cfn_options.metadata = {
    "metadata_key": "MetadataValue"
}
```

Resource dependencies (the `DependsOn` attribute) is modified using the
`cfnResource.addDependency` method:

```python
resource_a = CfnResource(self, "ResourceA", resource_props)
resource_b = CfnResource(self, "ResourceB", resource_props)

resource_b.add_dependency(resource_a)
```

#### CreationPolicy

Some resources support a [CreationPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html) to be specified as a CfnOption.

The creation policy is invoked only when AWS CloudFormation creates the associated resource. Currently, the only AWS CloudFormation resources that support creation policies are `CfnAutoScalingGroup`, `CfnInstance`, `CfnWaitCondition` and `CfnFleet`.

The `CfnFleet` resource from the `aws-appstream` module supports specifying `startFleet` as
a property of the creationPolicy on the resource options. Setting it to true will make AWS CloudFormation wait until the fleet is started before continuing with the creation of
resources that depend on the fleet resource.

```python
fleet = appstream.CfnFleet(self, "Fleet",
    instance_type="stream.standard.small",
    name="Fleet",
    compute_capacity=appstream.CfnFleet.ComputeCapacityProperty(
        desired_instances=1
    ),
    image_name="AppStream-AmazonLinux2-09-21-2022"
)
fleet.cfn_options.creation_policy = CfnCreationPolicy(
    start_fleet=True
)
```

The properties passed to the level 2 constructs `AutoScalingGroup` and `Instance` from the
`aws-ec2` module abstract what is passed into the `CfnOption` properties `resourceSignal` and
`autoScalingCreationPolicy`, but when using level 1 constructs you can specify these yourself.

The CfnWaitCondition resource from the `aws-cloudformation` module suppports the `resourceSignal`.
The format of the timeout is `PT#H#M#S`. In the example below AWS Cloudformation will wait for
3 success signals to occur within 15 minutes before the status of the resource will be set to
`CREATE_COMPLETE`.

```python
# resource: CfnResource


resource.cfn_options.creation_policy = CfnCreationPolicy(
    resource_signal=CfnResourceSignal(
        count=3,
        timeout="PR15M"
    )
)
```

### Intrinsic Functions and Condition Expressions

CloudFormation supports [intrinsic functions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html). These functions
can be accessed from the `Fn` class, which provides type-safe methods for each
intrinsic function as well as condition expressions:

```python
# my_object_or_array: Any
# my_array: Any


# To use Fn::Base64
Fn.base64("SGVsbG8gQ0RLIQo=")

# To compose condition expressions:
environment_parameter = CfnParameter(self, "Environment")
Fn.condition_and(
    # The "Environment" CloudFormation template parameter evaluates to "Production"
    Fn.condition_equals("Production", environment_parameter),
    # The AWS::Region pseudo-parameter value is NOT equal to "us-east-1"
    Fn.condition_not(Fn.condition_equals("us-east-1", Aws.REGION)))

# To use Fn::ToJsonString
Fn.to_json_string(my_object_or_array)

# To use Fn::Length
Fn.len(Fn.split(",", my_array))
```

When working with deploy-time values (those for which `Token.isUnresolved`
returns `true`), idiomatic conditionals from the programming language cannot be
used (the value will not be known until deployment time). When conditional logic
needs to be expressed with un-resolved values, it is necessary to use
CloudFormation conditions by means of the `CfnCondition` class:

```python
environment_parameter = CfnParameter(self, "Environment")
is_prod = CfnCondition(self, "IsProduction",
    expression=Fn.condition_equals("Production", environment_parameter)
)

# Configuration value that is a different string based on IsProduction
stage = Fn.condition_if(is_prod.logical_id, "Beta", "Prod").to_string()

# Make Bucket creation condition to IsProduction by accessing
# and overriding the CloudFormation resource
bucket = s3.Bucket(self, "Bucket")
cfn_bucket = my_bucket.node.default_child
cfn_bucket.cfn_options.condition = is_prod
```

### Mappings

CloudFormation [mappings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html) are created and queried using the
`CfnMappings` class:

```python
region_table = CfnMapping(self, "RegionTable",
    mapping={
        "us-east-1": {
            "region_name": "US East (N. Virginia)"
        },
        "us-east-2": {
            "region_name": "US East (Ohio)"
        }
    }
)

region_table.find_in_map(Aws.REGION, "regionName")
```

This will yield the following template:

```yaml
Mappings:
  RegionTable:
    us-east-1:
      regionName: US East (N. Virginia)
    us-east-2:
      regionName: US East (Ohio)
```

Mappings can also be synthesized "lazily"; lazy mappings will only render a "Mappings"
section in the synthesized CloudFormation template if some `findInMap` call is unable to
immediately return a concrete value due to one or both of the keys being unresolved tokens
(some value only available at deploy-time).

For example, the following code will not produce anything in the "Mappings" section. The
call to `findInMap` will be able to resolve the value during synthesis and simply return
`'US East (Ohio)'`.

```python
region_table = CfnMapping(self, "RegionTable",
    mapping={
        "us-east-1": {
            "region_name": "US East (N. Virginia)"
        },
        "us-east-2": {
            "region_name": "US East (Ohio)"
        }
    },
    lazy=True
)

region_table.find_in_map("us-east-2", "regionName")
```

On the other hand, the following code will produce the "Mappings" section shown above,
since the top-level key is an unresolved token. The call to `findInMap` will return a token that resolves to
`{ "Fn::FindInMap": [ "RegionTable", { "Ref": "AWS::Region" }, "regionName" ] }`.

```python
# region_table: CfnMapping


region_table.find_in_map(Aws.REGION, "regionName")
```

An optional default value can also be passed to `findInMap`. If either key is not found in the map and the mapping is lazy, `findInMap` will return the default value and not render the mapping.
If the mapping is not lazy or either key is an unresolved token, the call to `findInMap` will return a token that resolves to
`{ "Fn::FindInMap": [ "MapName", "TopLevelKey", "SecondLevelKey", { "DefaultValue": "DefaultValue" } ] }`, and the mapping will be rendered.
Note that the `AWS::LanguageExtentions` transform is added to enable the default value functionality.

For example, the following code will again not produce anything in the "Mappings" section. The
call to `findInMap` will be able to resolve the value during synthesis and simply return
`'Region not found'`.

```python
region_table = CfnMapping(self, "RegionTable",
    mapping={
        "us-east-1": {
            "region_name": "US East (N. Virginia)"
        },
        "us-east-2": {
            "region_name": "US East (Ohio)"
        }
    },
    lazy=True
)

region_table.find_in_map("us-west-1", "regionName", "Region not found")
```

### Dynamic References

CloudFormation supports [dynamically resolving](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html) values
for SSM parameters (including secure strings) and Secrets Manager. Encoding such
references is done using the `CfnDynamicReference` class:

```python
CfnDynamicReference(CfnDynamicReferenceService.SECRETS_MANAGER, "secret-id:secret-string:json-key:version-stage:version-id")
```

### Template Options & Transform

CloudFormation templates support a number of options, including which Macros or
[Transforms](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html) to use when deploying the stack. Those can be
configured using the `stack.templateOptions` property:

```python
stack = Stack(app, "StackName")

stack.template_options.description = "This will appear in the AWS console"
stack.template_options.transforms = ["AWS::Serverless-2016-10-31"]
stack.template_options.metadata = {
    "metadata_key": "MetadataValue"
}
```

### Emitting Raw Resources

The `CfnResource` class allows emitting arbitrary entries in the
[Resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html) section of the CloudFormation template.

```python
CfnResource(self, "ResourceId",
    type="AWS::S3::Bucket",
    properties={
        "BucketName": "amzn-s3-demo-bucket"
    }
)
```

As for any other resource, the logical ID in the CloudFormation template will be
generated by the AWS CDK, but the type and properties will be copied verbatim in
the synthesized template.

### Including raw CloudFormation template fragments

When migrating a CloudFormation stack to the AWS CDK, it can be useful to
include fragments of an existing template verbatim in the synthesized template.
This can be achieved using the `CfnInclude` class.

```python
CfnInclude(self, "ID",
    template={
        "Resources": {
            "Bucket": {
                "Type": "AWS::S3::Bucket",
                "Properties": {
                    "BucketName": "amzn-s3-demo-bucket"
                }
            }
        }
    }
)
```

### Termination Protection

You can prevent a stack from being accidentally deleted by enabling termination
protection on the stack. If a user attempts to delete a stack with termination
protection enabled, the deletion fails and the stack--including its status--remains
unchanged. Enabling or disabling termination protection on a stack sets it for any
nested stacks belonging to that stack as well. You can enable termination protection
on a stack by setting the `terminationProtection` prop to `true`.

```python
stack = Stack(app, "StackName",
    termination_protection=True
)
```

You can also set termination protection with the setter after you've instantiated the stack.

```python
stack = Stack(app, "StackName")
stack.termination_protection = True
```

By default, termination protection is disabled.

### Description

You can add a description of the stack in the same way as `StackProps`.

```python
stack = Stack(app, "StackName",
    description="This is a description."
)
```

### CfnJson

`CfnJson` allows you to postpone the resolution of a JSON blob from
deployment-time. This is useful in cases where the CloudFormation JSON template
cannot express a certain value.

A common example is to use `CfnJson` in order to render a JSON map which needs
to use intrinsic functions in keys. Since JSON map keys must be strings, it is
impossible to use intrinsics in keys and `CfnJson` can help.

The following example defines an IAM role which can only be assumed by
principals that are tagged with a specific tag.

```python
tag_param = CfnParameter(self, "TagName")

string_equals = CfnJson(self, "ConditionJson",
    value={
        "f"aws:PrincipalTag/{tagParam.valueAsString}"": True
    }
)

principal = iam.AccountRootPrincipal().with_conditions({
    "StringEquals": string_equals
})

iam.Role(self, "MyRole", assumed_by=principal)
```

**Explanation**: since in this example we pass the tag name through a parameter, it
can only be resolved during deployment. The resolved value can be represented in
the template through a `{ "Ref": "TagName" }`. However, since we want to use
this value inside a [`aws:PrincipalTag/TAG-NAME`](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-principaltag)
IAM operator, we need it in the *key* of a `StringEquals` condition. JSON keys
*must be* strings, so to circumvent this limitation, we use `CfnJson`
to "delay" the rendition of this template section to deploy-time. This means
that the value of `StringEquals` in the template will be `{ "Fn::GetAtt": [ "ConditionJson", "Value" ] }`, and will only "expand" to the operator we synthesized during deployment.

### Stack Resource Limit

When deploying to AWS CloudFormation, it needs to keep in check the amount of resources being added inside a Stack. Currently it's possible to check the limits in the [AWS CloudFormation quotas](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html) page.

It's possible to synthesize the project with more Resources than the allowed (or even reduce the number of Resources).

Set the context key `@aws-cdk/core:stackResourceLimit` with the proper value, being 0 for disable the limit of resources.

### Template Indentation

The AWS CloudFormation templates generated by CDK include indentation by default.
Indentation makes the templates more readable, but also increases their size,
and CloudFormation templates cannot exceed 1MB.

It's possible to reduce the size of your templates by suppressing indentation.

To do this for all templates, set the context key `@aws-cdk/core:suppressTemplateIndentation` to `true`.

To do this for a specific stack, add a `suppressTemplateIndentation: true` property to the
stack's `StackProps` parameter. You can also set this property to `false` to override
the context key setting.

## App Context

[Context values](https://docs.aws.amazon.com/cdk/v2/guide/context.html) are key-value pairs that can be associated with an app, stack, or construct.
One common use case for context is to use it for enabling/disabling [feature flags](https://docs.aws.amazon.com/cdk/v2/guide/featureflags.html). There are several places
where context can be specified. They are listed below in the order they are evaluated (items at the
top take precedence over those below).

* The `node.setContext()` method
* The `postCliContext` prop when you create an `App`
* The CLI via the `--context` CLI argument
* The `cdk.json` file via the `context` key:
* The `cdk.context.json` file:
* The `~/.cdk.json` file via the `context` key:
* The `context` prop when you create an `App`

### Examples of setting context

```python
App(
    context={
        "@aws-cdk/core:newStyleStackSynthesis": True
    }
)
```

```python
app = App()
app.node.set_context("@aws-cdk/core:newStyleStackSynthesis", True)
```

```python
App(
    post_cli_context={
        "@aws-cdk/core:newStyleStackSynthesis": True
    }
)
```

```console
cdk synth --context @aws-cdk/core:newStyleStackSynthesis=true
```

*cdk.json*

```json
{
  "context": {
    "@aws-cdk/core:newStyleStackSynthesis": true
  }
}
```

*cdk.context.json*

```json
{
  "@aws-cdk/core:newStyleStackSynthesis": true
}
```

*~/.cdk.json*

```json
{
  "context": {
    "@aws-cdk/core:newStyleStackSynthesis": true
  }
}
```

## IAM Permissions Boundary

It is possible to apply an [IAM permissions boundary](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html)
to all roles within a specific construct scope. The most common use case would
be to apply a permissions boundary at the `Stage` level.

```python
prod_stage = Stage(app, "ProdStage",
    permissions_boundary=PermissionsBoundary.from_name("cdk-${Qualifier}-PermissionsBoundary")
)
```

Any IAM Roles or Users created within this Stage will have the default
permissions boundary attached.

For more details see the [Permissions Boundary](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_iam-readme.html#permissions-boundaries) section in the IAM guide.

## Policy Validation

If you or your organization use (or would like to use) any policy validation tool, such as
[CloudFormation
Guard](https://docs.aws.amazon.com/cfn-guard/latest/ug/what-is-guard.html) or
[OPA](https://www.openpolicyagent.org/), to define constraints on your
CloudFormation template, you can incorporate them into the CDK application.
By using the appropriate plugin, you can make the CDK application check the
generated CloudFormation templates against your policies immediately after
synthesis. If there are any violations, the synthesis will fail and a report
will be printed to the console or to a file (see below).

> **Note**
> This feature is considered experimental, and both the plugin API and the
> format of the validation report are subject to change in the future.

### For application developers

To use one or more validation plugins in your application, use the
`policyValidationBeta1` property of `Stage`:

```python
# globally for the entire app (an app is a stage)
app = App(
    policy_validation_beta1=[
        # These hypothetical classes implement IPolicyValidationPluginBeta1:
        ThirdPartyPluginX(),
        ThirdPartyPluginY()
    ]
)

# only apply to a particular stage
prod_stage = Stage(app, "ProdStage",
    policy_validation_beta1=[
        ThirdPartyPluginX()
    ]
)
```

Immediately after synthesis, all plugins registered this way will be invoked to
validate all the templates generated in the scope you defined. In particular, if
you register the templates in the `App` object, all templates will be subject to
validation.

> **Warning**
> Other than modifying the cloud assembly, plugins can do anything that your CDK
> application can. They can read data from the filesystem, access the network
> etc. It's your responsibility as the consumer of a plugin to verify that it is
> secure to use.

By default, the report will be printed in a human readable format. If you want a
report in JSON format, enable it using the `@aws-cdk/core:validationReportJson`
context passing it directly to the application:

```python
app = App(
    context={"@aws-cdk/core:validationReportJson": True}
)
```

Alternatively, you can set this context key-value pair using the `cdk.json` or
`cdk.context.json` files in your project directory (see
[Runtime context](https://docs.aws.amazon.com/cdk/v2/guide/context.html)).

If you choose the JSON format, the CDK will print the policy validation report
to a file called `policy-validation-report.json` in the cloud assembly
directory. For the default, human-readable format, the report will be printed to
the standard output.

### For plugin authors

The communication protocol between the CDK core module and your policy tool is
defined by the `IPolicyValidationPluginBeta1` interface. To create a new plugin you must
write a class that implements this interface. There are two things you need to
implement: the plugin name (by overriding the `name` property), and the
`validate()` method.

The framework will call `validate()`, passing an `IPolicyValidationContextBeta1` object.
The location of the templates to be validated is given by `templatePaths`. The
plugin should return an instance of `PolicyValidationPluginReportBeta1`. This object
represents the report that the user wil receive at the end of the synthesis.

```python
@jsii.implements(IPolicyValidationPluginBeta1)
class MyPlugin:

    def validate(self, context):
        # First read the templates using context.templatePaths...

        # ...then perform the validation, and then compose and return the report.
        # Using hard-coded values here for better clarity:
        return PolicyValidationPluginReportBeta1(
            success=False,
            violations=[PolicyViolationBeta1(
                rule_name="CKV_AWS_117",
                description="Ensure that AWS Lambda function is configured inside a VPC",
                fix="https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1",
                violating_resources=[PolicyViolatingResourceBeta1(
                    resource_logical_id="MyFunction3BAA72D1",
                    template_path="/home/johndoe/myapp/cdk.out/MyService.template.json",
                    locations=["Properties/VpcConfig"]
                )]
            )]
        )
```

In addition to the name, plugins may optionally report their version (`version`
property ) and a list of IDs of the rules they are going to evaluate (`ruleIds`
property).

Note that plugins are not allowed to modify anything in the cloud assembly. Any
attempt to do so will result in synthesis failure.

If your plugin depends on an external tool, keep in mind that some developers may
not have that tool installed in their workstations yet. To minimize friction, we
highly recommend that you provide some installation script along with your
plugin package, to automate the whole process. Better yet, run that script as
part of the installation of your package. With `npm`, for example, you can run
add it to the `postinstall`
[script](https://docs.npmjs.com/cli/v9/using-npm/scripts) in the `package.json`
file.

## Annotations

Construct authors can add annotations to constructs to report at three different
levels: `ERROR`, `WARN`, `INFO`.

Typically warnings are added for things that are important for the user to be
aware of, but will not cause deployment errors in all cases. Some common
scenarios are (non-exhaustive list):

* Warn when the user needs to take a manual action, e.g. IAM policy should be
  added to an referenced resource.
* Warn if the user configuration might not follow best practices (but is still
  valid)
* Warn if the user is using a deprecated API

### Acknowledging Warnings

If you would like to run with `--strict` mode enabled (warnings will throw
errors) it is possible to `acknowledge` warnings to make the warning go away.

For example, if > 10 IAM managed policies are added to an IAM Group, a warning
will be created:

```text
IAM:Group:MaxPoliciesExceeded: You added 11 to IAM Group my-group. The maximum number of managed policies attached to an IAM group is 10.
```

If you have requested a [quota increase](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-quotas-entities)
you may have the ability to add > 10 managed policies which means that this
warning does not apply to you. You can acknowledge this by `acknowledging` the
warning by the `id`.

```python
Annotations.of(self).acknowledge_warning("IAM:Group:MaxPoliciesExceeded", "Account has quota increased to 20")
```

<!--END CORE DOCUMENTATION-->

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/aws/aws-cdk",
    "name": "aws-cdk-lib",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "~=3.8",
    "maintainer_email": null,
    "keywords": null,
    "author": "Amazon Web Services",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/f8/ec/365df25e38be6cc57f138edd02ade91390e860ac159a32205e6867105fa1/aws_cdk_lib-2.170.0.tar.gz",
    "platform": null,
    "description": "# AWS Cloud Development Kit Library\n\nThe AWS CDK construct library provides APIs to define your CDK application and add\nCDK constructs to the application.\n\n## Usage\n\n### Upgrade from CDK 1.x\n\nWhen upgrading from CDK 1.x, remove all dependencies to individual CDK packages\nfrom your dependencies file and follow the rest of the sections.\n\n### Installation\n\nTo use this package, you need to declare this package and the `constructs` package as\ndependencies.\n\nAccording to the kind of project you are developing:\n\nFor projects that are CDK libraries in NPM, declare them both under the `devDependencies` **and** `peerDependencies` sections.\nTo make sure your library is compatible with the widest range of CDK versions: pick the minimum `aws-cdk-lib` version\nthat your library requires; declare a range dependency with a caret on that version in peerDependencies, and declare a\npoint version dependency on that version in devDependencies.\n\nFor example, let's say the minimum version your library needs is `2.38.0`. Your `package.json` should look like this:\n\n```javascript\n{\n  \"peerDependencies\": {\n    \"aws-cdk-lib\": \"^2.38.0\",\n    \"constructs\": \"^10.0.0\"\n  },\n  \"devDependencies\": {\n    /* Install the oldest version for testing so we don't accidentally use features from a newer version than we declare */\n    \"aws-cdk-lib\": \"2.38.0\"\n  }\n}\n```\n\nFor CDK apps, declare them under the `dependencies` section. Use a caret so you always get the latest version:\n\n```json\n{\n  \"dependencies\": {\n    \"aws-cdk-lib\": \"^2.38.0\",\n    \"constructs\": \"^10.0.0\"\n  }\n}\n```\n\n### Use in your code\n\n#### Classic import\n\nYou can use a classic import to get access to each service namespaces:\n\n```python\nfrom aws_cdk import Stack, App, aws_s3 as s3\n\napp = App()\nstack = Stack(app, \"TestStack\")\n\ns3.Bucket(stack, \"TestBucket\")\n```\n\n#### Barrel import\n\nAlternatively, you can use \"barrel\" imports:\n\n```python\nfrom aws_cdk import App, Stack\nfrom aws_cdk.aws_s3 import Bucket\n\napp = App()\nstack = Stack(app, \"TestStack\")\n\nBucket(stack, \"TestBucket\")\n```\n\n<!--BEGIN CORE DOCUMENTATION-->\n\n## Stacks and Stages\n\nA `Stack` is the smallest physical unit of deployment, and maps directly onto\na CloudFormation Stack. You define a Stack by defining a subclass of `Stack`\n-- let's call it `MyStack` -- and instantiating the constructs that make up\nyour application in `MyStack`'s constructor. You then instantiate this stack\none or more times to define different instances of your application. For example,\nyou can instantiate it once using few and cheap EC2 instances for testing,\nand once again using more and bigger EC2 instances for production.\n\nWhen your application grows, you may decide that it makes more sense to split it\nout across multiple `Stack` classes. This can happen for a number of reasons:\n\n* You could be starting to reach the maximum number of resources allowed in a single\n  stack (this is currently 500).\n* You could decide you want to separate out stateful resources and stateless resources\n  into separate stacks, so that it becomes easy to tear down and recreate the stacks\n  that don't have stateful resources.\n* There could be a single stack with resources (like a VPC) that are shared\n  between multiple instances of other stacks containing your applications.\n\nAs soon as your conceptual application starts to encompass multiple stacks,\nit is convenient to wrap them in another construct that represents your\nlogical application. You can then treat that new unit the same way you used\nto be able to treat a single stack: by instantiating it multiple times\nfor different instances of your application.\n\nYou can define a custom subclass of `Stage`, holding one or more\n`Stack`s, to represent a single logical instance of your application.\n\nAs a final note: `Stack`s are not a unit of reuse. They describe physical\ndeployment layouts, and as such are best left to application builders to\norganize their deployments with. If you want to vend a reusable construct,\ndefine it as a subclasses of `Construct`: the consumers of your construct\nwill decide where to place it in their own stacks.\n\n## Stack Synthesizers\n\nEach Stack has a *synthesizer*, an object that determines how and where\nthe Stack should be synthesized and deployed. The synthesizer controls\naspects like:\n\n* How does the stack reference assets? (Either through CloudFormation\n  parameters the CLI supplies, or because the Stack knows a predefined\n  location where assets will be uploaded).\n* What roles are used to deploy the stack? These can be bootstrapped\n  roles, roles created in some other way, or just the CLI's current\n  credentials.\n\nThe following synthesizers are available:\n\n* `DefaultStackSynthesizer`: recommended. Uses predefined asset locations and\n  roles created by the modern bootstrap template. Access control is done by\n  controlling who can assume the deploy role. This is the default stack\n  synthesizer in CDKv2.\n* `LegacyStackSynthesizer`: Uses CloudFormation parameters to communicate\n  asset locations, and the CLI's current permissions to deploy stacks. This\n  is the default stack synthesizer in CDKv1.\n* `CliCredentialsStackSynthesizer`: Uses predefined asset locations, and the\n  CLI's current permissions.\n\nEach of these synthesizers takes configuration arguments. To configure\na stack with a synthesizer, pass it as one of its properties:\n\n```python\nMyStack(app, \"MyStack\",\n    synthesizer=DefaultStackSynthesizer(\n        file_assets_bucket_name=\"amzn-s3-demo-bucket\"\n    )\n)\n```\n\nFor more information on bootstrapping accounts and customizing synthesis,\nsee [Bootstrapping in the CDK Developer Guide](https://docs.aws.amazon.com/cdk/latest/guide/bootstrapping.html).\n\n## Nested Stacks\n\n[Nested stacks](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html) are stacks created as part of other stacks. You create a nested stack within another stack by using the `NestedStack` construct.\n\nAs your infrastructure grows, common patterns can emerge in which you declare the same components in multiple templates. You can separate out these common components and create dedicated templates for them. Then use the resource in your template to reference other templates, creating nested stacks.\n\nFor example, assume that you have a load balancer configuration that you use for most of your stacks. Instead of copying and pasting the same configurations into your templates, you can create a dedicated template for the load balancer. Then, you just use the resource to reference that template from within other templates.\n\nThe following example will define a single top-level stack that contains two nested stacks: each one with a single Amazon S3 bucket:\n\n```python\nclass MyNestedStack(cfn.NestedStack):\n    def __init__(self, scope, id, *, parameters=None, timeout=None, notifications=None):\n        super().__init__(scope, id, parameters=parameters, timeout=timeout, notifications=notifications)\n\n        s3.Bucket(self, \"NestedBucket\")\n\nclass MyParentStack(Stack):\n    def __init__(self, scope, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None):\n        super().__init__(scope, id, description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation)\n\n        MyNestedStack(self, \"Nested1\")\n        MyNestedStack(self, \"Nested2\")\n```\n\nResources references across nested/parent boundaries (even with multiple levels of nesting) will be wired by the AWS CDK\nthrough CloudFormation parameters and outputs. When a resource from a parent stack is referenced by a nested stack,\na CloudFormation parameter will automatically be added to the nested stack and assigned from the parent; when a resource\nfrom a nested stack is referenced by a parent stack, a CloudFormation output will be automatically be added to the\nnested stack and referenced using `Fn::GetAtt \"Outputs.Xxx\"` from the parent.\n\nNested stacks also support the use of Docker image and file assets.\n\n## Accessing resources in a different stack\n\nYou can access resources in a different stack, as long as they are in the\nsame account and AWS Region (see [next section](#accessing-resources-in-a-different-stack-and-region) for an exception).\nThe following example defines the stack `stack1`,\nwhich defines an Amazon S3 bucket. Then it defines a second stack, `stack2`,\nwhich takes the bucket from stack1 as a constructor property.\n\n```python\nprod = {\"account\": \"123456789012\", \"region\": \"us-east-1\"}\n\nstack1 = StackThatProvidesABucket(app, \"Stack1\", env=prod)\n\n# stack2 will take a property { bucket: IBucket }\nstack2 = StackThatExpectsABucket(app, \"Stack2\",\n    bucket=stack1.bucket,\n    env=prod\n)\n```\n\nIf the AWS CDK determines that the resource is in the same account and\nRegion, but in a different stack, it automatically synthesizes AWS\nCloudFormation\n[Exports](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-exports.html)\nin the producing stack and an\n[Fn::ImportValue](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-importvalue.html)\nin the consuming stack to transfer that information from one stack to the\nother.\n\n## Accessing resources in a different stack and region\n\n> **This feature is currently experimental**\n\nYou can enable the Stack property `crossRegionReferences`\nin order to access resources in a different stack *and* region. With this feature flag\nenabled it is possible to do something like creating a CloudFront distribution in `us-east-2` and\nan ACM certificate in `us-east-1`.\n\n```python\nstack1 = Stack(app, \"Stack1\",\n    env=Environment(\n        region=\"us-east-1\"\n    ),\n    cross_region_references=True\n)\ncert = acm.Certificate(stack1, \"Cert\",\n    domain_name=\"*.example.com\",\n    validation=acm.CertificateValidation.from_dns(route53.PublicHostedZone.from_hosted_zone_id(stack1, \"Zone\", \"Z0329774B51CGXTDQV3X\"))\n)\n\nstack2 = Stack(app, \"Stack2\",\n    env=Environment(\n        region=\"us-east-2\"\n    ),\n    cross_region_references=True\n)\ncloudfront.Distribution(stack2, \"Distribution\",\n    default_behavior=cloudfront.BehaviorOptions(\n        origin=origins.HttpOrigin(\"example.com\")\n    ),\n    domain_names=[\"dev.example.com\"],\n    certificate=cert\n)\n```\n\nWhen the AWS CDK determines that the resource is in a different stack *and* is in a different\nregion, it will \"export\" the value by creating a custom resource in the producing stack which\ncreates SSM Parameters in the consuming region for each exported value. The parameters will be\ncreated with the name '/cdk/exports/${consumingStackName}/${export-name}'.\nIn order to \"import\" the exports into the consuming stack a [SSM Dynamic reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#dynamic-references-ssm)\nis used to reference the SSM parameter which was created.\n\nIn order to mimic strong references, a Custom Resource is also created in the consuming\nstack which marks the SSM parameters as being \"imported\". When a parameter has been successfully\nimported, the producing stack cannot update the value.\n\n> [!NOTE]\n> As a consequence of this feature being built on a Custom Resource, we are restricted to a\n> CloudFormation response body size limitation of [4096 bytes](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html).\n> To prevent deployment errors related to the Custom Resource Provider response body being too\n> large, we recommend limiting the use of nested stacks and minimizing the length of stack names.\n> Doing this will prevent SSM parameter names from becoming too long which will reduce the size of the\n> response body.\n\nSee the [adr](https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/core/adr/cross-region-stack-references.md)\nfor more details on this feature.\n\n### Removing automatic cross-stack references\n\nThe automatic references created by CDK when you use resources across stacks\nare convenient, but may block your deployments if you want to remove the\nresources that are referenced in this way. You will see an error like:\n\n```text\nExport Stack1:ExportsOutputFnGetAtt-****** cannot be deleted as it is in use by Stack1\n```\n\nLet's say there is a Bucket in the `stack1`, and the `stack2` references its\n`bucket.bucketName`. You now want to remove the bucket and run into the error above.\n\nIt's not safe to remove `stack1.bucket` while `stack2` is still using it, so\nunblocking yourself from this is a two-step process. This is how it works:\n\nDEPLOYMENT 1: break the relationship\n\n* Make sure `stack2` no longer references `bucket.bucketName` (maybe the consumer\n  stack now uses its own bucket, or it writes to an AWS DynamoDB table, or maybe you just\n  remove the Lambda Function altogether).\n* In the `stack1` class, call `this.exportValue(this.bucket.bucketName)`. This\n  will make sure the CloudFormation Export continues to exist while the relationship\n  between the two stacks is being broken.\n* Deploy (this will effectively only change the `stack2`, but it's safe to deploy both).\n\nDEPLOYMENT 2: remove the resource\n\n* You are now free to remove the `bucket` resource from `stack1`.\n* Don't forget to remove the `exportValue()` call as well.\n* Deploy again (this time only the `stack1` will be changed -- the bucket will be deleted).\n\n## Durations\n\nTo make specifications of time intervals unambiguous, a single class called\n`Duration` is used throughout the AWS Construct Library by all constructs\nthat that take a time interval as a parameter (be it for a timeout, a\nrate, or something else).\n\nAn instance of Duration is constructed by using one of the static factory\nmethods on it:\n\n```python\nDuration.seconds(300) # 5 minutes\nDuration.minutes(5) # 5 minutes\nDuration.hours(1) # 1 hour\nDuration.days(7) # 7 days\nDuration.parse(\"PT5M\")\n```\n\nDurations can be added or subtracted together:\n\n```python\nDuration.minutes(1).plus(Duration.seconds(60)) # 2 minutes\nDuration.minutes(5).minus(Duration.seconds(10))\n```\n\n## Size (Digital Information Quantity)\n\nTo make specification of digital storage quantities unambiguous, a class called\n`Size` is available.\n\nAn instance of `Size` is initialized through one of its static factory methods:\n\n```python\nSize.kibibytes(200) # 200 KiB\nSize.mebibytes(5) # 5 MiB\nSize.gibibytes(40) # 40 GiB\nSize.tebibytes(200) # 200 TiB\nSize.pebibytes(3)\n```\n\nInstances of `Size` created with one of the units can be converted into others.\nBy default, conversion to a higher unit will fail if the conversion does not produce\na whole number. This can be overridden by unsetting `integral` property.\n\n```python\nSize.mebibytes(2).to_kibibytes() # yields 2048\nSize.kibibytes(2050).to_mebibytes(rounding=SizeRoundingBehavior.FLOOR)\n```\n\n## Secrets\n\nTo help avoid accidental storage of secrets as plain text, we use the `SecretValue` type to\nrepresent secrets. Any construct that takes a value that should be a secret (such as\na password or an access key) will take a parameter of type `SecretValue`.\n\nThe best practice is to store secrets in AWS Secrets Manager and reference them using `SecretValue.secretsManager`:\n\n```python\nsecret = SecretValue.secrets_manager(\"secretId\",\n    json_field=\"password\",  # optional: key of a JSON field to retrieve (defaults to all content),\n    version_id=\"id\",  # optional: id of the version (default AWSCURRENT)\n    version_stage=\"stage\"\n)\n```\n\nUsing AWS Secrets Manager is the recommended way to reference secrets in a CDK app.\n`SecretValue` also supports the following secret sources:\n\n* `SecretValue.unsafePlainText(secret)`: stores the secret as plain text in your app and the resulting template (not recommended).\n* `SecretValue.secretsManager(secret)`: refers to a secret stored in Secrets Manager\n* `SecretValue.ssmSecure(param, version)`: refers to a secret stored as a SecureString in the SSM\n  Parameter Store. If you don't specify the exact version, AWS CloudFormation uses the latest\n  version of the parameter.\n* `SecretValue.cfnParameter(param)`: refers to a secret passed through a CloudFormation parameter (must have `NoEcho: true`).\n* `SecretValue.cfnDynamicReference(dynref)`: refers to a secret described by a CloudFormation dynamic reference (used by `ssmSecure` and `secretsManager`).\n* `SecretValue.resourceAttribute(attr)`: refers to a secret returned from a CloudFormation resource creation.\n\n`SecretValue`s should only be passed to constructs that accept properties of type\n`SecretValue`. These constructs are written to ensure your secrets will not be\nexposed where they shouldn't be. If you try to use a `SecretValue` in a\ndifferent location, an error about unsafe secret usage will be thrown at\nsynthesis time.\n\nIf you rotate the secret's value in Secrets Manager, you must also change at\nleast one property on the resource where you are using the secret, to force\nCloudFormation to re-read the secret.\n\n`SecretValue.ssmSecure()` is only supported for a limited set of resources.\n[Click here for a list of supported resources and properties](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html#template-parameters-dynamic-patterns-resources).\n\n## ARN manipulation\n\nSometimes you will need to put together or pick apart Amazon Resource Names\n(ARNs). The functions `stack.formatArn()` and `stack.splitArn()` exist for\nthis purpose.\n\n`formatArn()` can be used to build an ARN from components. It will automatically\nuse the region and account of the stack you're calling it on:\n\n```python\n# stack: Stack\n\n\n# Builds \"arn:<PARTITION>:lambda:<REGION>:<ACCOUNT>:function:MyFunction\"\nstack.format_arn(\n    service=\"lambda\",\n    resource=\"function\",\n    arn_format=ArnFormat.COLON_RESOURCE_NAME,\n    resource_name=\"MyFunction\"\n)\n```\n\n`splitArn()` can be used to get a single component from an ARN. `splitArn()`\nwill correctly deal with both literal ARNs and deploy-time values (tokens),\nbut in case of a deploy-time value be aware that the result will be another\ndeploy-time value which cannot be inspected in the CDK application.\n\n```python\n# stack: Stack\n\n\n# Extracts the function name out of an AWS Lambda Function ARN\narn_components = stack.split_arn(arn, ArnFormat.COLON_RESOURCE_NAME)\nfunction_name = arn_components.resource_name\n```\n\nNote that the format of the resource separator depends on the service and\nmay be any of the values supported by `ArnFormat`. When dealing with these\nfunctions, it is important to know the format of the ARN you are dealing with.\n\nFor an exhaustive list of ARN formats used in AWS, see [AWS ARNs and\nNamespaces](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html)\nin the AWS General Reference.\n\n## Dependencies\n\n### Construct Dependencies\n\nSometimes AWS resources depend on other resources, and the creation of one\nresource must be completed before the next one can be started.\n\nIn general, CloudFormation will correctly infer the dependency relationship\nbetween resources based on the property values that are used. In the cases where\nit doesn't, the AWS Construct Library will add the dependency relationship for\nyou.\n\nIf you need to add an ordering dependency that is not automatically inferred,\nyou do so by adding a dependency relationship using\n`constructA.node.addDependency(constructB)`. This will add a dependency\nrelationship between all resources in the scope of `constructA` and all\nresources in the scope of `constructB`.\n\nIf you want a single object to represent a set of constructs that are not\nnecessarily in the same scope, you can use a `DependencyGroup`. The\nfollowing creates a single object that represents a dependency on two\nconstructs, `constructB` and `constructC`:\n\n```python\n# Declare the dependable object\nb_and_c = DependencyGroup()\nb_and_c.add(construct_b)\nb_and_c.add(construct_c)\n\n# Take the dependency\nconstruct_a.node.add_dependency(b_and_c)\n```\n\n### Stack Dependencies\n\nTwo different stack instances can have a dependency on one another. This\nhappens when an resource from one stack is referenced in another stack. In\nthat case, CDK records the cross-stack referencing of resources,\nautomatically produces the right CloudFormation primitives, and adds a\ndependency between the two stacks. You can also manually add a dependency\nbetween two stacks by using the `stackA.addDependency(stackB)` method.\n\nA stack dependency has the following implications:\n\n* Cyclic dependencies are not allowed, so if `stackA` is using resources from\n  `stackB`, the reverse is not possible anymore.\n* Stacks with dependencies between them are treated specially by the CDK\n  toolkit:\n\n  * If `stackA` depends on `stackB`, running `cdk deploy stackA` will also\n    automatically deploy `stackB`.\n  * `stackB`'s deployment will be performed *before* `stackA`'s deployment.\n\n### CfnResource Dependencies\n\nTo make declaring dependencies between `CfnResource` objects easier, you can declare dependencies from one `CfnResource` object on another by using the `cfnResource1.addDependency(cfnResource2)` method. This method will work for resources both within the same stack and across stacks as it detects the relative location of the two resources and adds the dependency either to the resource or between the relevant stacks, as appropriate. If more complex logic is in needed, you can similarly remove, replace, or view dependencies between `CfnResource` objects with the `CfnResource` `removeDependency`, `replaceDependency`, and `obtainDependencies` methods, respectively.\n\n## Custom Resources\n\nCustom Resources are CloudFormation resources that are implemented by arbitrary\nuser code. They can do arbitrary lookups or modifications during a\nCloudFormation deployment.\n\nCustom resources are backed by *custom resource providers*. Commonly, these are\nLambda Functions that are deployed in the same deployment as the one that\ndefines the custom resource itself, but they can also be backed by Lambda\nFunctions deployed previously, or code responding to SNS Topic events running on\nEC2 instances in a completely different account. For more information on custom\nresource providers, see the next section.\n\nOnce you have a provider, each definition of a `CustomResource` construct\nrepresents one invocation. A single provider can be used for the implementation\nof arbitrarily many custom resource definitions. A single definition looks like\nthis:\n\n```python\nCustomResource(self, \"MyMagicalResource\",\n    resource_type=\"Custom::MyCustomResource\",  # must start with 'Custom::'\n\n    # the resource properties\n    properties={\n        \"Property1\": \"foo\",\n        \"Property2\": \"bar\"\n    },\n\n    # the ARN of the provider (SNS/Lambda) which handles\n    # CREATE, UPDATE or DELETE events for this resource type\n    # see next section for details\n    service_token=\"ARN\"\n)\n```\n\n### Custom Resource Providers\n\nCustom resources are backed by a **custom resource provider** which can be\nimplemented in one of the following ways. The following table compares the\nvarious provider types (ordered from low-level to high-level):\n\n| Provider                                                             | Compute Type | Error Handling | Submit to CloudFormation |   Max Timeout   | Language | Footprint |\n| -------------------------------------------------------------------- | :----------: | :------------: | :----------------------: | :-------------: | :------: | :-------: |\n| [sns.Topic](#amazon-sns-topic)                                       | Self-managed |     Manual     |          Manual          |    Unlimited    |   Any    |  Depends  |\n| [lambda.Function](#aws-lambda-function)                              |  AWS Lambda  |     Manual     |          Manual          |      15min      |   Any    |   Small   |\n| [core.CustomResourceProvider](#the-corecustomresourceprovider-class) |  AWS Lambda  |      Auto      |           Auto           |      15min      | Node.js  |   Small   |\n| [custom-resources.Provider](#the-custom-resource-provider-framework) |  AWS Lambda  |      Auto      |           Auto           | Unlimited Async |   Any    |   Large   |\n\nLegend:\n\n* **Compute type**: which type of compute can be used to execute the handler.\n* **Error Handling**: whether errors thrown by handler code are automatically\n  trapped and a FAILED response is submitted to CloudFormation. If this is\n  \"Manual\", developers must take care of trapping errors. Otherwise, events\n  could cause stacks to hang.\n* **Submit to CloudFormation**: whether the framework takes care of submitting\n  SUCCESS/FAILED responses to CloudFormation through the event's response URL.\n* **Max Timeout**: maximum allows/possible timeout.\n* **Language**: which programming languages can be used to implement handlers.\n* **Footprint**: how many resources are used by the provider framework itself.\n\n**A NOTE ABOUT SINGLETONS**\n\nWhen defining resources for a custom resource provider, you will likely want to\ndefine them as a *stack singleton* so that only a single instance of the\nprovider is created in your stack and which is used by all custom resources of\nthat type.\n\nHere is a basic pattern for defining stack singletons in the CDK. The following\nexamples ensures that only a single SNS topic is defined:\n\n```python\ndef get_or_create(self, scope):\n    stack = Stack.of(scope)\n    uniqueid = \"GloballyUniqueIdForSingleton\" # For example, a UUID from `uuidgen`\n    existing = stack.node.try_find_child(uniqueid)\n    if existing:\n        return existing\n    return sns.Topic(stack, uniqueid)\n```\n\n#### Amazon SNS Topic\n\nEvery time a resource event occurs (CREATE/UPDATE/DELETE), an SNS notification\nis sent to the SNS topic. Users must process these notifications (e.g. through a\nfleet of worker hosts) and submit success/failure responses to the\nCloudFormation service.\n\n> You only need to use this type of provider if your custom resource cannot run on AWS Lambda, for reasons other than the 15\n> minute timeout. If you are considering using this type of provider because you want to write a custom resource provider that may need\n> to wait for more than 15 minutes for the API calls to stabilize, have a look at the [`custom-resources`](#the-custom-resource-provider-framework) module first.\n>\n> Refer to the [CloudFormation Custom Resource documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) for information on the contract your custom resource needs to adhere to.\n\nSet `serviceToken` to `topic.topicArn`  in order to use this provider:\n\n```python\ntopic = sns.Topic(self, \"MyProvider\")\n\nCustomResource(self, \"MyResource\",\n    service_token=topic.topic_arn\n)\n```\n\n#### AWS Lambda Function\n\nAn AWS lambda function is called *directly* by CloudFormation for all resource\nevents. The handler must take care of explicitly submitting a success/failure\nresponse to the CloudFormation service and handle various error cases.\n\n> **We do not recommend you use this provider type.** The CDK has wrappers around Lambda Functions that make them easier to work with.\n>\n> If you do want to use this provider, refer to the [CloudFormation Custom Resource documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html) for information on the contract your custom resource needs to adhere to.\n\nSet `serviceToken` to `lambda.functionArn` to use this provider:\n\n```python\nfn = lambda_.SingletonFunction(self, \"MyProvider\", function_props)\n\nCustomResource(self, \"MyResource\",\n    service_token=fn.function_arn\n)\n```\n\n#### The `core.CustomResourceProvider` class\n\nThe class [`@aws-cdk/core.CustomResourceProvider`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.CustomResourceProvider.html) offers a basic low-level\nframework designed to implement simple and slim custom resource providers. It\ncurrently only supports Node.js-based user handlers, represents permissions as raw\nJSON blobs instead of `iam.PolicyStatement` objects, and it does not have\nsupport for asynchronous waiting (handler cannot exceed the 15min lambda\ntimeout). The `CustomResourceProviderRuntime` supports runtime `nodejs12.x`,\n`nodejs14.x`, `nodejs16.x`, `nodejs18.x`.\n\n> **As an application builder, we do not recommend you use this provider type.** This provider exists purely for custom resources that are part of the AWS Construct Library.\n>\n> The [`custom-resources`](#the-custom-resource-provider-framework) provider is more convenient to work with and more fully-featured.\n\nThe provider has a built-in singleton method which uses the resource type as a\nstack-unique identifier and returns the service token:\n\n```python\nservice_token = CustomResourceProvider.get_or_create(self, \"Custom::MyCustomResourceType\",\n    code_directory=f\"{__dirname}/my-handler\",\n    runtime=CustomResourceProviderRuntime.NODEJS_18_X,\n    description=\"Lambda function created by the custom resource provider\"\n)\n\nCustomResource(self, \"MyResource\",\n    resource_type=\"Custom::MyCustomResourceType\",\n    service_token=service_token\n)\n```\n\nThe directory (`my-handler` in the above example) must include an `index.js` file. It cannot import\nexternal dependencies or files outside this directory. It must export an async\nfunction named `handler`. This function accepts the CloudFormation resource\nevent object and returns an object with the following structure:\n\n```js\nexports.handler = async function(event) {\n  const id = event.PhysicalResourceId; // only for \"Update\" and \"Delete\"\n  const props = event.ResourceProperties;\n  const oldProps = event.OldResourceProperties; // only for \"Update\"s\n\n  switch (event.RequestType) {\n    case \"Create\":\n      // ...\n\n    case \"Update\":\n      // ...\n\n      // if an error is thrown, a FAILED response will be submitted to CFN\n      throw new Error('Failed!');\n\n    case \"Delete\":\n      // ...\n  }\n\n  return {\n    // (optional) the value resolved from `resource.ref`\n    // defaults to \"event.PhysicalResourceId\" or \"event.RequestId\"\n    PhysicalResourceId: \"REF\",\n\n    // (optional) calling `resource.getAtt(\"Att1\")` on the custom resource in the CDK app\n    // will return the value \"BAR\".\n    Data: {\n      Att1: \"BAR\",\n      Att2: \"BAZ\"\n    },\n\n    // (optional) user-visible message\n    Reason: \"User-visible message\",\n\n    // (optional) hides values from the console\n    NoEcho: true\n  };\n}\n```\n\nHere is an complete example of a custom resource that summarizes two numbers:\n\n`sum-handler/index.js`:\n\n```js\nexports.handler = async (e) => {\n  return {\n    Data: {\n      Result: e.ResourceProperties.lhs + e.ResourceProperties.rhs,\n    },\n  };\n};\n```\n\n`sum.ts`:\n\n```python\nfrom constructs import Construct\nfrom aws_cdk import CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, Token\n\nclass Sum(Construct):\n\n    def __init__(self, scope, id, *, lhs, rhs):\n        super().__init__(scope, id)\n\n        resource_type = \"Custom::Sum\"\n        service_token = CustomResourceProvider.get_or_create(self, resource_type,\n            code_directory=f\"{__dirname}/sum-handler\",\n            runtime=CustomResourceProviderRuntime.NODEJS_18_X\n        )\n\n        resource = CustomResource(self, \"Resource\",\n            resource_type=resource_type,\n            service_token=service_token,\n            properties={\n                \"lhs\": lhs,\n                \"rhs\": rhs\n            }\n        )\n\n        self.result = Token.as_number(resource.get_att(\"Result\"))\n```\n\nUsage will look like this:\n\n```python\nsum = Sum(self, \"MySum\", lhs=40, rhs=2)\nCfnOutput(self, \"Result\", value=Token.as_string(sum.result))\n```\n\nTo access the ARN of the provider's AWS Lambda function role, use the `getOrCreateProvider()`\nbuilt-in singleton method:\n\n```python\nprovider = CustomResourceProvider.get_or_create_provider(self, \"Custom::MyCustomResourceType\",\n    code_directory=f\"{__dirname}/my-handler\",\n    runtime=CustomResourceProviderRuntime.NODEJS_18_X\n)\n\nrole_arn = provider.role_arn\n```\n\nThis role ARN can then be used in resource-based IAM policies.\n\nTo add IAM policy statements to this role, use `addToRolePolicy()`:\n\n```python\nprovider = CustomResourceProvider.get_or_create_provider(self, \"Custom::MyCustomResourceType\",\n    code_directory=f\"{__dirname}/my-handler\",\n    runtime=CustomResourceProviderRuntime.NODEJS_18_X\n)\nprovider.add_to_role_policy({\n    \"Effect\": \"Allow\",\n    \"Action\": \"s3:GetObject\",\n    \"Resource\": \"*\"\n})\n```\n\nNote that `addToRolePolicy()` uses direct IAM JSON policy blobs, *not* a\n`iam.PolicyStatement` object like you will see in the rest of the CDK.\n\n#### The Custom Resource Provider Framework\n\nThe [`@aws-cdk/custom-resources`](https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html) module includes an advanced framework for\nimplementing custom resource providers.\n\nHandlers are implemented as AWS Lambda functions, which means that they can be\nimplemented in any Lambda-supported runtime. Furthermore, this provider has an\nasynchronous mode, which means that users can provide an `isComplete` lambda\nfunction which is called periodically until the operation is complete. This\nallows implementing providers that can take up to two hours to stabilize.\n\nSet `serviceToken` to `provider.serviceToken` to use this type of provider:\n\n```python\nprovider = customresources.Provider(self, \"MyProvider\",\n    on_event_handler=on_event_handler,\n    is_complete_handler=is_complete_handler\n)\n\nCustomResource(self, \"MyResource\",\n    service_token=provider.service_token\n)\n```\n\nSee the [documentation](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-cdk-lib.custom_resources-readme.html) for more details.\n\n## AWS CloudFormation features\n\nA CDK stack synthesizes to an AWS CloudFormation Template. This section\nexplains how this module allows users to access low-level CloudFormation\nfeatures when needed.\n\n### Stack Outputs\n\nCloudFormation [stack outputs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html) and exports are created using\nthe `CfnOutput` class:\n\n```python\nCfnOutput(self, \"OutputName\",\n    value=my_bucket.bucket_name,\n    description=\"The name of an S3 bucket\",  # Optional\n    export_name=\"TheAwesomeBucket\"\n)\n```\n\n### Parameters\n\nCloudFormation templates support the use of [Parameters](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html) to\ncustomize a template. They enable CloudFormation users to input custom values to\na template each time a stack is created or updated. While the CDK design\nphilosophy favors using build-time parameterization, users may need to use\nCloudFormation in a number of cases (for example, when migrating an existing\nstack to the AWS CDK).\n\nTemplate parameters can be added to a stack by using the `CfnParameter` class:\n\n```python\nCfnParameter(self, \"MyParameter\",\n    type=\"Number\",\n    default=1337\n)\n```\n\nThe value of parameters can then be obtained using one of the `value` methods.\nAs parameters are only resolved at deployment time, the values obtained are\nplaceholder tokens for the real value (`Token.isUnresolved()` would return `true`\nfor those):\n\n```python\nparam = CfnParameter(self, \"ParameterName\")\n\n# If the parameter is a String\nparam.value_as_string\n\n# If the parameter is a Number\nparam.value_as_number\n\n# If the parameter is a List\nparam.value_as_list\n```\n\n### Pseudo Parameters\n\nCloudFormation supports a number of [pseudo parameters](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html),\nwhich resolve to useful values at deployment time. CloudFormation pseudo\nparameters can be obtained from static members of the `Aws` class.\n\nIt is generally recommended to access pseudo parameters from the scope's `stack`\ninstead, which guarantees the values produced are qualifying the designated\nstack, which is essential in cases where resources are shared cross-stack:\n\n```python\n# \"this\" is the current construct\nstack = Stack.of(self)\n\nstack.account # Returns the AWS::AccountId for this stack (or the literal value if known)\nstack.region # Returns the AWS::Region for this stack (or the literal value if known)\nstack.partition\n```\n\n### Resource Options\n\nCloudFormation resources can also specify [resource\nattributes](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-product-attribute-reference.html). The `CfnResource` class allows\naccessing those through the `cfnOptions` property:\n\n```python\nraw_bucket = s3.CfnBucket(self, \"Bucket\")\n# -or-\nraw_bucket_alt = my_bucket.node.default_child\n\n# then\nraw_bucket.cfn_options.condition = CfnCondition(self, \"EnableBucket\")\nraw_bucket.cfn_options.metadata = {\n    \"metadata_key\": \"MetadataValue\"\n}\n```\n\nResource dependencies (the `DependsOn` attribute) is modified using the\n`cfnResource.addDependency` method:\n\n```python\nresource_a = CfnResource(self, \"ResourceA\", resource_props)\nresource_b = CfnResource(self, \"ResourceB\", resource_props)\n\nresource_b.add_dependency(resource_a)\n```\n\n#### CreationPolicy\n\nSome resources support a [CreationPolicy](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html) to be specified as a CfnOption.\n\nThe creation policy is invoked only when AWS CloudFormation creates the associated resource. Currently, the only AWS CloudFormation resources that support creation policies are `CfnAutoScalingGroup`, `CfnInstance`, `CfnWaitCondition` and `CfnFleet`.\n\nThe `CfnFleet` resource from the `aws-appstream` module supports specifying `startFleet` as\na property of the creationPolicy on the resource options. Setting it to true will make AWS CloudFormation wait until the fleet is started before continuing with the creation of\nresources that depend on the fleet resource.\n\n```python\nfleet = appstream.CfnFleet(self, \"Fleet\",\n    instance_type=\"stream.standard.small\",\n    name=\"Fleet\",\n    compute_capacity=appstream.CfnFleet.ComputeCapacityProperty(\n        desired_instances=1\n    ),\n    image_name=\"AppStream-AmazonLinux2-09-21-2022\"\n)\nfleet.cfn_options.creation_policy = CfnCreationPolicy(\n    start_fleet=True\n)\n```\n\nThe properties passed to the level 2 constructs `AutoScalingGroup` and `Instance` from the\n`aws-ec2` module abstract what is passed into the `CfnOption` properties `resourceSignal` and\n`autoScalingCreationPolicy`, but when using level 1 constructs you can specify these yourself.\n\nThe CfnWaitCondition resource from the `aws-cloudformation` module suppports the `resourceSignal`.\nThe format of the timeout is `PT#H#M#S`. In the example below AWS Cloudformation will wait for\n3 success signals to occur within 15 minutes before the status of the resource will be set to\n`CREATE_COMPLETE`.\n\n```python\n# resource: CfnResource\n\n\nresource.cfn_options.creation_policy = CfnCreationPolicy(\n    resource_signal=CfnResourceSignal(\n        count=3,\n        timeout=\"PR15M\"\n    )\n)\n```\n\n### Intrinsic Functions and Condition Expressions\n\nCloudFormation supports [intrinsic functions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html). These functions\ncan be accessed from the `Fn` class, which provides type-safe methods for each\nintrinsic function as well as condition expressions:\n\n```python\n# my_object_or_array: Any\n# my_array: Any\n\n\n# To use Fn::Base64\nFn.base64(\"SGVsbG8gQ0RLIQo=\")\n\n# To compose condition expressions:\nenvironment_parameter = CfnParameter(self, \"Environment\")\nFn.condition_and(\n    # The \"Environment\" CloudFormation template parameter evaluates to \"Production\"\n    Fn.condition_equals(\"Production\", environment_parameter),\n    # The AWS::Region pseudo-parameter value is NOT equal to \"us-east-1\"\n    Fn.condition_not(Fn.condition_equals(\"us-east-1\", Aws.REGION)))\n\n# To use Fn::ToJsonString\nFn.to_json_string(my_object_or_array)\n\n# To use Fn::Length\nFn.len(Fn.split(\",\", my_array))\n```\n\nWhen working with deploy-time values (those for which `Token.isUnresolved`\nreturns `true`), idiomatic conditionals from the programming language cannot be\nused (the value will not be known until deployment time). When conditional logic\nneeds to be expressed with un-resolved values, it is necessary to use\nCloudFormation conditions by means of the `CfnCondition` class:\n\n```python\nenvironment_parameter = CfnParameter(self, \"Environment\")\nis_prod = CfnCondition(self, \"IsProduction\",\n    expression=Fn.condition_equals(\"Production\", environment_parameter)\n)\n\n# Configuration value that is a different string based on IsProduction\nstage = Fn.condition_if(is_prod.logical_id, \"Beta\", \"Prod\").to_string()\n\n# Make Bucket creation condition to IsProduction by accessing\n# and overriding the CloudFormation resource\nbucket = s3.Bucket(self, \"Bucket\")\ncfn_bucket = my_bucket.node.default_child\ncfn_bucket.cfn_options.condition = is_prod\n```\n\n### Mappings\n\nCloudFormation [mappings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html) are created and queried using the\n`CfnMappings` class:\n\n```python\nregion_table = CfnMapping(self, \"RegionTable\",\n    mapping={\n        \"us-east-1\": {\n            \"region_name\": \"US East (N. Virginia)\"\n        },\n        \"us-east-2\": {\n            \"region_name\": \"US East (Ohio)\"\n        }\n    }\n)\n\nregion_table.find_in_map(Aws.REGION, \"regionName\")\n```\n\nThis will yield the following template:\n\n```yaml\nMappings:\n  RegionTable:\n    us-east-1:\n      regionName: US East (N. Virginia)\n    us-east-2:\n      regionName: US East (Ohio)\n```\n\nMappings can also be synthesized \"lazily\"; lazy mappings will only render a \"Mappings\"\nsection in the synthesized CloudFormation template if some `findInMap` call is unable to\nimmediately return a concrete value due to one or both of the keys being unresolved tokens\n(some value only available at deploy-time).\n\nFor example, the following code will not produce anything in the \"Mappings\" section. The\ncall to `findInMap` will be able to resolve the value during synthesis and simply return\n`'US East (Ohio)'`.\n\n```python\nregion_table = CfnMapping(self, \"RegionTable\",\n    mapping={\n        \"us-east-1\": {\n            \"region_name\": \"US East (N. Virginia)\"\n        },\n        \"us-east-2\": {\n            \"region_name\": \"US East (Ohio)\"\n        }\n    },\n    lazy=True\n)\n\nregion_table.find_in_map(\"us-east-2\", \"regionName\")\n```\n\nOn the other hand, the following code will produce the \"Mappings\" section shown above,\nsince the top-level key is an unresolved token. The call to `findInMap` will return a token that resolves to\n`{ \"Fn::FindInMap\": [ \"RegionTable\", { \"Ref\": \"AWS::Region\" }, \"regionName\" ] }`.\n\n```python\n# region_table: CfnMapping\n\n\nregion_table.find_in_map(Aws.REGION, \"regionName\")\n```\n\nAn optional default value can also be passed to `findInMap`. If either key is not found in the map and the mapping is lazy, `findInMap` will return the default value and not render the mapping.\nIf the mapping is not lazy or either key is an unresolved token, the call to `findInMap` will return a token that resolves to\n`{ \"Fn::FindInMap\": [ \"MapName\", \"TopLevelKey\", \"SecondLevelKey\", { \"DefaultValue\": \"DefaultValue\" } ] }`, and the mapping will be rendered.\nNote that the `AWS::LanguageExtentions` transform is added to enable the default value functionality.\n\nFor example, the following code will again not produce anything in the \"Mappings\" section. The\ncall to `findInMap` will be able to resolve the value during synthesis and simply return\n`'Region not found'`.\n\n```python\nregion_table = CfnMapping(self, \"RegionTable\",\n    mapping={\n        \"us-east-1\": {\n            \"region_name\": \"US East (N. Virginia)\"\n        },\n        \"us-east-2\": {\n            \"region_name\": \"US East (Ohio)\"\n        }\n    },\n    lazy=True\n)\n\nregion_table.find_in_map(\"us-west-1\", \"regionName\", \"Region not found\")\n```\n\n### Dynamic References\n\nCloudFormation supports [dynamically resolving](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html) values\nfor SSM parameters (including secure strings) and Secrets Manager. Encoding such\nreferences is done using the `CfnDynamicReference` class:\n\n```python\nCfnDynamicReference(CfnDynamicReferenceService.SECRETS_MANAGER, \"secret-id:secret-string:json-key:version-stage:version-id\")\n```\n\n### Template Options & Transform\n\nCloudFormation templates support a number of options, including which Macros or\n[Transforms](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html) to use when deploying the stack. Those can be\nconfigured using the `stack.templateOptions` property:\n\n```python\nstack = Stack(app, \"StackName\")\n\nstack.template_options.description = \"This will appear in the AWS console\"\nstack.template_options.transforms = [\"AWS::Serverless-2016-10-31\"]\nstack.template_options.metadata = {\n    \"metadata_key\": \"MetadataValue\"\n}\n```\n\n### Emitting Raw Resources\n\nThe `CfnResource` class allows emitting arbitrary entries in the\n[Resources](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html) section of the CloudFormation template.\n\n```python\nCfnResource(self, \"ResourceId\",\n    type=\"AWS::S3::Bucket\",\n    properties={\n        \"BucketName\": \"amzn-s3-demo-bucket\"\n    }\n)\n```\n\nAs for any other resource, the logical ID in the CloudFormation template will be\ngenerated by the AWS CDK, but the type and properties will be copied verbatim in\nthe synthesized template.\n\n### Including raw CloudFormation template fragments\n\nWhen migrating a CloudFormation stack to the AWS CDK, it can be useful to\ninclude fragments of an existing template verbatim in the synthesized template.\nThis can be achieved using the `CfnInclude` class.\n\n```python\nCfnInclude(self, \"ID\",\n    template={\n        \"Resources\": {\n            \"Bucket\": {\n                \"Type\": \"AWS::S3::Bucket\",\n                \"Properties\": {\n                    \"BucketName\": \"amzn-s3-demo-bucket\"\n                }\n            }\n        }\n    }\n)\n```\n\n### Termination Protection\n\nYou can prevent a stack from being accidentally deleted by enabling termination\nprotection on the stack. If a user attempts to delete a stack with termination\nprotection enabled, the deletion fails and the stack--including its status--remains\nunchanged. Enabling or disabling termination protection on a stack sets it for any\nnested stacks belonging to that stack as well. You can enable termination protection\non a stack by setting the `terminationProtection` prop to `true`.\n\n```python\nstack = Stack(app, \"StackName\",\n    termination_protection=True\n)\n```\n\nYou can also set termination protection with the setter after you've instantiated the stack.\n\n```python\nstack = Stack(app, \"StackName\")\nstack.termination_protection = True\n```\n\nBy default, termination protection is disabled.\n\n### Description\n\nYou can add a description of the stack in the same way as `StackProps`.\n\n```python\nstack = Stack(app, \"StackName\",\n    description=\"This is a description.\"\n)\n```\n\n### CfnJson\n\n`CfnJson` allows you to postpone the resolution of a JSON blob from\ndeployment-time. This is useful in cases where the CloudFormation JSON template\ncannot express a certain value.\n\nA common example is to use `CfnJson` in order to render a JSON map which needs\nto use intrinsic functions in keys. Since JSON map keys must be strings, it is\nimpossible to use intrinsics in keys and `CfnJson` can help.\n\nThe following example defines an IAM role which can only be assumed by\nprincipals that are tagged with a specific tag.\n\n```python\ntag_param = CfnParameter(self, \"TagName\")\n\nstring_equals = CfnJson(self, \"ConditionJson\",\n    value={\n        \"f\"aws:PrincipalTag/{tagParam.valueAsString}\"\": True\n    }\n)\n\nprincipal = iam.AccountRootPrincipal().with_conditions({\n    \"StringEquals\": string_equals\n})\n\niam.Role(self, \"MyRole\", assumed_by=principal)\n```\n\n**Explanation**: since in this example we pass the tag name through a parameter, it\ncan only be resolved during deployment. The resolved value can be represented in\nthe template through a `{ \"Ref\": \"TagName\" }`. However, since we want to use\nthis value inside a [`aws:PrincipalTag/TAG-NAME`](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-principaltag)\nIAM operator, we need it in the *key* of a `StringEquals` condition. JSON keys\n*must be* strings, so to circumvent this limitation, we use `CfnJson`\nto \"delay\" the rendition of this template section to deploy-time. This means\nthat the value of `StringEquals` in the template will be `{ \"Fn::GetAtt\": [ \"ConditionJson\", \"Value\" ] }`, and will only \"expand\" to the operator we synthesized during deployment.\n\n### Stack Resource Limit\n\nWhen deploying to AWS CloudFormation, it needs to keep in check the amount of resources being added inside a Stack. Currently it's possible to check the limits in the [AWS CloudFormation quotas](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html) page.\n\nIt's possible to synthesize the project with more Resources than the allowed (or even reduce the number of Resources).\n\nSet the context key `@aws-cdk/core:stackResourceLimit` with the proper value, being 0 for disable the limit of resources.\n\n### Template Indentation\n\nThe AWS CloudFormation templates generated by CDK include indentation by default.\nIndentation makes the templates more readable, but also increases their size,\nand CloudFormation templates cannot exceed 1MB.\n\nIt's possible to reduce the size of your templates by suppressing indentation.\n\nTo do this for all templates, set the context key `@aws-cdk/core:suppressTemplateIndentation` to `true`.\n\nTo do this for a specific stack, add a `suppressTemplateIndentation: true` property to the\nstack's `StackProps` parameter. You can also set this property to `false` to override\nthe context key setting.\n\n## App Context\n\n[Context values](https://docs.aws.amazon.com/cdk/v2/guide/context.html) are key-value pairs that can be associated with an app, stack, or construct.\nOne common use case for context is to use it for enabling/disabling [feature flags](https://docs.aws.amazon.com/cdk/v2/guide/featureflags.html). There are several places\nwhere context can be specified. They are listed below in the order they are evaluated (items at the\ntop take precedence over those below).\n\n* The `node.setContext()` method\n* The `postCliContext` prop when you create an `App`\n* The CLI via the `--context` CLI argument\n* The `cdk.json` file via the `context` key:\n* The `cdk.context.json` file:\n* The `~/.cdk.json` file via the `context` key:\n* The `context` prop when you create an `App`\n\n### Examples of setting context\n\n```python\nApp(\n    context={\n        \"@aws-cdk/core:newStyleStackSynthesis\": True\n    }\n)\n```\n\n```python\napp = App()\napp.node.set_context(\"@aws-cdk/core:newStyleStackSynthesis\", True)\n```\n\n```python\nApp(\n    post_cli_context={\n        \"@aws-cdk/core:newStyleStackSynthesis\": True\n    }\n)\n```\n\n```console\ncdk synth --context @aws-cdk/core:newStyleStackSynthesis=true\n```\n\n*cdk.json*\n\n```json\n{\n  \"context\": {\n    \"@aws-cdk/core:newStyleStackSynthesis\": true\n  }\n}\n```\n\n*cdk.context.json*\n\n```json\n{\n  \"@aws-cdk/core:newStyleStackSynthesis\": true\n}\n```\n\n*~/.cdk.json*\n\n```json\n{\n  \"context\": {\n    \"@aws-cdk/core:newStyleStackSynthesis\": true\n  }\n}\n```\n\n## IAM Permissions Boundary\n\nIt is possible to apply an [IAM permissions boundary](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html)\nto all roles within a specific construct scope. The most common use case would\nbe to apply a permissions boundary at the `Stage` level.\n\n```python\nprod_stage = Stage(app, \"ProdStage\",\n    permissions_boundary=PermissionsBoundary.from_name(\"cdk-${Qualifier}-PermissionsBoundary\")\n)\n```\n\nAny IAM Roles or Users created within this Stage will have the default\npermissions boundary attached.\n\nFor more details see the [Permissions Boundary](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_iam-readme.html#permissions-boundaries) section in the IAM guide.\n\n## Policy Validation\n\nIf you or your organization use (or would like to use) any policy validation tool, such as\n[CloudFormation\nGuard](https://docs.aws.amazon.com/cfn-guard/latest/ug/what-is-guard.html) or\n[OPA](https://www.openpolicyagent.org/), to define constraints on your\nCloudFormation template, you can incorporate them into the CDK application.\nBy using the appropriate plugin, you can make the CDK application check the\ngenerated CloudFormation templates against your policies immediately after\nsynthesis. If there are any violations, the synthesis will fail and a report\nwill be printed to the console or to a file (see below).\n\n> **Note**\n> This feature is considered experimental, and both the plugin API and the\n> format of the validation report are subject to change in the future.\n\n### For application developers\n\nTo use one or more validation plugins in your application, use the\n`policyValidationBeta1` property of `Stage`:\n\n```python\n# globally for the entire app (an app is a stage)\napp = App(\n    policy_validation_beta1=[\n        # These hypothetical classes implement IPolicyValidationPluginBeta1:\n        ThirdPartyPluginX(),\n        ThirdPartyPluginY()\n    ]\n)\n\n# only apply to a particular stage\nprod_stage = Stage(app, \"ProdStage\",\n    policy_validation_beta1=[\n        ThirdPartyPluginX()\n    ]\n)\n```\n\nImmediately after synthesis, all plugins registered this way will be invoked to\nvalidate all the templates generated in the scope you defined. In particular, if\nyou register the templates in the `App` object, all templates will be subject to\nvalidation.\n\n> **Warning**\n> Other than modifying the cloud assembly, plugins can do anything that your CDK\n> application can. They can read data from the filesystem, access the network\n> etc. It's your responsibility as the consumer of a plugin to verify that it is\n> secure to use.\n\nBy default, the report will be printed in a human readable format. If you want a\nreport in JSON format, enable it using the `@aws-cdk/core:validationReportJson`\ncontext passing it directly to the application:\n\n```python\napp = App(\n    context={\"@aws-cdk/core:validationReportJson\": True}\n)\n```\n\nAlternatively, you can set this context key-value pair using the `cdk.json` or\n`cdk.context.json` files in your project directory (see\n[Runtime context](https://docs.aws.amazon.com/cdk/v2/guide/context.html)).\n\nIf you choose the JSON format, the CDK will print the policy validation report\nto a file called `policy-validation-report.json` in the cloud assembly\ndirectory. For the default, human-readable format, the report will be printed to\nthe standard output.\n\n### For plugin authors\n\nThe communication protocol between the CDK core module and your policy tool is\ndefined by the `IPolicyValidationPluginBeta1` interface. To create a new plugin you must\nwrite a class that implements this interface. There are two things you need to\nimplement: the plugin name (by overriding the `name` property), and the\n`validate()` method.\n\nThe framework will call `validate()`, passing an `IPolicyValidationContextBeta1` object.\nThe location of the templates to be validated is given by `templatePaths`. The\nplugin should return an instance of `PolicyValidationPluginReportBeta1`. This object\nrepresents the report that the user wil receive at the end of the synthesis.\n\n```python\n@jsii.implements(IPolicyValidationPluginBeta1)\nclass MyPlugin:\n\n    def validate(self, context):\n        # First read the templates using context.templatePaths...\n\n        # ...then perform the validation, and then compose and return the report.\n        # Using hard-coded values here for better clarity:\n        return PolicyValidationPluginReportBeta1(\n            success=False,\n            violations=[PolicyViolationBeta1(\n                rule_name=\"CKV_AWS_117\",\n                description=\"Ensure that AWS Lambda function is configured inside a VPC\",\n                fix=\"https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1\",\n                violating_resources=[PolicyViolatingResourceBeta1(\n                    resource_logical_id=\"MyFunction3BAA72D1\",\n                    template_path=\"/home/johndoe/myapp/cdk.out/MyService.template.json\",\n                    locations=[\"Properties/VpcConfig\"]\n                )]\n            )]\n        )\n```\n\nIn addition to the name, plugins may optionally report their version (`version`\nproperty ) and a list of IDs of the rules they are going to evaluate (`ruleIds`\nproperty).\n\nNote that plugins are not allowed to modify anything in the cloud assembly. Any\nattempt to do so will result in synthesis failure.\n\nIf your plugin depends on an external tool, keep in mind that some developers may\nnot have that tool installed in their workstations yet. To minimize friction, we\nhighly recommend that you provide some installation script along with your\nplugin package, to automate the whole process. Better yet, run that script as\npart of the installation of your package. With `npm`, for example, you can run\nadd it to the `postinstall`\n[script](https://docs.npmjs.com/cli/v9/using-npm/scripts) in the `package.json`\nfile.\n\n## Annotations\n\nConstruct authors can add annotations to constructs to report at three different\nlevels: `ERROR`, `WARN`, `INFO`.\n\nTypically warnings are added for things that are important for the user to be\naware of, but will not cause deployment errors in all cases. Some common\nscenarios are (non-exhaustive list):\n\n* Warn when the user needs to take a manual action, e.g. IAM policy should be\n  added to an referenced resource.\n* Warn if the user configuration might not follow best practices (but is still\n  valid)\n* Warn if the user is using a deprecated API\n\n### Acknowledging Warnings\n\nIf you would like to run with `--strict` mode enabled (warnings will throw\nerrors) it is possible to `acknowledge` warnings to make the warning go away.\n\nFor example, if > 10 IAM managed policies are added to an IAM Group, a warning\nwill be created:\n\n```text\nIAM:Group:MaxPoliciesExceeded: You added 11 to IAM Group my-group. The maximum number of managed policies attached to an IAM group is 10.\n```\n\nIf you have requested a [quota increase](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html#reference_iam-quotas-entities)\nyou may have the ability to add > 10 managed policies which means that this\nwarning does not apply to you. You can acknowledge this by `acknowledging` the\nwarning by the `id`.\n\n```python\nAnnotations.of(self).acknowledge_warning(\"IAM:Group:MaxPoliciesExceeded\", \"Account has quota increased to 20\")\n```\n\n<!--END CORE DOCUMENTATION-->\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "Version 2 of the AWS Cloud Development Kit library",
    "version": "2.170.0",
    "project_urls": {
        "Homepage": "https://github.com/aws/aws-cdk",
        "Source": "https://github.com/aws/aws-cdk.git"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ce52bbd2490309b879996a77e04474e22d5911b1643389ae25bfa42bccb07a12",
                "md5": "8c4ff5afe2516bdcf4cbe739eac43c03",
                "sha256": "0eb2b58d45c3ada4b3980488bce1a2279626b081fcdaad55f4aed6b4c6bd4d70"
            },
            "downloads": -1,
            "filename": "aws_cdk_lib-2.170.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8c4ff5afe2516bdcf4cbe739eac43c03",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "~=3.8",
            "size": 37709699,
            "upload_time": "2024-11-22T04:42:10",
            "upload_time_iso_8601": "2024-11-22T04:42:10.626649Z",
            "url": "https://files.pythonhosted.org/packages/ce/52/bbd2490309b879996a77e04474e22d5911b1643389ae25bfa42bccb07a12/aws_cdk_lib-2.170.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f8ec365df25e38be6cc57f138edd02ade91390e860ac159a32205e6867105fa1",
                "md5": "0fe938ae759018205f8e5ca13c08b0d2",
                "sha256": "9194b7637e0204aa031e28ec761d325d0f4a931d3a303b0121812e9ec0bc1147"
            },
            "downloads": -1,
            "filename": "aws_cdk_lib-2.170.0.tar.gz",
            "has_sig": false,
            "md5_digest": "0fe938ae759018205f8e5ca13c08b0d2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "~=3.8",
            "size": 37445904,
            "upload_time": "2024-11-22T04:42:53",
            "upload_time_iso_8601": "2024-11-22T04:42:53.735107Z",
            "url": "https://files.pythonhosted.org/packages/f8/ec/365df25e38be6cc57f138edd02ade91390e860ac159a32205e6867105fa1/aws_cdk_lib-2.170.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-22 04:42:53",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "aws",
    "github_project": "aws-cdk",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "aws-cdk-lib"
}
        
Elapsed time: 0.83407s