From d71298db6d7cd32d278e170c4eee5d7892f02ecb Mon Sep 17 00:00:00 2001 From: Daniel Schroeder Date: Wed, 20 Apr 2022 18:44:20 +0200 Subject: [PATCH] Removes cdk-iam-floyd as ddependecy (#31) * removes cdk-iam-floyd from dependencies * limit jsii version to last compatible * update versiopn for next release * normalize imports * combine test steps: deploy & destroy * ignore tsconfig.tsbuildinfo --- .github/workflows/test.yml | 8 +-- .gitignore | 1 + README.md | 46 +++++++------- VERSION | 2 +- lib/index.ts | 125 +++++++++++++++++++++++-------------- package.json | 6 +- test/lib/test-stack.ts | 33 +++++----- test/package.json | 1 - 8 files changed, 120 insertions(+), 102 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f370c27..54b04b2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,13 +31,7 @@ jobs: chmod 777 $GITHUB_WORKSPACE/lambda --recursive - name: Deploy - run: cd test && make deploy - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - - name: Destroy - run: cd test && make DESTROY + run: cd test && make deploy DESTROY env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.gitignore b/.gitignore index deadeef..d5fc74c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ lambda/* **/*.d.ts **/cdk.out **/package-lock.json +tsconfig.tsbuildinfo diff --git a/README.md b/README.md index bb41ae6..2883b3b 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ For TypeScript/NodeJS, add these to your `dependencies` in `package.json`. For P - cdk-ssm-document - aws-cdk-lib (^2.0.0) -- cdk-iam-floyd (^0.300.0) - constructs (^10.0.0) ## CDK compatibility @@ -140,41 +139,39 @@ export class TestStack extends cdk.Stack { ### Creating a distributor package ```typescript -import * as cdk from 'aws-cdk-lib'; -import { Construct } from 'constructs'; +import { aws_iam, aws_s3, aws_s3_deployment, Stack, StackProps } from 'aws-cdk-lib'; import { Document } from 'cdk-ssm-document'; -import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment'; -import * as s3 from 'aws-cdk-lib/aws-s3'; -import * as statement from 'cdk-iam-floyd'; +import { Construct } from 'constructs'; import fs = require('fs'); import path = require('path'); - -export class TestStack extends cdk.Stack { - constructor(scope: cdk.Construct, id: string, props: cdk.StackProps) { +export class TestStack extends Stack { + constructor(scope: Construct, id: string, props: StackProps) { super(scope, id, props); - const bucketName = `${cdk.Stack.of(this).account}-cdk-ssm-document-storage`; - const bucket = new s3.Bucket(this, 'DistributorPackages', { + const bucketName = `${Stack.of(this).account}-cdk-ssm-document-storage`; + const bucket = new aws_s3.Bucket(this, 'DistributorPackages', { bucketName: bucketName, }); - const packageDeploy = new s3deploy.BucketDeployment(this, 'distribution-packages', { - sources: [s3deploy.Source.asset('../location/to/distributor/packages')], - destinationBucket: bucket - }); + const packageDeploy = new aws_s3_deployment.BucketDeployment( + this, + 'distribution-packages', + { + sources: [aws_s3_deployment.Source.asset('../location/to/distributor/packages')], + destinationBucket: bucket, + } + ); - file = path.join( + const file = path.join( __dirname, '../location/to/distributor/packages/v1/manifest.json' ); - const docE = new Document(this, `SSM-Distribution-Package`, { + const doc = new Document(this, `SSM-Distribution-Package`, { documentType: 'Package', name: 'Test-Distribution-Package', content: fs.readFileSync(file).toString(), versionName: '1.0-Custom-Name', - attachments: [ - { key: "SourceUrl", values: [`s3://${bucketName}/v1`] } - ] + attachments: [{ key: 'SourceUrl', values: [`s3://${bucketName}/v1`] }], }); /** @@ -193,14 +190,15 @@ export class TestStack extends cdk.Stack { * ``` */ doc.lambda.role?.addToPrincipalPolicy( - new statement.S3() // - .allow() - .toGetObject() - .onObject(bucket.bucketName, '*') + new aws_iam.PolicyStatement({ + actions: ['s3:GetObject'], + resources: [`${bucket.arnForObjects('*')}`], + }) ); doc.node.addDependency(packageDeploy); } } + ``` ## Deploying many documents in a single stack diff --git a/VERSION b/VERSION index fd2a018..94ff29c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.1.0 +3.1.1 diff --git a/lib/index.ts b/lib/index.ts index 1e27981..d2b8789 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,7 +1,16 @@ -import cdk = require('aws-cdk-lib'); -import iam = require('aws-cdk-lib/aws-iam'); -import lambda = require('aws-cdk-lib/aws-lambda'); -import * as statement from 'cdk-iam-floyd'; +import { + Annotations, + aws_iam, + aws_lambda, + CustomResource, + Duration, + ITaggable, + Lazy, + Stack, + StackProps, + TagManager, + TagType, +} from 'aws-cdk-lib'; import { Construct } from 'constructs'; import yaml = require('js-yaml'); import path = require('path'); @@ -143,7 +152,7 @@ export interface DocumentContent { /** * Definition of the SSM document */ -export interface DocumentProps extends cdk.StackProps { +export interface DocumentProps extends StackProps { /** * Defines if the default version should be updated to the latest version on document updates * @@ -191,7 +200,7 @@ export interface DocumentProps extends cdk.StackProps { /** * An SSM document */ -export class Document extends Construct implements cdk.ITaggable { +export class Document extends Construct implements ITaggable { /** * Name of the document */ @@ -200,12 +209,12 @@ export class Document extends Construct implements cdk.ITaggable { /** * Resource tags */ - public readonly tags: cdk.TagManager; + public readonly tags: TagManager; /** * The lambda function that is created */ - public readonly lambda: lambda.IFunction; + public readonly lambda: aws_lambda.IFunction; /** * Defines a new SSM document @@ -213,15 +222,15 @@ export class Document extends Construct implements cdk.ITaggable { constructor(scope: Construct, id: string, props: DocumentProps) { super(scope, id); - this.tags = new cdk.TagManager(cdk.TagType.MAP, 'Custom::SSM-Document'); + this.tags = new TagManager(TagType.MAP, 'Custom::SSM-Document'); this.tags.setTag(createdByTag, ID); - const stack = cdk.Stack.of(this).stackName; + const stack = Stack.of(this).stackName; this.lambda = this.ensureLambda(); const name = this.fixDocumentName(props.name); if (name.length < 3 || name.length > 128) { - cdk.Annotations.of(this).addError( + Annotations.of(this).addError( `SSM Document name ${name} is invalid. The name must be between 3 and 128 characters.` ); return; @@ -233,7 +242,7 @@ export class Document extends Construct implements cdk.ITaggable { content = yaml.safeLoad(content) as DocumentContent; } - const document = new cdk.CustomResource(this, `SSM-Document-${name}`, { + const document = new CustomResource(this, `SSM-Document-${name}`, { serviceToken: this.lambda.functionArn, resourceType: resourceType, properties: { @@ -245,7 +254,7 @@ export class Document extends Construct implements cdk.ITaggable { attachments: props.attachments, versionName: props.versionName, StackName: stack, - tags: cdk.Lazy.any({ + tags: Lazy.any({ produce: () => this.tags.renderTags(), }), }, @@ -255,59 +264,79 @@ export class Document extends Construct implements cdk.ITaggable { this.name = document.getAttString('Name'); } - private ensureLambda(): lambda.Function { - const stack = cdk.Stack.of(this); + private ensureLambda(): aws_lambda.Function { + const stack = Stack.of(this); const constructName = 'SSM-Document-Manager-Lambda'; const existing = stack.node.tryFindChild(constructName); if (existing) { - return existing as lambda.Function; + return existing as aws_lambda.Function; } - const policy = new iam.ManagedPolicy(stack, 'SSM-Document-Manager-Policy', { - managedPolicyName: `${stack.stackName}-${cleanID}`, - description: `Used by Lambda ${cleanID}, which is a custom CFN resource, managing SSM documents`, - statements: [ - new statement.Ssm().allow().toListDocuments().toListTagsForResource(), - new statement.Ssm() - .allow() - .toCreateDocument() - .toAddTagsToResource() - .ifAwsRequestTag(createdByTag, ID), - new statement.Ssm() - .allow() - .toDeleteDocument() - .toDescribeDocument() - .toGetDocument() - .toListDocumentVersions() - .toModifyDocumentPermission() - .toUpdateDocument() - .toUpdateDocumentDefaultVersion() - .toAddTagsToResource() - .toRemoveTagsFromResource() - .ifResourceTag(createdByTag, ID), - ], - }); - - const role = new iam.Role(stack, 'SSM-Document-Manager-Role', { + const policy = new aws_iam.ManagedPolicy( + stack, + 'SSM-Document-Manager-Policy', + { + managedPolicyName: `${stack.stackName}-${cleanID}`, + description: `Used by Lambda ${cleanID}, which is a custom CFN resource, managing SSM documents`, + statements: [ + new aws_iam.PolicyStatement({ + actions: ['ssm:ListDocuments', 'ssm:ListTagsForResource'], + resources: ['*'], + }), + new aws_iam.PolicyStatement({ + actions: ['ssm:AddTagsToResource', 'ssm:CreateDocument'], + resources: ['*'], + conditions: { + StringLike: { + 'aws:RequestTag/CreatedByCfnCustomResource': ID, + }, + }, + }), + new aws_iam.PolicyStatement({ + actions: [ + 'ssm:AddTagsToResource', + 'ssm:DeleteDocument', + 'ssm:DescribeDocument', + 'ssm:GetDocument', + 'ssm:ListDocumentVersions', + 'ssm:ModifyDocumentPermission', + 'ssm:RemoveTagsFromResource', + 'ssm:UpdateDocument', + 'ssm:UpdateDocumentDefaultVersion', + ], + resources: ['*'], + conditions: { + StringLike: { + 'ssm:ResourceTag/CreatedByCfnCustomResource': ID, + }, + }, + }), + ], + } + ); + + const role = new aws_iam.Role(stack, 'SSM-Document-Manager-Role', { roleName: `${stack.stackName}-${cleanID}`, description: `Used by Lambda ${cleanID}, which is a custom CFN resource, managing SSM documents`, - assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), + assumedBy: new aws_iam.ServicePrincipal('lambda.amazonaws.com'), managedPolicies: [ policy, - iam.ManagedPolicy.fromAwsManagedPolicyName( + aws_iam.ManagedPolicy.fromAwsManagedPolicyName( 'service-role/AWSLambdaBasicExecutionRole' ), ], }); - const fn = new lambda.Function(stack, constructName, { + const fn = new aws_lambda.Function(stack, constructName, { functionName: `${stack.stackName}-${cleanID}`, role: role, description: 'Custom CFN resource: Manage SSM Documents', - runtime: lambda.Runtime.NODEJS_14_X, + runtime: aws_lambda.Runtime.NODEJS_14_X, handler: 'index.handler', - code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/code.zip')), - timeout: cdk.Duration.minutes(lambdaTimeout), + code: aws_lambda.Code.fromAsset( + path.join(__dirname, '../lambda/code.zip') + ), + timeout: Duration.minutes(lambdaTimeout), }); return fn; diff --git a/package.json b/package.json index 8f59a6a..fc8c15d 100644 --- a/package.json +++ b/package.json @@ -60,11 +60,10 @@ "aws-lambda": "^1.0.7", "aws-sdk": "^2.1069.0", "constructs": "^10.0.0", - "jsii": "^1.52.1", - "jsii-pacmak": "^1.52.1", + "jsii": "1.55.1", + "jsii-pacmak": "1.55.1", "ts-node": "^10.4.0", "typescript": "^4.5.5", - "cdk-iam-floyd": "^0.300.0", "aws-cloudformation-custom-resource": "^2.0.1" }, "dependencies": { @@ -72,7 +71,6 @@ }, "peerDependencies": { "aws-cdk-lib": "^2.0.0", - "cdk-iam-floyd": "^0.300.0", "constructs": "^10.0.0" }, "bundleDependencies": [ diff --git a/test/lib/test-stack.ts b/test/lib/test-stack.ts index 392d026..f1ccf8b 100644 --- a/test/lib/test-stack.ts +++ b/test/lib/test-stack.ts @@ -1,15 +1,12 @@ -import * as cdk from 'aws-cdk-lib'; -import * as s3 from 'aws-cdk-lib/aws-s3'; -import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment'; -import * as statement from 'cdk-iam-floyd'; +import { aws_iam, aws_s3, aws_s3_deployment, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import fs = require('fs'); import path = require('path'); import { Document } from '../../lib'; -export class TestStack extends cdk.Stack { - constructor(scope: Construct, id: string, props?: cdk.StackProps) { +export class TestStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); let file = path.join( __dirname, @@ -68,21 +65,23 @@ export class TestStack extends cdk.Stack { * * Requires a bucket to hold install/update/uninstall scripts. */ - const bucketName = `${cdk.Stack.of(this).account}-cdk-ssm-document-storage`; - const bucket = new s3.Bucket(this, 'DistributorPackages', { + const bucketName = `${Stack.of(this).account}-cdk-ssm-document-storage`; + const bucket = new aws_s3.Bucket(this, 'DistributorPackages', { bucketName: bucketName, - blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, + blockPublicAccess: aws_s3.BlockPublicAccess.BLOCK_ALL, enforceSSL: true, - encryption: s3.BucketEncryption.KMS_MANAGED, + encryption: aws_s3.BucketEncryption.KMS_MANAGED, // Makes for easy destroy and rerun of this stack over and over. - removalPolicy: cdk.RemovalPolicy.DESTROY, + removalPolicy: RemovalPolicy.DESTROY, autoDeleteObjects: true, }); - const packageDeploy = new s3deploy.BucketDeployment( + const packageDeploy = new aws_s3_deployment.BucketDeployment( this, 'distribution-packages', { - sources: [s3deploy.Source.asset('../test/documents/distributor')], + sources: [ + aws_s3_deployment.Source.asset('../test/documents/distributor'), + ], destinationBucket: bucket, } ); @@ -117,10 +116,10 @@ export class TestStack extends cdk.Stack { * `Active`. */ docE.lambda.role?.addToPrincipalPolicy( - new statement.S3() // - .allow() - .toGetObject() - .onObject(bucket.bucketName, '*') + new aws_iam.PolicyStatement({ + actions: ['s3:GetObject'], + resources: [`${bucket.arnForObjects('*')}`], + }) ); docE.node.addDependency(docD); diff --git a/test/package.json b/test/package.json index 1e25e60..60d9d70 100644 --- a/test/package.json +++ b/test/package.json @@ -15,7 +15,6 @@ }, "dependencies": { "aws-cdk-lib": "2.x", - "cdk-iam-floyd": "0.313.0", "cdk-ssm-document": "file:.." } }