Skip to content

Instantly share code, notes, and snippets.

@cagdas1
Last active July 21, 2019 21:49
Show Gist options
  • Save cagdas1/306fea80a44501c9e75de67f61ce2129 to your computer and use it in GitHub Desktop.
Save cagdas1/306fea80a44501c9e75de67f61ce2129 to your computer and use it in GitHub Desktop.
Cloudformation Drift Detection
//env variable for aws profile
process.env.AWS_PROFILE = "your_profile";
const axios = require("axios").default;
const AWS = require("aws-sdk");
const regions = ["us-west-1", "us-west-2"]
const SLACK_URL = "https://hooks.slack.com/services/CHANGE";
async function getAllStacks(cloudformation){
let lastKey = null;
let arr = [];
const params = {};
do{
if(lastKey){
params.NextToken = lastKey;
const result = await cloudformation.describeStacks(params).promise();
lastKey = result.NextToken;
arr = [...arr,...result.Stacks];
}else{
const result = await cloudformation.describeStacks(params).promise();
lastKey = result.NextToken;
arr = [...arr,...result.Stacks];
}
}while(lastKey);
return arr;
}
async function detectDrifts(){
for(const region of regions){
const cloudformation = new AWS.CloudFormation({region});
const stacks = await getAllStacks(cloudformation);
const driftDetections = []
for(const stack of stacks){
if(!isStackInTransition(stack.StackStatus)){
const res = await cloudformation.detectStackDrift({StackName: stack.StackName}).promise()
driftDetections.push({driftDetectionId: res.StackDriftDetectionId, stackName: stack.StackName})
}
}
for(let i=0; i < 5; i++) {
if(driftDetections.length < 1) {
break;
}
//wait 10 seconds
console.log("round", i + 1);
await sleep(10000);
for(const driftIndex in driftDetections){
const driftDetection = driftDetections[driftIndex];
const driftStatus = await cloudformation.describeStackDriftDetectionStatus({StackDriftDetectionId: driftDetection.driftDetectionId}).promise()
if(driftStatus.DetectionStatus !== "DETECTION_IN_PROGRESS" && driftStatus.StackDriftStatus === "DRIFTED"){
const resourceDrifts = await cloudformation.describeStackResourceDrifts({StackName: driftDetection.stackName, StackResourceDriftStatusFilters: ["IN_SYNC", "MODIFIED", "DELETED"]}).promise();
const url = `https://${region}.console.aws.amazon.com/cloudformation/home?region=${region}#/stack/detail?stackId=${driftStatus.StackId}`;
const message = `Cloudformation Drift detected for the stack: ${url}`;
await sendSlackMessage({message, data: resourceDrifts, url});
console.log(`Slack message sent for stack: ${driftDetection.stackName}`)
driftDetections.splice(driftIndex, 1);
}
}
}
}
}
function sendSlackMessage(params) {
const payload = {
attachments: [
{
"pretext": params.message,
"title": "Drift Detected",
"title_link": params.url,
"text": JSON.stringify(params.data),
"color": "#800000"
}
]
}
return axios.request({
url: SLACK_URL,
method: "POST",
data: payload
})
}
function isStackInTransition(stack) {
const transitions = ["CREATE_IN_PROGRESS", "CREATE_FAILED","ROLLBACK_FAILED","DELETE_FAILED","UPDATE_ROLLBACK_FAILED","UPDATE_IN_PROGRESS","REVIEW_IN_PROGRESS","DELETE_IN_PROGRESS", "ROLLBACK_COMPLETE"]
if(transitions.find(x=>x===stack)) {
return true;
}else {
false;
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
detectDrifts().then().catch(err=>console.error(err))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment