0.0.442 • Published 2 days ago

@cdklabs/cdk-enterprise-iac v0.0.442

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
2 days ago

CDK Enterprise IaC

Utilities for using CDK within enterprise constraints.

Install

Typescript

npm install @cdklabs/cdk-enterprise-iac

Python

pip install cdklabs.cdk-enterprise-iac

Who this project is for

Within large enterprises, builders can come up against enterprise imposed constraints when deploying on AWS.

This could be simple things such as "All IAM roles must have a specific Permissions Boundary attached".

This could also be more restrictive such as strict separation of duties, only allowing certain teams the ability to deploy specific AWS resources (e.g. Networking team can deploy VPCs, Subnets, and route tables. Security team can deploy IAM resources. Developers can deploy Compute. DBAs can deploy Databases, etc.)

Enterprises with very restrictive environments like these would benefit from taking a closer look at their policies to see how they can allow builders to safely deploy resources with less friction. However in many enterprises this is easier said than done, and builders are still expected to deliver.

This project is meant to reduce friction for builders working within these enterprise constraints while the enterprise determines what policies make the most sense for their organization, and is in no way prescriptive.

Usage

There are many tools available, all detailed in API.md.

A few examples of these tools below:

Adding permissions boundaries to all generated IAM roles

Example for AddPermissionBoundary in Typescript project.

import * as cdk from 'aws-cdk-lib';
import { MyStack } from '../lib/my-project-stack';
import { Aspects } from 'aws-cdk-lib';
import { AddPermissionBoundary } from '@cdklabs/cdk-enterprise-iac';

const app = new cdk.App();
new MyStack(app, 'MyStack');

Aspects.of(app).add(
  new AddPermissionBoundary({
    permissionsBoundaryPolicyName: 'MyPermissionBoundaryName',
    instanceProfilePrefix: 'MY_PREFIX_', // optional, Defaults to ''
    policyPrefix: 'MY_POLICY_PREFIX_', // optional, Defaults to ''
    rolePrefix: 'MY_ROLE_PREFIX_', // optional, Defaults to ''
  })
);

Example for AddPermissionBoundary in Python project.

import aws_cdk as cdk
from cdklabs.cdk_enterprise_iac import AddPermissionBoundary
from test_py.test_py_stack import TestPyStack


app = cdk.App()
TestPyStack(app, "TestPyStack")

cdk.Aspects.of(app).add(AddPermissionBoundary(
    permissions_boundary_policy_name="MyPermissionBoundaryName",
    instance_profile_prefix="MY_PREFIX_",  # optional, Defaults to ""
    policy_prefix="MY_POLICY_PREFIX_",  # optional, Defaults to ""
    role_prefix="MY_ROLE_PREFIX_"  # optional, Defaults to ""
))

app.synth()

Resource extraction

:warning: Resource extraction is in an experimental phase. Test and validate before using in production. Please open any issues found here.

In many enterprises, there are separate teams with different IAM permissions than developers deploying CDK applications.

For example there might be a networking team with permissions to deploy AWS::EC2::SecurityGroup and AWS::EC2::EIP, or a security team with permissions to deploy AWS::IAM::Role and AWS::IAM::Policy, but the developers deploying the CDK don't have those permissions.

When a developer doesn't have permissions to deploy necessary resources in their CDK application, writing good code becomes difficult to manage when a cdk deploy will quickly error due to not being able to deploy something like an AWS::IAM::Role which is foundational to any project deployed into AWS.

An enterprise should allow builders to deploy these resources via CDK for many reasons, and can use Permissions Boundaries to prevent privilege escalation. For enterprises that haven't yet utilized Permissions Boundaries, the ResourceExtractor can make it easier for builders to write good CDK while complying with enterprise policies.

Using the ResourceExtractor Aspect, developers can write their CDK code as though they had sufficient IAM permissions, but extract those resources into a separate stack for an external team to deploy on their behalf.

Take the following example stack:

import { App, Aspects, RemovalPolicy, Stack } from 'aws-cdk-lib';
import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
import { Bucket } from 'aws-cdk-lib/aws-s3';

const app = new App();
const appStack = new Stack(app, 'MyAppStack');

const func = new Function(appStack, 'TestLambda', {
  code: Code.fromAsset(path.join(__dirname, 'lambda-handler')),
  handler: 'index.handler',
  runtime: Runtime.PYTHON_3_11,
});
const bucket = new Bucket(appStack, 'TestBucket', {
  autoDeleteObjects: true,
  removalPolicy: RemovalPolicy.DESTROY,
});
bucket.grantReadWrite(func);

app.synth()

The synthesized Cloudformation would include all AWS resources required, including resources a developer might not have permissions to deploy

The above example would include the following snippet in the synthesized Cloudformation

TestLambdaServiceRoleC28C2D9C:
  Type: 'AWS::IAM::Role'
  Properties:
    AssumeRolePolicyDocument:
      Statement:
        - Action: 'sts:AssumeRole'
          Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
      Version: 2012-10-17
    # excluding remaining properties
  TestLambda2F70C45E:
    Type: 'AWS::Lambda::Function'
    Properties:
      Role: !GetAtt
        - TestLambdaServiceRoleC28C2D9C
        - Arn
      # excluding remaining properties

While including bucket.grantReadWrite(func) in the CDK application ensures an IAM role with least privilege IAM policies for the application, the creation of IAM resources such as Roles and Policies may be restricted to a security team, resulting in the synthesized Cloudformation template not being deployable by a developer.

Using the ResourceExtractor, we can pull out an arbitrary list of Cloudformation resources that a developer doesn't have permissions to provision, and create a separate stack that can be sent to a security team.

import { App, Aspects, RemovalPolicy, Stack } from 'aws-cdk-lib';
import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
import { Bucket } from 'aws-cdk-lib/aws-s3';
// Import ResourceExtractor
import { ResourceExtractor } from '@cdklabs/cdk-enterprise-iac';

const app = new App();
const appStack = new Stack(app, 'MyAppStack');
// Set up a destination stack to extract resources to
const extractedStack = new Stack(app, 'ExtractedStack');

const func = new Function(appStack, 'TestLambda', {
  code: Code.fromAsset(path.join(__dirname, 'lambda-handler')),
  handler: 'index.handler',
  runtime: Runtime.PYTHON_3_11,
});
const bucket = new Bucket(appStack, 'TestBucket', {
  autoDeleteObjects: true,
  removalPolicy: RemovalPolicy.DESTROY,
});
bucket.grantReadWrite(func);

// Capture the output of app.synth()
const synthedApp = app.synth();
// Apply the ResourceExtractor Aspect
Aspects.of(app).add(
  new ResourceExtractor({
    // synthesized stacks to examine
    stackArtifacts: synthedApp.stacks,
    // Array of Cloudformation resources to extract
    resourceTypesToExtract: [
      'AWS::IAM::Role',
      'AWS::IAM::Policy',
      'AWS::IAM::ManagedPolicy',
      'AWS::IAM::InstanceProfile',
    ],
    // Destination stack for extracted resources
    extractDestinationStack: extractedStack,
  })
);
// Resynthing since ResourceExtractor has modified the app
app.synth({ force: true });

