or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

change-sets.mdclient-configuration.mddrift-detection.mdgenerated-templates.mdindex.mdpagination-waiters.mdresource-type-registry.mdstack-information.mdstack-management.mdstack-refactoring.mdstack-sets.mdtemplate-operations.md
tile.json

drift-detection.mddocs/

Drift Detection

Detect configuration drift between deployed resources and CloudFormation templates.

Capabilities

Detect Stack Drift

Initiates drift detection for an entire stack to identify configuration changes.

/**
 * Initiates drift detection for all resources in a stack
 * Compares actual resource configuration with template definitions
 */
class DetectStackDriftCommand {
  constructor(input: DetectStackDriftCommandInput);
}

interface DetectStackDriftCommandInput {
  /** Name or ARN of the stack to check for drift */
  StackName: string;
  
  /** Specific logical resource IDs to check (optional) */
  LogicalResourceIds?: string[];
}

interface DetectStackDriftCommandOutput {
  /** Unique identifier for the drift detection operation */
  StackDriftDetectionId: string;
}

Usage Examples:

import { 
  CloudFormationClient, 
  DetectStackDriftCommand,
  DescribeStackDriftDetectionStatusCommand
} from "@aws-sdk/client-cloudformation";

const client = new CloudFormationClient({ region: "us-east-1" });

// Detect drift for entire stack
const detectCommand = new DetectStackDriftCommand({
  StackName: "my-production-stack"
});

const detection = await client.send(detectCommand);
console.log("Drift detection ID:", detection.StackDriftDetectionId);

// Detect drift for specific resources only
const specificDetectCommand = new DetectStackDriftCommand({
  StackName: "my-stack",
  LogicalResourceIds: ["MyDatabase", "MyBucket", "MySecurityGroup"]
});

const specificDetection = await client.send(specificDetectCommand);

Detect Stack Resource Drift

Detects drift for a specific resource within a stack.

/**
 * Detects configuration drift for a specific resource
 * Returns immediate drift status for the resource
 */
class DetectStackResourceDriftCommand {
  constructor(input: DetectStackResourceDriftCommandInput);
}

interface DetectStackResourceDriftCommandInput {
  /** Name or ARN of the stack containing the resource */
  StackName: string;
  
  /** Logical ID of the resource to check */
  LogicalResourceId: string;
}

interface DetectStackResourceDriftCommandOutput {
  /** Drift information for the resource */
  StackResourceDrift: StackResourceDrift;
}

interface StackResourceDrift {
  /** Stack ID */
  StackId: string;
  
  /** Logical resource ID */
  LogicalResourceId: string;
  
  /** Physical resource ID */
  PhysicalResourceId?: string;
  
  /** Resource type */
  ResourceType: string;
  
  /** Expected properties from template */
  ExpectedProperties?: string;
  
  /** Actual properties from AWS */
  ActualProperties?: string;
  
  /** Property differences */
  PropertyDifferences?: PropertyDifference[];
  
  /** Drift status */
  StackResourceDriftStatus: StackResourceDriftStatus;
  
  /** Timestamp of drift check */
  Timestamp: Date;
  
  /** Module information */
  ModuleInfo?: ModuleInfo;
}

interface PropertyDifference {
  /** Property path */
  PropertyPath: string;
  
  /** Expected value */
  ExpectedValue: string;
  
  /** Actual value */
  ActualValue: string;
  
  /** Difference type */
  DifferenceType: DifferenceType;
}

interface ModuleInfo {
  /** Type hierarchy */
  TypeHierarchy?: string;
  
  /** Logical ID hierarchy */
  LogicalIdHierarchy?: string;
}

type StackResourceDriftStatus = 
  | "IN_SYNC"
  | "MODIFIED"
  | "DELETED"
  | "NOT_CHECKED";

type DifferenceType = 
  | "ADD"
  | "REMOVE"
  | "NOT_EQUAL";

Describe Stack Drift Detection Status

Retrieves the status and results of a drift detection operation.

/**
 * Retrieves drift detection status and summary results
 * Shows overall drift status and resource counts
 */
class DescribeStackDriftDetectionStatusCommand {
  constructor(input: DescribeStackDriftDetectionStatusCommandInput);
}

interface DescribeStackDriftDetectionStatusCommandInput {
  /** Drift detection ID from DetectStackDrift operation */
  StackDriftDetectionId: string;
}

interface DescribeStackDriftDetectionStatusCommandOutput {
  /** Stack ID */
  StackId: string;
  
  /** Drift detection ID */
  StackDriftDetectionId: string;
  
  /** Overall drift status for the stack */
  StackDriftStatus?: StackDriftStatus;
  
  /** Detection operation status */
  DetectionStatus: StackDriftDetectionStatus;
  
