diff --git a/src/guardian/index.js b/src/guardian/index.js index 944e659c..4e99a558 100644 --- a/src/guardian/index.js +++ b/src/guardian/index.js @@ -7,10 +7,12 @@ import NoMaximumTimeout from "./rules/best_practices/no-max-timeout"; import NoMaximumMemory from "./rules/best_practices/no-max-memory"; import NoIdenticalCode from "./rules/best_practices/no-identical-code"; import NoSharedRoles from "./rules/best_practices/no-shared-roles"; +import S3ActivateIntelligentTiering from "./rules/best_practices/s3-activate-intelligent-tiering"; import { getAWSCredentials, getStackResources, getLambdaFunctions, + getAllS3Buckets, } from "../services"; import ServerlessConfigParser from "../services/severlessConfigParser/serverlessConfigParser"; @@ -43,12 +45,14 @@ class GuardianCI { NoMaximumMemory, NoIdenticalCode, NoSharedRoles, + S3ActivateIntelligentTiering, ]; this.failingChecks = []; this.resourceIDs = []; this.allFunctions = []; this.stackFunctions = []; + this.allS3Buckets = []; if (program.slsDevToolsConfig) { this.config = program.slsDevToolsConfig.guardian; @@ -78,12 +82,19 @@ class GuardianCI { return lambdaFunctionResources.map((lambda) => lambda.PhysicalResourceId); } + async getAllS3Buckets() { + const S3 = new this.AWS.S3(); + const allBuckets = getAllS3Buckets(S3); + return allBuckets; + } + async initResources() { this.resourceIDs = await this.getStackFunctionResouceIDs(); this.allFunctions = await this.getAllLambdaFunctions(); this.stackFunctions = this.allFunctions.filter((lambda) => this.resourceIDs.includes(lambda.FunctionName) ); + this.allS3Buckets = await this.getAllS3Buckets(); } ignoreCheck(check) { @@ -144,7 +155,8 @@ class GuardianCI { this.AWS, this.stackName, this.stackFunctions, - this.SLS + this.SLS, + this.allS3Buckets ); if (!this.ignoreCheck(check)) { const filteredStack = this.ignoreArns(check, this.stackFunctions); diff --git a/src/guardian/rules/best_practices/s3-activate-intelligent-tiering/index.js b/src/guardian/rules/best_practices/s3-activate-intelligent-tiering/index.js new file mode 100644 index 00000000..01b2375b --- /dev/null +++ b/src/guardian/rules/best_practices/s3-activate-intelligent-tiering/index.js @@ -0,0 +1,51 @@ +class S3IntelligentTiering { + constructor(AWS, stackName, stackFunctions, SLS, stackS3Buckets) { + this.AWS = AWS; + this.stackName = stackName; + this.stackFunctions = stackFunctions; + this.SLS = SLS; + this.stackS3Buckets = stackS3Buckets; + this.name = "s3-intl-tiering"; + this.failureMessage = + "The following S3 buckets have no Intelligent Tiering configurations defined"; + this.S3 = new this.AWS.S3(); + this.failingResources = []; + } + + async getNumberOfIntelligentTieringConfigurations(bucketName) { + const configurations = await this.S3.listBucketIntelligentTieringConfigurations( + { + Bucket: bucketName, + } + ).promise(); + return configurations.IntelligentTieringConfigurationList.length; + } + + async run() { + try { + const bucketsWithCount = await Promise.all( + this.stackS3Buckets.map(async (bucket) => { + const numberOfConfigurations = await this.getNumberOfIntelligentTieringConfigurations( + bucket.Name + ); + return { + bucketName: bucket.Name, + numberOfConfigurations, + }; + }) + ); + this.failingResources = bucketsWithCount.reduce( + (acc, current) => + current.numberOfConfigurations === 0 ? [...acc, current] : acc, + [] + ); + this.result = this.failingResources.length === 0; + } catch (e) { + console.error(e); + this.result = false; + } + return this.result; + } +} + +export default S3IntelligentTiering; diff --git a/src/services/awsS3.js b/src/services/awsS3.js new file mode 100644 index 00000000..f0b9c9e0 --- /dev/null +++ b/src/services/awsS3.js @@ -0,0 +1,9 @@ +async function getAllS3Buckets(S3) { + const response = await S3.listBuckets({}).promise(); + const allBuckets = response.Buckets; + return allBuckets; +} + +module.exports = { + getAllS3Buckets, +}; diff --git a/src/services/index.js b/src/services/index.js index 42d99e79..9533b642 100644 --- a/src/services/index.js +++ b/src/services/index.js @@ -1,3 +1,4 @@ export { getAWSCredentials } from "./awsCredentials"; export { getStackResources } from "./stackResources"; export { getLambdaFunctions } from "./awsLambda"; +export { getAllS3Buckets } from "./awsS3";