In the example above, all resources are created in the appStack, and an empty extractedStack is also created.

We apply the ResourceExtractor Aspect, specifying the Cloudformation resource types the developer is unable to deploy due to insufficient IAM permissions.

Now when we list stacks in the CDK project, we can see an added stack

$ cdk ls
MyAppStack
ExtractedStack

Taking a look at these synthesized stacks, in the ExtractedStack we'll find:

Resources:
  TestLambdaServiceRoleC28C2D9C:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: 'sts:AssumeRole'
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: 2012-10-17
      # excluding remaining properties
Outputs:
  ExportAppStackTestLambdaServiceRoleC28C2D9C:
    Value:
      'Fn::GetAtt':
        - TestLambdaServiceRoleC28C2D9C
        - Arn
    Export:
      Name: 'AppStack:TestLambdaServiceRoleC28C2D9C'  # Exported name

And inside the synthesized MyAppStack template:

Resources:
  TestLambda2F70C45E:
    Type: 'AWS::Lambda::Function'
    Properties:
      Role: !ImportValue 'AppStack:TestLambdaServiceRoleC28C2D9C'  # Using ImportValue instrinsic function to use pre-created IAM role
      # excluding remaining properties

In this scenario, a developer is able to provide an external security team with sufficient IAM privileges to deploy the ExtractedStack.

Once deployed, a developer can run cdk deploy MyAppStack without errors due to insufficient IAM privileges

Value Sharing methods

When resources are extracted from a stack, there must be a method to reference the resources that have been extracted.

There are three methods (see ResourceExtractorShareMethod enum)

  • CFN_OUTPUT
  • SSM_PARAMETER
  • API_LOOKUP
CFN_OUTPUT

The default sharing method is CFN_OUTPUT, which uses Cloudformation Export/Import to Export values in the extracted stack (see Outputs), and use the Fn::ImportValue intrinsic function to reference those values.

This works fine, but some teams may prefer a looser coupling between the extracted stack deployed by an external team and the rest of the CDK infrastructure.

SSM_PARAMETER

In this method, the extracted stack generates Parameters in AWS Systems Manager Parameter Store, and modifies the CDK application to look up the generated parameter using aws_ssm.StringParameter.valueFromLookup() at synthesis time.

Example on using this method:

import { ResourceExtractor, ResourceExtractorShareMethod } from '@cdklabs/cdk-enterprise-iac';

Aspects.of(app).add(
  new ResourceExtractor({
    stackArtifacts: synthedApp.stacks,
    resourceTypesToExtract: [
      'AWS::IAM::Role',
      'AWS::IAM::Policy',
      'AWS::IAM::ManagedPolicy',
      'AWS::IAM::InstanceProfile',
    ],
    extractDestinationStack: extractedStack,
    valueShareMethod: ResourceExtractorShareMethod.SSM_PARAMETER,  // Specify SSM_PARAMETER Method
  });
);
API_LOOKUP

The API_LOOKUP sharing method is a work in progress, and not yet supported

Resource Partials

Some resources that get extracted might reference resources that aren't yet created.

In our example CDK application we include the line

bucket.grantReadWrite(func);

This creates an AWS::IAM::Policy that includes the necessary Actions scoped down to the S3 bucket.

When the AWS::IAM::Policy is extracted, it's unable to use Ref or Fn::GetAtt to reference the S3 bucket since the S3 bucket wasn't extracted.

In this case we substitute the reference with a "partial ARN" that makes a best effort to scope the resources in the IAM policy statement to the ARN of the yet-to-be created S3 bucket.

There are multiple resource types supported out of the box (found in createDefaultTransforms). In the event you have a resource not yet supported, you'll receive a MissingTransformError. In this case you can either open an issue with the resource in question, or you can include the additionalTransforms property.

Consider the following:

const vpc = new Vpc(stack, 'TestVpc');
const db = new DatabaseInstance(stack, 'TestDb', {
  vpc,
  engine: DatabaseInstanceEngine.POSTGRES,
})
const func = new Function(stack, 'TestLambda', {
  code: Code.fromAsset(path.join(__dirname, 'lambda-handler')),
  handler: 'index.handler',
  runtime: Runtime.PYTHON_3_11,
});
db.secret?.grantRead(func)

const synthedApp = app.synth();
Aspects.of(app).add(
  new ResourceExtractor({
    extractDestinationStack: extractedStack,
    stackArtifacts: synthedApp.stacks,
    valueShareMethod: ResourceExtractorShareMethod.CFN_OUTPUT,
    resourceTypesToExtract: ['AWS::IAM::Role', 'AWS::IAM::Policy'],
    additionalTransforms: {
      'AWS::SecretsManager::SecretTargetAttachment': `arn:${Aws.PARTITION}:secretsmanager:${Aws.REGION}:${Aws.ACCOUNT_ID}:secret:some-expected-value*`,
    },
  });
);
app.synth({ force: true });

In this case, there is a AWS::SecretsManager::SecretTargetAttachment generated to complete the final link between a Secrets Manager secret and the associated database by adding the database connection information to the secret JSON, which returns the ARN of the generated secret.

In the context of extracting the IAM policy, we want to tell the ResourceExtractor how to handle the resource section of the IAM policy statement so that it is scoped down sufficiently.

In this case rather than using a Ref: LogicalIdForTheSecretTargetAttachment we construct the ARN we want to use.

Details in API.md

Generated API.md


Generated API.md below:

CDK Enterprise IaC

Utilities for using CDK within enterprise constraints.

Install

Typescript

npm install @cdklabs/cdk-enterprise-iac

Python

pip install cdklabs.cdk-enterprise-iac

Who this project is for

Within large enterprises, builders can come up against enterprise imposed constraints when deploying on AWS.

This could be simple things such as "All IAM roles must have a specific Permissions Boundary attached".

This could also be more restrictive such as strict separation of duties, only allowing certain teams the ability to deploy specific AWS resources (e.g. Networking team can deploy VPCs, Subnets, and route tables. Security team can deploy IAM resources. Developers can deploy Compute. DBAs can deploy Databases, etc.)

Enterprises with very restrictive environments like these would benefit from taking a closer look at their policies to see how they can allow builders to safely deploy resources with less friction. However in many enterprises this is easier said than done, and builders are still expected to deliver.

This project is meant to reduce friction for builders working within these enterprise constraints while the enterprise determines what policies make the most sense for their organization, and is in no way prescriptive.

Usage

There are many tools available, all detailed in API.md.

A few examples of these tools below:

Adding permissions boundaries to all generated IAM roles

Example for AddPermissionBoundary in Typescript project.

import * as cdk from 'aws-cdk-lib';
import { MyStack } from '../lib/my-project-stack';
import { Aspects } from 'aws-cdk-lib';
import { AddPermissionBoundary } from '@cdklabs/cdk-enterprise-iac';

const app = new cdk.App();
new MyStack(app, 'MyStack');