  /** Status reason */
  DetectionStatusReason?: string;
  
  /** Number of resources checked */
  DriftedStackResourceCount?: number;
  
  /** Detection start timestamp */
  Timestamp: Date;
}

type StackDriftStatus = 
  | "DRIFTED"
  | "IN_SYNC"
  | "UNKNOWN"
  | "NOT_CHECKED";

type StackDriftDetectionStatus = 
  | "DETECTION_IN_PROGRESS"
  | "DETECTION_FAILED"
  | "DETECTION_COMPLETE";

Usage Examples:

// Monitor drift detection progress
async function checkDriftStatus(detectionId: string) {
  const statusCommand = new DescribeStackDriftDetectionStatusCommand({
    StackDriftDetectionId: detectionId
  });
  
  const status = await client.send(statusCommand);
  
  if (status.DetectionStatus === "DETECTION_COMPLETE") {
    console.log("Drift detection completed");
    console.log("Stack drift status:", status.StackDriftStatus);
    console.log("Drifted resources:", status.DriftedStackResourceCount);
    return status;
  } else if (status.DetectionStatus === "DETECTION_FAILED") {
    console.error("Drift detection failed:", status.DetectionStatusReason);
    throw new Error("Drift detection failed");
  } else {
    console.log("Drift detection in progress...");
    // Poll again after delay
    await new Promise(resolve => setTimeout(resolve, 5000));
    return checkDriftStatus(detectionId);
  }
}

// Check drift for specific resource
const resourceDriftCommand = new DetectStackResourceDriftCommand({
  StackName: "my-stack",
  LogicalResourceId: "MyS3Bucket"
});

const resourceDrift = await client.send(resourceDriftCommand);
console.log("Resource drift status:", resourceDrift.StackResourceDrift.StackResourceDriftStatus);

if (resourceDrift.StackResourceDrift.PropertyDifferences) {
  console.log("Property differences:");
  resourceDrift.StackResourceDrift.PropertyDifferences.forEach(diff => {
    console.log(`${diff.PropertyPath}: expected ${diff.ExpectedValue}, actual ${diff.ActualValue}`);
  });
}

Describe Stack Resource Drifts

Retrieves drift information for resources in a stack with pagination support.

/**
 * Retrieves detailed drift information for stack resources
 * Supports filtering and pagination for large stacks
 */
class DescribeStackResourceDriftsCommand {
  constructor(input: DescribeStackResourceDriftsCommandInput);
}

interface DescribeStackResourceDriftsCommandInput {
  /** Name or ARN of the stack */
  StackName: string;
  
  /** Filter by drift status */
  StackResourceDriftStatusFilters?: StackResourceDriftStatus[];
  
  /** Token for pagination */
  NextToken?: string;
  
  /** Maximum number of results */
  MaxResults?: number;
}

interface DescribeStackResourceDriftsCommandOutput {
  /** Resource drift details */
  StackResourceDrifts: StackResourceDrift[];
  
  /** Pagination token */
  NextToken?: string;
}

Detect Stack Set Drift

Initiates drift detection for a stack set to check all instances.

/**
 * Initiates drift detection for all stack instances in a stack set
 * Checks configuration drift across multiple accounts and regions
 */
class DetectStackSetDriftCommand {
  constructor(input: DetectStackSetDriftCommandInput);
}

interface DetectStackSetDriftCommandInput {
  /** Name of the stack set */
  StackSetName: string;
  
  /** Operation preferences for drift detection */
  OperationPreferences?: StackSetOperationPreferences;
  
  /** Operation ID for idempotency */
  OperationId?: string;
  
  /** Call context */
  CallAs?: CallAs;
}

interface DetectStackSetDriftCommandOutput {
  /** Operation ID for the drift detection */
  OperationId?: string;
}

interface StackSetOperationPreferences {
  /** Region concurrency type */
  RegionConcurrencyType?: RegionConcurrencyType;
  
  /** Region order */
  RegionOrder?: string[];
  
  /** Failure tolerance count */
  FailureToleranceCount?: number;
  
  /** Failure tolerance percentage */
  FailureTolerancePercentage?: number;
  
  /** Maximum concurrent count */
  MaxConcurrentCount?: number;
  
  /** Maximum concurrent percentage */
  MaxConcurrentPercentage?: number;
  
  /** Concurrency mode */
  ConcurrencyMode?: ConcurrencyMode;
}

type RegionConcurrencyType = 
  | "SEQUENTIAL"
  | "PARALLEL";

type ConcurrencyMode = 
  | "STRICT_FAILURE_TOLERANCE"
  | "SOFT_FAILURE_TOLERANCE";

type CallAs = 
  | "SELF"
  | "DELEGATED_ADMIN";

List Stack Instance Resource Drifts

