From 6e0c0161b3d5510379519b2323777421421bd664 Mon Sep 17 00:00:00 2001 From: Will Dady Date: Thu, 25 Aug 2022 14:55:29 +1000 Subject: [PATCH] feat: added CloudformationPolicyCollector --- package.json | 1 + src/cloudformation/index.ts | 56 +++++++++++++++++++++++++++++++++++++ src/index.ts | 2 ++ yarn.lock | 53 +++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 src/cloudformation/index.ts diff --git a/package.json b/package.json index 733d20b..8e7ccee 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "dependencies": { "@aws-sdk/client-api-gateway": "^3.58.0", "@aws-sdk/client-backup": "^3.58.0", + "@aws-sdk/client-cloudformation": "^3.58.0", "@aws-sdk/client-cloudwatch-logs": "^3.58.0", "@aws-sdk/client-codeartifact": "^3.58.0", "@aws-sdk/client-codebuild": "^3.58.0", diff --git a/src/cloudformation/index.ts b/src/cloudformation/index.ts new file mode 100644 index 0000000..0fe200e --- /dev/null +++ b/src/cloudformation/index.ts @@ -0,0 +1,56 @@ +import { + CloudFormationClient, + CloudFormationClientConfig, + GetStackPolicyCommand, + paginateListStacks, +} from '@aws-sdk/client-cloudformation'; +import { BasePolicyCollector, ServicePoliciesResult } from '../core'; + +export class CloudformationPolicyCollector extends BasePolicyCollector { + private client: CloudFormationClient; + + constructor(clientConfig?: CloudFormationClientConfig) { + super({ serviceName: 'cloudformation' }); + this.client = new CloudFormationClient(clientConfig || {}); + } + + private async listStacks() { + const paginator = paginateListStacks({ client: this.client }, {}); + const stacks = []; + for await (const page of paginator) { + stacks.push(...(page.StackSummaries || [])); + } + return stacks; + } + + private async getStackPolicy(stackName: string) { + const response = await this.client.send( + new GetStackPolicyCommand({ + StackName: stackName, + }), + ); + return response.StackPolicyBody; + } + + public async run(): Promise { + const result: ServicePoliciesResult = { + serviceName: this.serviceName, + resources: [], + }; + try { + const stacks = await this.listStacks(); + for (const s of stacks) { + const stackPolicy = await this.getStackPolicy(s.StackName!); + if (!stackPolicy) continue; + result.resources.push({ + type: 'Cloudformation::StackPolicy', // Note there is no-such CF resource type + id: s.StackName!, + policy: stackPolicy, + }); + } + } catch (err) { + result.error = JSON.stringify(err); + } + return result; + } +} diff --git a/src/index.ts b/src/index.ts index 8873f04..f27aefd 100755 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import { ApiGatewayPolicyCollector } from './apigateway'; import { BackupPolicyCollector } from './backup'; +import { CloudformationPolicyCollector } from './cloudformation'; import { CloudWatchLogsPolicyCollector } from './logs'; import { CodeArtifactPolicyCollector } from './codeartifact'; import { CodeBuildPolicyCollector } from './codebuild'; @@ -28,6 +29,7 @@ export const collect = async (config?: { region?: string }) => { const collectors = [ new ApiGatewayPolicyCollector(config), new BackupPolicyCollector(config), + new CloudformationPolicyCollector(config), new CloudWatchLogsPolicyCollector(config), new CodeArtifactPolicyCollector(config), new CodeBuildPolicyCollector(config), diff --git a/yarn.lock b/yarn.lock index 754758e..19c3873 100644 --- a/yarn.lock +++ b/yarn.lock @@ -230,6 +230,50 @@ tslib "^2.3.1" uuid "^8.3.2" +"@aws-sdk/client-cloudformation@^3.58.0": + version "3.154.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-cloudformation/-/client-cloudformation-3.154.0.tgz#cd8ed0ec0956214c788e75d7946794cea0ea8659" + integrity sha512-Dc6bF0wqbkZUUIp6qsTKXZUsGLUg8oclMVOQrQBLdfQZGn7fyI2oEOBup+ELf+5cdmuExO5lyO1WtKpqI2Iyhg== + dependencies: + "@aws-crypto/sha256-browser" "2.0.0" + "@aws-crypto/sha256-js" "2.0.0" + "@aws-sdk/client-sts" "3.154.0" + "@aws-sdk/config-resolver" "3.130.0" + "@aws-sdk/credential-provider-node" "3.154.0" + "@aws-sdk/fetch-http-handler" "3.131.0" + "@aws-sdk/hash-node" "3.127.0" + "@aws-sdk/invalid-dependency" "3.127.0" + "@aws-sdk/middleware-content-length" "3.127.0" + "@aws-sdk/middleware-host-header" "3.127.0" + "@aws-sdk/middleware-logger" "3.127.0" + "@aws-sdk/middleware-recursion-detection" "3.127.0" + "@aws-sdk/middleware-retry" "3.127.0" + "@aws-sdk/middleware-serde" "3.127.0" + "@aws-sdk/middleware-signing" "3.130.0" + "@aws-sdk/middleware-stack" "3.127.0" + "@aws-sdk/middleware-user-agent" "3.127.0" + "@aws-sdk/node-config-provider" "3.127.0" + "@aws-sdk/node-http-handler" "3.127.0" + "@aws-sdk/protocol-http" "3.127.0" + "@aws-sdk/smithy-client" "3.142.0" + "@aws-sdk/types" "3.127.0" + "@aws-sdk/url-parser" "3.127.0" + "@aws-sdk/util-base64-browser" "3.109.0" + "@aws-sdk/util-base64-node" "3.55.0" + "@aws-sdk/util-body-length-browser" "3.154.0" + "@aws-sdk/util-body-length-node" "3.55.0" + "@aws-sdk/util-defaults-mode-browser" "3.142.0" + "@aws-sdk/util-defaults-mode-node" "3.142.0" + "@aws-sdk/util-user-agent-browser" "3.127.0" + "@aws-sdk/util-user-agent-node" "3.127.0" + "@aws-sdk/util-utf8-browser" "3.109.0" + "@aws-sdk/util-utf8-node" "3.109.0" + "@aws-sdk/util-waiter" "3.127.0" + entities "2.2.0" + fast-xml-parser "3.19.0" + tslib "^2.3.1" + uuid "^8.3.2" + "@aws-sdk/client-cloudwatch-logs@^3.58.0": version "3.58.0" resolved "https://registry.yarnpkg.com/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.58.0.tgz#086184178761915b82c37f178da4776cedecfd93" @@ -2355,6 +2399,15 @@ "@aws-sdk/util-buffer-from" "3.55.0" tslib "^2.3.1" +"@aws-sdk/util-waiter@3.127.0": + version "3.127.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-waiter/-/util-waiter-3.127.0.tgz#3485ebb614cc417fee397daf61ba4ca3aa5bbedb" + integrity sha512-E5qrRpBJS8dmClqSDW1pWVMKzCG/mxabG6jVUtlW/WLHnl/znxGaOQc6tnnwKik0nEq/4DpT9fEfPUz9JiLrkw== + dependencies: + "@aws-sdk/abort-controller" "3.127.0" + "@aws-sdk/types" "3.127.0" + tslib "^2.3.1" + "@aws-sdk/util-waiter@3.55.0": version "3.55.0" resolved "https://registry.yarnpkg.com/@aws-sdk/util-waiter/-/util-waiter-3.55.0.tgz#0e48a8ce98931f99cfbcad750222fd1f0b237fda"