Aspects.of(app).add(
  new AddPermissionBoundary({
    permissionsBoundaryPolicyName: 'MyPermissionBoundaryName',
    instanceProfilePrefix: 'MY_PREFIX_', // optional, Defaults to ''
    policyPrefix: 'MY_POLICY_PREFIX_', // optional, Defaults to ''
    rolePrefix: 'MY_ROLE_PREFIX_', // optional, Defaults to ''
  })
);

Example for AddPermissionBoundary in Python project.

import aws_cdk as cdk
from cdklabs.cdk_enterprise_iac import AddPermissionBoundary
from test_py.test_py_stack import TestPyStack


app = cdk.App()
TestPyStack(app, "TestPyStack")

cdk.Aspects.of(app).add(AddPermissionBoundary(
    permissions_boundary_policy_name="MyPermissionBoundaryName",
    instance_profile_prefix="MY_PREFIX_",  # optional, Defaults to ""
    policy_prefix="MY_POLICY_PREFIX_",  # optional, Defaults to ""
    role_prefix="MY_ROLE_PREFIX_"  # optional, Defaults to ""
))

app.synth()

Resource extraction

:warning: Resource extraction is in an experimental phase. Test and validate before using in production. Please open any issues found here.

In many enterprises, there are separate teams with different IAM permissions than developers deploying CDK applications.

For example there might be a networking team with permissions to deploy AWS::EC2::SecurityGroup and AWS::EC2::EIP, or a security team with permissions to deploy AWS::IAM::Role and AWS::IAM::Policy, but the developers deploying the CDK don't have those permissions.

When a developer doesn't have permissions to deploy necessary resources in their CDK application, writing good code becomes difficult to manage when a cdk deploy will quickly error due to not being able to deploy something like an AWS::IAM::Role which is foundational to any project deployed into AWS.

An enterprise should allow builders to deploy these resources via CDK for many reasons, and can use Permissions Boundaries to prevent privilege escalation. For enterprises that haven't yet utilized Permissions Boundaries, the ResourceExtractor can make it easier for builders to write good CDK while complying with enterprise policies.

Using the ResourceExtractor Aspect, developers can write their CDK code as though they had sufficient IAM permissions, but extract those resources into a separate stack for an external team to deploy on their behalf.

Take the following example stack:

import { App, Aspects, RemovalPolicy, Stack } from 'aws-cdk-lib';
import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
import { Bucket } from 'aws-cdk-lib/aws-s3';

const app = new App();
const appStack = new Stack(app, 'MyAppStack');

const func = new Function(appStack, 'TestLambda', {
  code: Code.fromAsset(path.join(__dirname, 'lambda-handler')),
  handler: 'index.handler',
  runtime: Runtime.PYTHON_3_11,
});
const bucket = new Bucket(appStack, 'TestBucket', {
  autoDeleteObjects: true,
  removalPolicy: RemovalPolicy.DESTROY,
});
bucket.grantReadWrite(func);

app.synth()

The synthesized Cloudformation would include all AWS resources required, including resources a developer might not have permissions to deploy

The above example would include the following snippet in the synthesized Cloudformation

TestLambdaServiceRoleC28C2D9C:
  Type: 'AWS::IAM::Role'
  Properties:
    AssumeRolePolicyDocument:
      Statement:
        - Action: 'sts:AssumeRole'
          Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
      Version: 2012-10-17
    # excluding remaining properties
  TestLambda2F70C45E:
    Type: 'AWS::Lambda::Function'
    Properties:
      Role: !GetAtt
        - TestLambdaServiceRoleC28C2D9C
        - Arn
      # excluding remaining properties

While including bucket.grantReadWrite(func) in the CDK application ensures an IAM role with least privilege IAM policies for the application, the creation of IAM resources such as Roles and Policies may be restricted to a security team, resulting in the synthesized Cloudformation template not being deployable by a developer.

Using the ResourceExtractor, we can pull out an arbitrary list of Cloudformation resources that a developer doesn't have permissions to provision, and create a separate stack that can be sent to a security team.

import { App, Aspects, RemovalPolicy, Stack } from 'aws-cdk-lib';
import { Code, Function, Runtime } from 'aws-cdk-lib/aws-lambda';
import { Bucket } from 'aws-cdk-lib/aws-s3';
// Import ResourceExtractor
import { ResourceExtractor } from '@cdklabs/cdk-enterprise-iac';

const app = new App();
const appStack = new Stack(app, 'MyAppStack');
// Set up a destination stack to extract resources to
const extractedStack = new Stack(app, 'ExtractedStack');

const func = new Function(appStack, 'TestLambda', {
  code: Code.fromAsset(path.join(__dirname, 'lambda-handler')),
  handler: 'index.handler',
  runtime: Runtime.PYTHON_3_11,
});
const bucket = new Bucket(appStack, 'TestBucket', {
  autoDeleteObjects: true,
  removalPolicy: RemovalPolicy.DESTROY,
});
bucket.grantReadWrite(func);

// Capture the output of app.synth()
const synthedApp = app.synth();
// Apply the ResourceExtractor Aspect
Aspects.of(app).add(
  new ResourceExtractor({
    // synthesized stacks to examine
    stackArtifacts: synthedApp.stacks,
    // Array of Cloudformation resources to extract
    resourceTypesToExtract: [
      'AWS::IAM::Role',
      'AWS::IAM::Policy',
      'AWS::IAM::ManagedPolicy',
      'AWS::IAM::InstanceProfile',
    ],
    // Destination stack for extracted resources
    extractDestinationStack: extractedStack,
  })
);
// Resynthing since ResourceExtractor has modified the app
app.synth({ force: true });

In the example above, all resources are created in the appStack, and an empty extractedStack is also created.

We apply the ResourceExtractor Aspect, specifying the Cloudformation resource types the developer is unable to deploy due to insufficient IAM permissions.

Now when we list stacks in the CDK project, we can see an added stack

$ cdk ls
MyAppStack
ExtractedStack

Taking a look at these synthesized stacks, in the ExtractedStack we'll find:

Resources:
  TestLambdaServiceRoleC28C2D9C:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: 'sts:AssumeRole'
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: 2012-10-17
      # excluding remaining properties
Outputs:
  ExportAppStackTestLambdaServiceRoleC28C2D9C:
    Value:
      'Fn::GetAtt':
        - TestLambdaServiceRoleC28C2D9C
        - Arn
    Export:
      Name: 'AppStack:TestLambdaServiceRoleC28C2D9C'  # Exported name

And inside the synthesized MyAppStack template:

Resources:
  TestLambda2F70C45E:
    Type: 'AWS::Lambda::Function'
    Properties:
      Role: !ImportValue 'AppStack:TestLambdaServiceRoleC28C2D9C'  # Using ImportValue instrinsic function to use pre-created IAM role
      # excluding remaining properties

In this scenario, a developer is able to provide an external security team with sufficient IAM privileges to deploy the ExtractedStack.

Once deployed, a developer can run cdk deploy MyAppStack without errors due to insufficient IAM privileges

Value Sharing methods

When resources are extracted from a stack, there must be a method to reference the resources that have been extracted.

There are three methods (see ResourceExtractorShareMethod enum)

  • CFN_OUTPUT
  • SSM_PARAMETER
  • API_LOOKUP