Lists resource drifts for stack instances in a stack set.

/**
 * Lists resource drift information for stack set instances
 * Provides drift details across multiple accounts and regions
 */
class ListStackInstanceResourceDriftsCommand {
  constructor(input: ListStackInstanceResourceDriftsCommandInput);
}

interface ListStackInstanceResourceDriftsCommandInput {
  /** Stack set name */
  StackSetName: string;
  
  /** Stack instance account */
  StackInstanceAccount: string;
  
  /** Stack instance region */
  StackInstanceRegion: string;
  
  /** Operation ID that performed drift detection */
  OperationId: string;
  
  /** Token for pagination */
  NextToken?: string;
  
  /** Maximum results */
  MaxResults?: number;
  
  /** Filter by drift status */
  StackInstanceResourceDriftStatuses?: StackResourceDriftStatus[];
  
  /** Call context */
  CallAs?: CallAs;
}

interface ListStackInstanceResourceDriftsCommandOutput {
  /** Resource drift summaries */
  Summaries?: StackInstanceResourceDriftSummary[];
  
  /** Pagination token */
  NextToken?: string;
}

interface StackInstanceResourceDriftSummary {
  /** Stack ID */
  StackId?: string;
  
  /** Logical resource ID */
  LogicalResourceId?: string;
  
  /** Physical resource ID */
  PhysicalResourceId?: string;
  
  /** Physical resource ID context */
  PhysicalResourceIdContext?: PhysicalResourceIdContextKeyValuePair[];
  
  /** Resource type */
  ResourceType?: string;
  
  /** Property differences */
  PropertyDifferences?: PropertyDifference[];
  
  /** Drift status */
  StackResourceDriftStatus?: StackResourceDriftStatus;
  
  /** Timestamp */
  Timestamp?: Date;
}

interface PhysicalResourceIdContextKeyValuePair {
  /** Key */
  Key?: string;
  
  /** Value */
  Value?: string;
}

Usage Examples:

// Detect drift for stack set
const stackSetDriftCommand = new DetectStackSetDriftCommand({
  StackSetName: "my-cross-account-stack-set",
  OperationPreferences: {
    RegionConcurrencyType: "PARALLEL",
    MaxConcurrentPercentage: 25,
    FailureTolerancePercentage: 10
  }
});

const stackSetOperation = await client.send(stackSetDriftCommand);
console.log("Stack set drift operation:", stackSetOperation.OperationId);

// List resource drifts for specific stack instance
const instanceDriftsCommand = new ListStackInstanceResourceDriftsCommand({
  StackSetName: "my-cross-account-stack-set",
  StackInstanceAccount: "123456789012",
  StackInstanceRegion: "us-east-1",
  OperationId: stackSetOperation.OperationId!
});

const instanceDrifts = await client.send(instanceDriftsCommand);
console.log("Instance resource drifts:", instanceDrifts.Summaries);

// Get detailed drift information for all resources in a stack
const allDriftsCommand = new DescribeStackResourceDriftsCommand({
  StackName: "my-stack",
  StackResourceDriftStatusFilters: ["MODIFIED", "DELETED"]
});

const allDrifts = await client.send(allDriftsCommand);
allDrifts.StackResourceDrifts.forEach(drift => {
  console.log(`Resource ${drift.LogicalResourceId}: ${drift.StackResourceDriftStatus}`);
  if (drift.PropertyDifferences) {
    drift.PropertyDifferences.forEach(diff => {
      console.log(`  ${diff.PropertyPath}: ${diff.DifferenceType}`);
    });
  }
});

Drift Analysis and Remediation

Analyzing Drift Results

async function analyzeDrift(stackName: string) {
  // Start drift detection
  const detectCommand = new DetectStackDriftCommand({ StackName: stackName });
  const detection = await client.send(detectCommand);
  
  // Wait for completion
  const status = await checkDriftStatus(detection.StackDriftDetectionId);
  
  if (status.StackDriftStatus === "DRIFTED") {
    // Get detailed drift information
    const driftsCommand = new DescribeStackResourceDriftsCommand({
      StackName: stackName,
      StackResourceDriftStatusFilters: ["MODIFIED", "DELETED"]
    });
    
    const drifts = await client.send(driftsCommand);
    
    // Analyze each drifted resource
    for (const drift of drifts.StackResourceDrifts) {
      console.log(`\nResource: ${drift.LogicalResourceId} (${drift.ResourceType})`);
      console.log(`Status: ${drift.StackResourceDriftStatus}`);
      
      if (drift.PropertyDifferences) {
        console.log("Property changes:");
        drift.PropertyDifferences.forEach(diff => {
          console.log(`  ${diff.PropertyPath}:`);
          console.log(`    Expected: ${diff.ExpectedValue}`);
          console.log(`    Actual: ${diff.ActualValue}`);
          console.log(`    Change: ${diff.DifferenceType}`);
        });
      }
    }
    
    return drifts.StackResourceDrifts;
  }
  
  return [];
}