CFN_OUTPUT

The default sharing method is CFN_OUTPUT, which uses Cloudformation Export/Import to Export values in the extracted stack (see Outputs), and use the Fn::ImportValue intrinsic function to reference those values.

This works fine, but some teams may prefer a looser coupling between the extracted stack deployed by an external team and the rest of the CDK infrastructure.

SSM_PARAMETER

In this method, the extracted stack generates Parameters in AWS Systems Manager Parameter Store, and modifies the CDK application to look up the generated parameter using aws_ssm.StringParameter.valueFromLookup() at synthesis time.

Example on using this method:

import { ResourceExtractor, ResourceExtractorShareMethod } from '@cdklabs/cdk-enterprise-iac';

Aspects.of(app).add(
  new ResourceExtractor({
    stackArtifacts: synthedApp.stacks,
    resourceTypesToExtract: [
      'AWS::IAM::Role',
      'AWS::IAM::Policy',
      'AWS::IAM::ManagedPolicy',
      'AWS::IAM::InstanceProfile',
    ],
    extractDestinationStack: extractedStack,
    valueShareMethod: ResourceExtractorShareMethod.SSM_PARAMETER,  // Specify SSM_PARAMETER Method
  });
);
API_LOOKUP

The API_LOOKUP sharing method is a work in progress, and not yet supported

Resource Partials

Some resources that get extracted might reference resources that aren't yet created.

In our example CDK application we include the line

bucket.grantReadWrite(func);

This creates an AWS::IAM::Policy that includes the necessary Actions scoped down to the S3 bucket.

When the AWS::IAM::Policy is extracted, it's unable to use Ref or Fn::GetAtt to reference the S3 bucket since the S3 bucket wasn't extracted.

In this case we substitute the reference with a "partial ARN" that makes a best effort to scope the resources in the IAM policy statement to the ARN of the yet-to-be created S3 bucket.

There are multiple resource types supported out of the box (found in createDefaultTransforms). In the event you have a resource not yet supported, you'll receive a MissingTransformError. In this case you can either open an issue with the resource in question, or you can include the additionalTransforms property.

Consider the following:

const vpc = new Vpc(stack, 'TestVpc');
const db = new DatabaseInstance(stack, 'TestDb', {
  vpc,
  engine: DatabaseInstanceEngine.POSTGRES,
})
const func = new Function(stack, 'TestLambda', {
  code: Code.fromAsset(path.join(__dirname, 'lambda-handler')),
  handler: 'index.handler',
  runtime: Runtime.PYTHON_3_11,
});
db.secret?.grantRead(func)

const synthedApp = app.synth();
Aspects.of(app).add(
  new ResourceExtractor({
    extractDestinationStack: extractedStack,
    stackArtifacts: synthedApp.stacks,
    valueShareMethod: ResourceExtractorShareMethod.CFN_OUTPUT,
    resourceTypesToExtract: ['AWS::IAM::Role', 'AWS::IAM::Policy'],
    additionalTransforms: {
      'AWS::SecretsManager::SecretTargetAttachment': `arn:${Aws.PARTITION}:secretsmanager:${Aws.REGION}:${Aws.ACCOUNT_ID}:secret:some-expected-value*`,
    },
  });
);
app.synth({ force: true });

In this case, there is a AWS::SecretsManager::SecretTargetAttachment generated to complete the final link between a Secrets Manager secret and the associated database by adding the database connection information to the secret JSON, which returns the ARN of the generated secret.

In the context of extracting the IAM policy, we want to tell the ResourceExtractor how to handle the resource section of the IAM policy statement so that it is scoped down sufficiently.

In this case rather than using a Ref: LogicalIdForTheSecretTargetAttachment we construct the ARN we want to use.

Details in API.md

Generated API.md


Generated API.md below:

API Reference

Constructs

EcsIsoServiceAutoscaler

Creates a EcsIsoServiceAutoscaler construct.

This construct allows you to scale an ECS service in an ISO region where classic ECS Autoscaling may not be available.

Initializers

import { EcsIsoServiceAutoscaler } from '@cdklabs/cdk-enterprise-iac'

new EcsIsoServiceAutoscaler(scope: Construct, id: string, props: EcsIsoServiceAutoscalerProps)
NameTypeDescription
scopeconstructs.ConstructNo description.
idstringNo description.
propsEcsIsoServiceAutoscalerPropsNo description.

scopeRequired
  • Type: constructs.Construct

idRequired
  • Type: string

propsRequired
  • Type: EcsIsoServiceAutoscalerProps

Methods

NameDescription
toStringReturns a string representation of this construct.

toString
public toString(): string

Returns a string representation of this construct.

Static Functions

NameDescription
isConstructChecks if x is a construct.

isConstruct
import { EcsIsoServiceAutoscaler } from '@cdklabs/cdk-enterprise-iac'

EcsIsoServiceAutoscaler.isConstruct(x: any)

Checks if x is a construct.

xRequired
  • Type: any

Any object.


Properties

NameTypeDescription
nodeconstructs.NodeThe tree node.
ecsScalingManagerFunctionaws-cdk-lib.aws_lambda.FunctionNo description.

nodeRequired
public readonly node: Node;
  • Type: constructs.Node

The tree node.


ecsScalingManagerFunctionRequired
public readonly ecsScalingManagerFunction: Function;
  • Type: aws-cdk-lib.aws_lambda.Function

PopulateWithConfig

Populate a provided VPC with subnets based on a provided configuration.

Example

const mySubnetConfig: SubnetConfig[] = [
   {
     groupName: 'app',
     cidrRange: '172.31.0.0/27',
     availabilityZone: 'a',
     subnetType: subnetType.PUBLIC,
   },
   {
     groupName: 'app',
     cidrRange: '172.31.0.32/27',
     availabilityZone: 'b',
     subnetType: subnetType.PUBLIC,
   },
   {
     groupName: 'db',
     cidrRange: '172.31.0.64/27',
     availabilityZone: 'a',
     subnetType: subnetType.PRIVATE_WITH_EGRESS,
   },
   {
     groupName: 'db',
     cidrRange: '172.31.0.96/27',
     availabilityZone: 'b',
     subnetType: subnetType.PRIVATE_WITH_EGRESS,
   },
   {
     groupName: 'iso',
     cidrRange: '172.31.0.128/26',
     availabilityZone: 'a',
     subnetType: subnetType.PRIVATE_ISOLATED,
   },
   {
     groupName: 'iso',
     cidrRange: '172.31.0.196/26',
     availabilityZone: 'b',
     subnetType: subnetType.PRIVATE_ISOLATED,
   },
 ];
new PopulateWithConfig(this, "vpcPopulater", {
  vpcId: 'vpc-abcdefg1234567',
  privateRouteTableId: 'rt-abcdefg123456',
  localRouteTableId: 'rt-123456abcdefg',
  subnetConfig: mySubnetConfig,
})

Initializers

import { PopulateWithConfig } from '@cdklabs/cdk-enterprise-iac'

new PopulateWithConfig(scope: Construct, id: string, props: PopulateWithConfigProps)
NameTypeDescription
scopeconstructs.ConstructNo description.
idstringNo description.
propsPopulateWithConfigPropsNo description.

scopeRequired
  • Type: constructs.Construct

idRequired
  • Type: string

propsRequired
  • Type: PopulateWithConfigProps

Methods

NameDescription
toStringReturns a string representation of this construct.

toString
public toString(): string

Returns a string representation of this construct.

Static Functions

NameDescription
isConstructChecks if x is a construct.

isConstruct
import { PopulateWithConfig } from '@cdklabs/cdk-enterprise-iac'

PopulateWithConfig.isConstruct(x: any)

Checks if x is a construct.

xRequired
  • Type: any

Any object.


Properties

NameTypeDescription
nodeconstructs.NodeThe tree node.

nodeRequired
public readonly node: Node;
  • Type: constructs.Node

The tree node.


SplitVpcEvenly

Splits a VPC evenly between a provided number of AZs (3 if not defined), and attaches a provided route table to each, and labels.

Example

// with more specific properties
new SplitVpcEvenly(this, 'evenSplitVpc', {
  vpcId: 'vpc-abcdefg123456',
  vpcCidr: '172.16.0.0/16',
  routeTableId: 'rt-abcdefgh123456',
  cidrBits: '10',
  numberOfAzs: 4,
  subnetType: subnetType.PRIVATE_ISOLATED,
});

Initializers

import { SplitVpcEvenly } from '@cdklabs/cdk-enterprise-iac'

new SplitVpcEvenly(scope: Construct, id: string, props: SplitVpcEvenlyProps)
NameTypeDescription
scopeconstructs.ConstructNo description.
idstringNo description.
propsSplitVpcEvenlyPropsNo description.

scopeRequired
  • Type: constructs.Construct

idRequired
  • Type: string

propsRequired
  • Type: SplitVpcEvenlyProps

Methods

NameDescription
toStringReturns a string representation of this construct.

toString
public toString(): string

Returns a string representation of this construct.

Static Functions

NameDescription
isConstructChecks if x is a construct.

isConstruct
import { SplitVpcEvenly } from '@cdklabs/cdk-enterprise-iac'

SplitVpcEvenly.isConstruct(x: any)

Checks if x is a construct.

xRequired
  • Type: any

Any object.


Properties

NameTypeDescription
nodeconstructs.NodeThe tree node.

nodeRequired
public readonly node: Node;
  • Type: constructs.Node

The tree node.


Structs

AddCfnInitProxyProps

Properties for the proxy server to use with cfn helper commands.

Initializer

import { AddCfnInitProxyProps } from '@cdklabs/cdk-enterprise-iac'

const addCfnInitProxyProps: AddCfnInitProxyProps = { ... }

Properties

NameTypeDescription
proxyHoststringhost of your proxy.
proxyPortnumberproxy port.
proxyCredentialsaws-cdk-lib.aws_secretsmanager.ISecretJSON secret containing user and password properties to use if your proxy requires credentials http://user:password@host:port could contain sensitive data, so using a Secret.
proxyTypeProxyTypeProxy Type.

proxyHostRequired
public readonly proxyHost: string;
  • Type: string

host of your proxy.


Example

example.com
proxyPortRequired
public readonly proxyPort: number;
  • Type: number

proxy port.


Example

8080
proxyCredentialsOptional
public readonly proxyCredentials: ISecret;
  • Type: aws-cdk-lib.aws_secretsmanager.ISecret

JSON secret containing user and password properties to use if your proxy requires credentials http://user:password@host:port could contain sensitive data, so using a Secret.

Note that while the user and password won't be visible in the cloudformation template they will be in plain text inside your UserData


Example

const secret = new Secret(stack, 'TestSecret', {
 secretObjectValue: {
   user: SecretValue,
   password: SecretValue,
 },
});
proxyTypeOptional
public readonly proxyType: ProxyType;
  • Type: ProxyType
  • Default: ProxyType.HTTP

Proxy Type.


Example

ProxyType.HTTPS

AddPermissionBoundaryProps

Properties to pass to the AddPermissionBoundary.

Initializer

import { AddPermissionBoundaryProps } from '@cdklabs/cdk-enterprise-iac'

const addPermissionBoundaryProps: AddPermissionBoundaryProps = { ... }

Properties

NameTypeDescription
permissionsBoundaryPolicyNamestringName of Permissions Boundary Policy to add to all IAM roles.
instanceProfilePrefixstringA prefix to prepend to the name of the IAM InstanceProfiles (Default: '').
policyPrefixstringA prefix to prepend to the name of the IAM Policies and ManagedPolicies (Default: '').
rolePrefixstringA prefix to prepend to the name of IAM Roles (Default: '').

permissionsBoundaryPolicyNameRequired
public readonly permissionsBoundaryPolicyName: string;
  • Type: string

Name of Permissions Boundary Policy to add to all IAM roles.


instanceProfilePrefixOptional
public readonly instanceProfilePrefix: string;
  • Type: string

A prefix to prepend to the name of the IAM InstanceProfiles (Default: '').


policyPrefixOptional
public readonly policyPrefix: string;
  • Type: string

A prefix to prepend to the name of the IAM Policies and ManagedPolicies (Default: '').


rolePrefixOptional
public readonly rolePrefix: string;
  • Type: string

A prefix to prepend to the name of IAM Roles (Default: '').


EcsIsoServiceAutoscalerProps

Initializer

import { EcsIsoServiceAutoscalerProps } from '@cdklabs/cdk-enterprise-iac'

const ecsIsoServiceAutoscalerProps: EcsIsoServiceAutoscalerProps = { ... }

Properties

NameTypeDescription
ecsClusteraws-cdk-lib.aws_ecs.ClusterThe cluster the service you wish to scale resides in.
ecsServiceaws-cdk-lib.aws_ecs.IServiceThe ECS service you wish to scale.
scaleAlarmaws-cdk-lib.aws_cloudwatch.AlarmBaseThe Cloudwatch Alarm that will cause scaling actions to be invoked, whether it's in or not in alarm will determine scale up and down actions.
maximumTaskCountnumberThe maximum number of tasks that the service will scale out to.
minimumTaskCountnumberThe minimum number of tasks the service will have.
roleaws-cdk-lib.aws_iam.IRoleOptional IAM role to attach to the created lambda to adjust the desired count on the ECS Service.
scaleInCooldownaws-cdk-lib.DurationHow long will the application wait before performing another scale in action.
scaleInIncrementnumberThe number of tasks that will scale in on scale in alarm status.
scaleOutCooldownaws-cdk-lib.DurationHow long will a the application wait before performing another scale out action.
scaleOutIncrementnumberThe number of tasks that will scale out on scale out alarm status.

ecsClusterRequired
public readonly ecsCluster: Cluster;
  • Type: aws-cdk-lib.aws_ecs.Cluster

The cluster the service you wish to scale resides in.


ecsServiceRequired
public readonly ecsService: IService;
  • Type: aws-cdk-lib.aws_ecs.IService

The ECS service you wish to scale.