Automated Drift Monitoring

class DriftMonitor {
  private client: CloudFormationClient;
  private monitoredStacks: Set<string> = new Set();
  
  constructor(client: CloudFormationClient) {
    this.client = client;
  }
  
  async monitorStack(stackName: string, intervalMinutes: number = 60) {
    if (this.monitoredStacks.has(stackName)) {
      return;
    }
    
    this.monitoredStacks.add(stackName);
    
    const monitor = async () => {
      try {
        console.log(`Checking drift for stack: ${stackName}`);
        
        const detection = await this.client.send(
          new DetectStackDriftCommand({ StackName: stackName })
        );
        
        const status = await checkDriftStatus(detection.StackDriftDetectionId);
        
        if (status.StackDriftStatus === "DRIFTED") {
          await this.handleDriftDetected(stackName, status);
        } else {
          console.log(`Stack ${stackName} is in sync`);
        }
      } catch (error) {
        console.error(`Error monitoring stack ${stackName}:`, error);
      }
      
      // Schedule next check
      setTimeout(monitor, intervalMinutes * 60 * 1000);
    };
    
    // Start monitoring
    monitor();
  }
  
  private async handleDriftDetected(
    stackName: string, 
    status: DescribeStackDriftDetectionStatusCommandOutput
  ) {
    console.log(`ALERT: Drift detected in stack ${stackName}`);
    console.log(`Drifted resources: ${status.DriftedStackResourceCount}`);
    
    // Get detailed drift information
    const drifts = await this.client.send(
      new DescribeStackResourceDriftsCommand({
        StackName: stackName,
        StackResourceDriftStatusFilters: ["MODIFIED", "DELETED"]
      })
    );
    
    // Send notifications or trigger remediation
    await this.sendDriftNotification(stackName, drifts.StackResourceDrifts);
  }
  
  private async sendDriftNotification(
    stackName: string, 
    drifts: StackResourceDrift[]
  ) {
    // Implementation would send notifications via SNS, email, etc.
    console.log(`Sending drift notification for stack: ${stackName}`);
    drifts.forEach(drift => {
      console.log(`- ${drift.LogicalResourceId}: ${drift.StackResourceDriftStatus}`);
    });
  }
}

// Usage
const monitor = new DriftMonitor(client);
await monitor.monitorStack("production-infrastructure", 30); // Check every 30 minutes

Supporting Types

interface StackResourceDrift {
  StackId: string;
  LogicalResourceId: string;
  PhysicalResourceId?: string;
  ResourceType: string;
  ExpectedProperties?: string;
  ActualProperties?: string;
  PropertyDifferences?: PropertyDifference[];
  StackResourceDriftStatus: StackResourceDriftStatus;
  Timestamp: Date;
  ModuleInfo?: ModuleInfo;
}

interface PropertyDifference {
  PropertyPath: string;
  ExpectedValue: string;
  ActualValue: string;
  DifferenceType: DifferenceType;
}

type StackResourceDriftStatus = 
  | "IN_SYNC"
  | "MODIFIED"
  | "DELETED"
  | "NOT_CHECKED";

type StackDriftStatus = 
  | "DRIFTED"
  | "IN_SYNC"
  | "UNKNOWN"
  | "NOT_CHECKED";

type DifferenceType = 
  | "ADD"
  | "REMOVE"
  | "NOT_EQUAL";

Best Practices

Drift Detection Strategy

  • Implement regular drift detection schedules for critical stacks
  • Use selective resource checking for large stacks to improve performance
  • Monitor drift detection operations and handle failures appropriately
  • Establish thresholds for acceptable vs. critical drift

Remediation Approaches

  • Template Update: Update the CloudFormation template to match actual state
  • Resource Correction: Manually correct drifted resources to match template
  • Stack Recreation: Delete and recreate the stack if drift is extensive
  • Rollback: Use stack rollback capabilities for recent changes

Monitoring and Alerting

  • Set up automated drift detection for production environments
  • Configure alerts for drift detection completion and failures
  • Implement dashboards showing drift status across environments
  • Track drift patterns to identify common configuration changes

Performance Optimization

  • Use resource-specific drift detection for targeted checks
  • Implement caching for frequently checked stacks
  • Consider the impact of drift detection on AWS API limits
  • Batch drift detection operations during maintenance windows

Compliance and Governance

  • Document approved vs. unapproved configuration changes
  • Establish processes for handling detected drift
  • Implement approval workflows for drift remediation
  • Maintain audit trails of drift detection and resolution activities