scaleAlarmRequired
public readonly scaleAlarm: AlarmBase;
  • Type: aws-cdk-lib.aws_cloudwatch.AlarmBase

The Cloudwatch Alarm that will cause scaling actions to be invoked, whether it's in or not in alarm will determine scale up and down actions.

Note: composite alarms can not be generated with CFN in all regions, while this allows you to pass in a composite alarm alarm creation is outside the scope of this construct


maximumTaskCountOptional
public readonly maximumTaskCount: number;
  • Type: number
  • Default: 10

The maximum number of tasks that the service will scale out to.

Note: This does not provide any protection from scaling out above the maximum allowed in your account, set this variable and manage account quotas appropriately.


minimumTaskCountOptional
public readonly minimumTaskCount: number;
  • Type: number
  • Default: 1

The minimum number of tasks the service will have.


roleOptional
public readonly role: IRole;
  • Type: aws-cdk-lib.aws_iam.IRole
  • Default: A role is created for you with least privilege IAM policy

Optional IAM role to attach to the created lambda to adjust the desired count on the ECS Service.

Ensure this role has appropriate privileges. Example IAM policy statements:

{
  "PolicyDocument": {
    "Statement": [
      {
        "Action": "cloudwatch:DescribeAlarms",
        "Effect": "Allow",
        "Resource": "*"
      },
      {
        "Action": [
          "ecs:DescribeServices",
          "ecs:UpdateService"
        ],
        "Condition": {
          "StringEquals": {
            "ecs:cluster": "arn:${Partition}:ecs:${Region}:${Account}:cluster/${ClusterName}"
          }
        },
        "Effect": "Allow",
        "Resource": "arn:${Partition}:ecs:${Region}:${Account}:service/${ClusterName}/${ServiceName}"
      }
    ],
    "Version": "2012-10-17"
  }
}

scaleInCooldownOptional
public readonly scaleInCooldown: Duration;
  • Type: aws-cdk-lib.Duration
  • Default: 60 seconds

How long will the application wait before performing another scale in action.


scaleInIncrementOptional
public readonly scaleInIncrement: number;
  • Type: number
  • Default: 1

The number of tasks that will scale in on scale in alarm status.


scaleOutCooldownOptional
public readonly scaleOutCooldown: Duration;
  • Type: aws-cdk-lib.Duration
  • Default: 60 seconds

How long will a the application wait before performing another scale out action.


scaleOutIncrementOptional
public readonly scaleOutIncrement: number;
  • Type: number
  • Default: 1

The number of tasks that will scale out on scale out alarm status.


PopulateWithConfigProps

Initializer

import { PopulateWithConfigProps } from '@cdklabs/cdk-enterprise-iac'

const populateWithConfigProps: PopulateWithConfigProps = { ... }

Properties

NameTypeDescription
localRouteTableIdstringLocal route table ID, with routes only to local VPC.
privateRouteTableIdstringRoute table ID for a provided route table with routes to enterprise network.
subnetConfigSubnetConfig[]List of Subnet configs to provision to provision.
vpcIdstringID of the VPC provided that needs to be populated.

localRouteTableIdRequired
public readonly localRouteTableId: string;
  • Type: string

Local route table ID, with routes only to local VPC.


privateRouteTableIdRequired
public readonly privateRouteTableId: string;
  • Type: string

Route table ID for a provided route table with routes to enterprise network.

Both subnetType.PUBLIC and subnetType.PRIVATE_WITH_EGRESS will use this property


subnetConfigRequired
public readonly subnetConfig: SubnetConfig[];
  • Type: SubnetConfig[]

List of Subnet configs to provision to provision.


vpcIdRequired
public readonly vpcId: string;
  • Type: string

ID of the VPC provided that needs to be populated.


RemoveTagsProps

Initializer

import { RemoveTagsProps } from '@cdklabs/cdk-enterprise-iac'

const removeTagsProps: RemoveTagsProps = { ... }

Properties

NameTypeDescription
cloudformationResourcestringName of Cloudformation resource Type (e.g. 'AWS::Lambda::Function').
tagPropertyNamestringName of the tag property to remove from the resource.

cloudformationResourceRequired
public readonly cloudformationResource: string;
  • Type: string

Name of Cloudformation resource Type (e.g. 'AWS::Lambda::Function').


tagPropertyNameOptional
public readonly tagPropertyName: string;
  • Type: string
  • Default: Tags

Name of the tag property to remove from the resource.


ResourceExtractorProps

Initializer

import { ResourceExtractorProps } from '@cdklabs/cdk-enterprise-iac'

const resourceExtractorProps: ResourceExtractorProps = { ... }

Properties

NameTypeDescription
extractDestinationStackaws-cdk-lib.StackStack to move found extracted resources into.
resourceTypesToExtractstring[]List of resource types to extract, ex: AWS::IAM::Role.
stackArtifactsaws-cdk-lib.cx_api.CloudFormationStackArtifact[]Synthed stack artifacts from your CDK app.
additionalTransforms{ key: string : string}Additional resource transformations.
valueShareMethodResourceExtractorShareMethodThe sharing method to use when passing exported resources from the "Extracted Stack" into the original stack(s).

extractDestinationStackRequired
public readonly extractDestinationStack: Stack;
  • Type: aws-cdk-lib.Stack

Stack to move found extracted resources into.


resourceTypesToExtractRequired
public readonly resourceTypesToExtract: string[];
  • Type: string[]

List of resource types to extract, ex: AWS::IAM::Role.


stackArtifactsRequired
public readonly stackArtifacts: CloudFormationStackArtifact[];
  • Type: aws-cdk-lib.cx_api.CloudFormationStackArtifact[]

Synthed stack artifacts from your CDK app.


additionalTransformsOptional
public readonly additionalTransforms: {[ key: string ]: string};

Additional resource transformations.


valueShareMethodOptional
public readonly valueShareMethod: ResourceExtractorShareMethod;
  • Type: ResourceExtractorShareMethod

The sharing method to use when passing exported resources from the "Extracted Stack" into the original stack(s).


SetApiGatewayEndpointConfigurationProps

Initializer

import { SetApiGatewayEndpointConfigurationProps } from '@cdklabs/cdk-enterprise-iac'

const setApiGatewayEndpointConfigurationProps: SetApiGatewayEndpointConfigurationProps = { ... }

Properties

NameTypeDescription
endpointTypeaws-cdk-lib.aws_apigateway.EndpointTypeAPI Gateway endpoint type to override to.

endpointTypeOptional
public readonly endpointType: EndpointType;
  • Type: aws-cdk-lib.aws_apigateway.EndpointType
  • Default: EndpointType.REGIONAL

API Gateway endpoint type to override to.

Defaults to EndpointType.REGIONAL


SplitVpcEvenlyProps

Initializer

import { SplitVpcEvenlyProps } from '@cdklabs/cdk-enterprise-iac'

const splitVpcEvenlyProps: SplitVpcEvenlyProps = { ... }

Properties

NameTypeDescription
routeTableIdstringRoute Table ID that will be attached to each subnet created.
vpcCidrstringCIDR range of the VPC you're populating.
vpcIdstringID of the existing VPC you're trying to populate.
cidrBitsstringcidrBits argument for the Fn::Cidr Cloudformation intrinsic function.
numberOfAzsnumberNumber of AZs to evenly split into.
subnetTypeaws-cdk-lib.aws_ec2.SubnetTypeNo description.

routeTableIdRequired
public readonly routeTableId: string;
  • Type: string

Route Table ID that will be attached to each subnet created.


vpcCidrRequired
public readonly vpcCidr: string;
  • Type: string

CIDR range of the VPC you're populating.


vpcIdRequired
public readonly vpcId: string;
  • Type: string

ID of the existing VPC you're trying to populate.


cidrBitsOptional
public readonly cidrBits: string;
  • Type: string
  • Default: '6'

cidrBits argument for the Fn::Cidr Cloudformation intrinsic function.


numberOfAzsOptional <a name="numberOfAzs" id="@cdklabs/cdk-enterprise-iac.SplitVpcEven
0.0.442

2 days ago

0.0.441

3 days ago

0.0.440

5 days ago

0.0.439

6 days ago

0.0.438

7 days ago

0.0.437

8 days ago

0.0.436

9 days ago

0.0.435

10 days ago

0.0.434

10 days ago

0.0.433

12 days ago

0.0.432

13 days ago

0.0.431

14 days ago

0.0.430

15 days ago

0.0.429

16 days ago

0.0.428

17 days ago

0.0.427

19 days ago

0.0.425

21 days ago

0.0.426

20 days ago

0.0.424

22 days ago

0.0.423

26 days ago

0.0.422

27 days ago

0.0.421

28 days ago

0.0.420

29 days ago

0.0.419

30 days ago

0.0.418

1 month ago

0.0.417

1 month ago

0.0.416

1 month ago

0.0.415

1 month ago

0.0.414

1 month ago

0.0.413

1 month ago

0.0.412

1 month ago

0.0.411

1 month ago

0.0.410

1 month ago

0.0.409

1 month ago

0.0.408

2 months ago

0.0.407

2 months ago

0.0.406

2 months ago

0.0.405

2 months ago

0.0.404

2 months ago

0.0.403

2 months ago

0.0.402

2 months ago

0.0.401

2 months ago

0.0.400

2 months ago

0.0.399

2 months ago

0.0.398

2 months ago

0.0.397

2 months ago

0.0.396

2 months ago

0.0.395

2 months ago

0.0.394

2 months ago

0.0.393

2 months ago

0.0.392

2 months ago

0.0.391

2 months ago

0.0.390

2 months ago

0.0.389

2 months ago

0.0.388

2 months ago

0.0.384

3 months ago

0.0.383

3 months ago

0.0.387

2 months ago

0.0.386

3 months ago

0.0.385

3 months ago

0.0.382

3 months ago

0.0.381

3 months ago

0.0.380

3 months ago

0.0.379

3 months ago

0.0.378

3 months ago

0.0.377

3 months ago

0.0.376

3 months ago

0.0.375

3 months ago

0.0.374

3 months ago

0.0.373

3 months ago

0.0.372

3 months ago

0.0.371

3 months ago

0.0.370

3 months ago

0.0.369

3 months ago

0.0.368

3 months ago

0.0.367

3 months ago

0.0.366

3 months ago

0.0.365

3 months ago

0.0.364

3 months ago

0.0.363

3 months ago

0.0.362

3 months ago

0.0.361

3 months ago

0.0.360

4 months ago

0.0.359

4 months ago

0.0.358

4 months ago

0.0.357

4 months ago

0.0.356

4 months ago

0.0.355

4 months ago

0.0.354

4 months ago

0.0.353

4 months ago

0.0.352

4 months ago

0.0.351

4 months ago

0.0.350

4 months ago

0.0.349

4 months ago

0.0.348

4 months ago

0.0.347

4 months ago

0.0.346

4 months ago

0.0.345

4 months ago

0.0.344

4 months ago

0.0.343

4 months ago

0.0.342

5 months ago

0.0.341

5 months ago

0.0.340

5 months ago

0.0.339

5 months ago

0.0.337

5 months ago

0.0.338

5 months ago

0.0.336

5 months ago

0.0.335

5 months ago

0.0.334

5 months ago

0.0.333

5 months ago

0.0.332

5 months ago

0.0.331

5 months ago

0.0.330

5 months ago

0.0.329

5 months ago

0.0.326

5 months ago

0.0.325

5 months ago

0.0.324

5 months ago

0.0.323

5 months ago

0.0.328

5 months ago

0.0.327

5 months ago

0.0.315

10 months ago

0.0.314

10 months ago

0.0.313

10 months ago

0.0.312

10 months ago

0.0.319

6 months ago

0.0.318

6 months ago

0.0.317

6 months ago

0.0.316

10 months ago

0.0.311

10 months ago

0.0.310

11 months ago

0.0.322

6 months ago

0.0.321

6 months ago

0.0.320

6 months ago

0.0.309

11 months ago

0.0.304

11 months ago

0.0.303

11 months ago

0.0.302

11 months ago

0.0.301

11 months ago

0.0.308

11 months ago

0.0.307

11 months ago

0.0.306

11 months ago

0.0.305

11 months ago

0.0.300

11 months ago

0.0.289

11 months ago

0.0.288

11 months ago

0.0.287

11 months ago

0.0.286

11 months ago

0.0.296

11 months ago

0.0.295

11 months ago

0.0.294

11 months ago

0.0.293

11 months ago

0.0.299

11 months ago

0.0.298

11 months ago

0.0.297

11 months ago

0.0.292

11 months ago

0.0.291

11 months ago

0.0.290

11 months ago

0.0.279

12 months ago

0.0.274

12 months ago

0.0.273

12 months ago

0.0.272

12 months ago

0.0.271

12 months ago

0.0.278

12 months ago

0.0.277

12 months ago

0.0.276

12 months ago

0.0.275

12 months ago

0.0.270

12 months ago

0.0.285

11 months ago

0.0.284

11 months ago

0.0.283

11 months ago

0.0.282

11 months ago

0.0.281

11 months ago

0.0.280

12 months ago

0.0.259

1 year ago

0.0.258

1 year ago

0.0.257

1 year ago

0.0.252

1 year ago

0.0.251

1 year ago

0.0.256

1 year ago

0.0.255

1 year ago

0.0.254

1 year ago

0.0.253

1 year ago

0.0.269

12 months ago

0.0.268

12 months ago

0.0.263

12 months ago

0.0.262

12 months ago

0.0.261

1 year ago

0.0.260

1 year ago

0.0.267

12 months ago

0.0.266

12 months ago

0.0.265

12 months ago

0.0.264

12 months ago

0.0.238

1 year ago

0.0.237

1 year ago

0.0.236

1 year ago

0.0.235

1 year ago

0.0.239

1 year ago

0.0.230

1 year ago

0.0.234

1 year ago

0.0.233

1 year ago

0.0.232

1 year ago

0.0.231

1 year ago

0.0.249

1 year ago

0.0.248

1 year ago

0.0.247

1 year ago

0.0.246

1 year ago

0.0.241

1 year ago

0.0.240

1 year ago

0.0.245

1 year ago

0.0.244

1 year ago

0.0.243

1 year ago

0.0.242

1 year ago

0.0.250

1 year ago

0.0.205

1 year ago

0.0.204

1 year ago

0.0.203

1 year ago

0.0.202

1 year ago

0.0.209

1 year ago

0.0.208

1 year ago

0.0.207

1 year ago

0.0.206

1 year ago

0.0.201

1 year ago

0.0.200

1 year ago

0.0.216

1 year ago

0.0.215

1 year ago

0.0.214

1 year ago

0.0.213

1 year ago

0.0.219

1 year ago

0.0.218

1 year ago

0.0.217

1 year ago

0.0.212

1 year ago

0.0.211

1 year ago

0.0.210

1 year ago

0.0.227

1 year ago

0.0.226

1 year ago

0.0.225

1 year ago

0.0.224

1 year ago

0.0.229

1 year ago

0.0.228

1 year ago

0.0.223

1 year ago

0.0.222

1 year ago

0.0.221

1 year ago

0.0.220

1 year ago

0.0.197

1 year ago

0.0.196

1 year ago

0.0.195

1 year ago

0.0.194

1 year ago

0.0.199

1 year ago

0.0.198

1 year ago

0.0.193

1 year ago

0.0.192

1 year ago

0.0.191

1 year ago

0.0.189

1 year ago

0.0.188

1 year ago

0.0.187

1 year ago

0.0.190

1 year ago

0.0.186

1 year ago

0.0.185

1 year ago

0.0.184

1 year ago

0.0.183

1 year ago

0.0.175

1 year ago

0.0.174

1 year ago

0.0.173

1 year ago

0.0.179

1 year ago

0.0.178

1 year ago

0.0.177

1 year ago

0.0.176

1 year ago

0.0.182

1 year ago

0.0.181

1 year ago

0.0.180

1 year ago

0.0.169

1 year ago

0.0.168

1 year ago

0.0.167

1 year ago

0.0.172

1 year ago

0.0.171

1 year ago

0.0.170

1 year ago

0.0.159

1 year ago

0.0.158

1 year ago

0.0.153

1 year ago

0.0.152

1 year ago

0.0.151

1 year ago

0.0.150

1 year ago

0.0.157

1 year ago

0.0.156

1 year ago

0.0.155

1 year ago

0.0.154

1 year ago

0.0.164

1 year ago

0.0.163

1 year ago

0.0.162

1 year ago

0.0.161

1 year ago

0.0.166

1 year ago

0.0.165

1 year ago

0.0.160

1 year ago

0.0.128

1 year ago

0.0.127

1 year ago

0.0.126

1 year ago

0.0.129

1 year ago

0.0.139

1 year ago

0.0.138

1 year ago

0.0.137

1 year ago

0.0.136

1 year ago

0.0.131

1 year ago

0.0.130

1 year ago

0.0.135

1 year ago

0.0.134

1 year ago

0.0.133

1 year ago

0.0.132

1 year ago

0.0.149

1 year ago

0.0.148

1 year ago

0.0.147

1 year ago

0.0.142

1 year ago

0.0.141

1 year ago

0.0.140

1 year ago

0.0.146

1 year ago

0.0.145

1 year ago

0.0.144

1 year ago

0.0.143

1 year ago

0.0.84

1 year ago

0.0.85

1 year ago

0.0.86

1 year ago

0.0.87

1 year ago

0.0.88

1 year ago

0.0.89

1 year ago

0.0.80

1 year ago

0.0.81

1 year ago

0.0.82

1 year ago

0.0.83

1 year ago

0.0.73

1 year ago

0.0.74

1 year ago

0.0.75

1 year ago

0.0.76

1 year ago

0.0.77

1 year ago

0.0.78

1 year ago

0.0.79

1 year ago

0.0.70

1 year ago

0.0.71

1 year ago

0.0.72

1 year ago

0.0.62

2 years ago

0.0.63

2 years ago

0.0.64

2 years ago

0.0.65

2 years ago

0.0.66

2 years ago

0.0.67

2 years ago

0.0.68

2 years ago

0.0.69

2 years ago

0.0.60

2 years ago

0.0.61

2 years ago

0.0.59

2 years ago

0.0.106

1 year ago

0.0.51

2 years ago

0.0.105

1 year ago

0.0.52

2 years ago

0.0.104

1 year ago

0.0.53

2 years ago

0.0.103

1 year ago

0.0.54

2 years ago

0.0.55

2 years ago

0.0.109

1 year ago

0.0.56

2 years ago

0.0.108

1 year ago

0.0.57

2 years ago

0.0.107

1 year ago

0.0.58

2 years ago

0.0.102

1 year ago

0.0.101

1 year ago

0.0.100

1 year ago

0.0.50

2 years ago

0.0.48

2 years ago

0.0.49

2 years ago

0.0.117

1 year ago

0.0.116

1 year ago

0.0.115

1 year ago

0.0.42

2 years ago

0.0.114

1 year ago

0.0.43

2 years ago

0.0.44

2 years ago

0.0.45

2 years ago

0.0.119

1 year ago

0.0.46

2 years ago

0.0.118

1 year ago

0.0.47

2 years ago

0.0.113

1 year ago

0.0.112

1 year ago

0.0.111

1 year ago

0.0.110

1 year ago

0.0.125

1 year ago

0.0.120

1 year ago

0.0.124

1 year ago

0.0.123

1 year ago

0.0.122

1 year ago

0.0.121

1 year ago

0.0.95

1 year ago

0.0.96

1 year ago

0.0.97

1 year ago

0.0.98

1 year ago

0.0.99

1 year ago

0.0.90

1 year ago

0.0.91

1 year ago

0.0.92

1 year ago

0.0.93

1 year ago

0.0.94

1 year ago

0.0.40

2 years ago

0.0.41

2 years ago

0.0.20

2 years ago

0.0.21

2 years ago

0.0.22

2 years ago

0.0.23

2 years ago

0.0.24

2 years ago

0.0.25

2 years ago

0.0.37

2 years ago

0.0.38

2 years ago

0.0.39

2 years ago

0.0.30

2 years ago

0.0.31

2 years ago

0.0.32

2 years ago

0.0.33

2 years ago

0.0.34

2 years ago

0.0.35

2 years ago

0.0.36

2 years ago

0.0.26

2 years ago

0.0.27

2 years ago

0.0.28

2 years ago

0.0.29

2 years ago

0.0.19

2 years ago

0.0.18

2 years ago

0.0.17

2 years ago

0.0.16

2 years ago

0.0.15

2 years ago

0.0.14

2 years ago

0.0.13

2 years ago

0.0.12

2 years ago

0.0.11

2 years ago

0.0.10

2 years ago

0.0.9

2 years ago

0.0.8

2 years ago

0.0.7

2 years ago

0.0.6

2 years ago

0.0.5

2 years ago

0.0.4

2 years ago

0.0.3

2 years ago

0.0.2

2 years ago

0.0.1

2 years ago