or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cloudformation-init.mdec2-instances.mdflow-logs.mdindex.mdlaunch-templates.mdmachine-images.mdnetwork-acl.mdsecurity-groups.mdstorage-volumes.mdsubnets-networking.mduser-data.mdvpc-endpoints.mdvpc-management.mdvpn-connectivity.md
tile.json

cloudformation-init.mddocs/

CloudFormation Init

CloudFormation Init in AWS CDK EC2 provides advanced instance initialization capabilities using AWS CloudFormation helper scripts for complex configuration management.

CloudFormationInit Class

The main class for creating CloudFormation Init configurations:

class CloudFormationInit {
  static fromElements(...elements: InitElement[]): CloudFormationInit;
  static fromConfig(config: InitConfig): CloudFormationInit;
  static fromConfigSets(props: ConfigSetProps): CloudFormationInit;
  
  addConfig(configName: string, config: InitConfig): void;
  addConfigSet(configSetName: string, configNames: string[]): void;
  attach(attachedResource: CfnResource, options: AttachInitOptions): void;
}

class InitConfig {
  constructor(elements: InitElement[]);
  add(...elements: InitElement[]): void;
}

interface ConfigSetProps {
  readonly configSets: Record<string, string[]>;
  readonly configs: Record<string, InitConfig>;
}

Init Elements

Base classes and implementations for different initialization elements:

abstract class InitElement {
  // Factory methods for creating different types of elements
}

class InitPackage extends InitElement {
  static yum(packageName: string): InitPackage;
  static rpm(packageName: string, options?: InitPackageOptions): InitPackage;
  static msi(packageName: string, options?: InitPackageOptions): InitPackage;
  static python(packageName: string, version?: string): InitPackage;
  static rubyGem(packageName: string, version?: string): InitPackage;
}

class InitFile extends InitElement {
  static fromString(fileName: string, content: string, options?: InitFileOptions): InitFile;
  static fromFileInline(fileName: string, sourceFileName: string, options?: InitFileOptions): InitFile;
  static fromAsset(fileName: string, asset: Asset, options?: InitFileOptions): InitFile;
  static fromExistingAsset(fileName: string, asset: Asset, options?: InitFileOptions): InitFile;
  static fromS3Object(fileName: string, bucket: s3.IBucket, key: string, options?: InitFileOptions): InitFile;
  static fromUrl(fileName: string, url: string, options?: InitFileOptions): InitFile;
}

class InitService extends InitElement {
  static enable(serviceName: string, options?: InitServiceOptions): InitService;
  static disable(serviceName: string, options?: InitServiceOptions): InitService;
  static systemdConfigFile(serviceName: string, options: InitServiceOptions): InitService;
}

class InitCommand extends InitElement {
  static shellCommand(command: string, options?: InitCommandOptions): InitCommand;
  static argvCommand(argv: string[], options?: InitCommandOptions): InitCommand;
}

class InitUser extends InitElement {
  constructor(userName: string, options?: InitUserOptions);
}

class InitGroup extends InitElement {
  constructor(groupName: string, options?: InitGroupOptions);
}

class InitSource extends InitElement {
  static fromS3(targetDirectory: string, bucket: s3.IBucket, key: string): InitSource;
  static fromUrl(targetDirectory: string, url: string): InitSource;
  static fromAsset(targetDirectory: string, asset: Asset): InitSource;
  static fromExistingAsset(targetDirectory: string, asset: Asset): InitSource;
  static fromGitHub(targetDirectory: string, owner: string, repo: string, options?: InitSourceOptions): InitSource;
}

Configuration Options

Interfaces for configuring different init elements:

interface InitFileOptions {
  readonly mode?: string;
  readonly owner?: string;
  readonly group?: string;
  readonly base64Encoded?: boolean;
  readonly serviceRestartHandles?: InitServiceRestartHandle[];
}

interface InitServiceOptions {
  readonly enabled?: boolean;
  readonly ensureRunning?: boolean;
  readonly files?: string[];
  readonly packages?: InitPackage[];
  readonly sources?: InitSource[];
  readonly commands?: InitCommand[];
  readonly serviceRestartHandle?: InitServiceRestartHandle;
}

interface InitCommandOptions {
  readonly key?: string;
  readonly cwd?: string;
  readonly env?: Record<string, string>;
  readonly ignoreErrors?: boolean;
  readonly testCmd?: string;
  readonly waitAfterCompletion?: InitCommandWaitDuration;
  readonly serviceRestartHandles?: InitServiceRestartHandle[];
}

interface InitPackageOptions {
  readonly version?: string[];
  readonly serviceRestartHandles?: InitServiceRestartHandle[];
}

interface InitUserOptions {
  readonly userId?: number;
  readonly groups?: string[];
  readonly homeDir?: string;
}

interface InitGroupOptions {
  readonly groupId?: number;
}

interface InitSourceOptions {
  readonly serviceRestartHandles?: InitServiceRestartHandle[];
}

Service Management

Classes for managing service restarts and dependencies:

class InitServiceRestartHandle {
  constructor();
}

enum InitCommandWaitDuration {
  NONE = 'none',
  FOREVER = 'forever'
}

interface AttachInitOptions {
  readonly platform?: InitPlatform;
  readonly userData?: UserData;
  readonly ignoreFailures?: boolean;
  readonly includeUrl?: boolean;
  readonly includeRole?: boolean;
  readonly printLog?: boolean;
  readonly configSets?: string[];
}

interface ApplyCloudFormationInitOptions {
  readonly timeout?: Duration;
  readonly includeUrl?: boolean;
  readonly includeRole?: boolean;
  readonly printLog?: boolean;
  readonly ignoreFailures?: boolean;
  readonly configSets?: string[];
}

enum InitPlatform {
  LINUX = 'linux',
  WINDOWS = 'windows'
}

Usage Examples

Basic CloudFormation Init

import * as ec2 from "@aws-cdk/aws-ec2";
import * as cdk from "@aws-cdk/core";

const vpc = new ec2.Vpc(this, "MyVpc");

// Create basic init configuration
const init = ec2.CloudFormationInit.fromElements(
  ec2.InitPackage.yum("httpd"),
  ec2.InitFile.fromString("/var/www/html/index.html", "<h1>Hello World</h1>"),
  ec2.InitService.enable("httpd", {
    enabled: true,
    ensureRunning: true
  })
);

const instance = new ec2.Instance(this, "WebServer", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  init,
  initOptions: {
    timeout: cdk.Duration.minutes(10),
    includeUrl: true,
    includeRole: true,
    printLog: true
  }
});

Multi-Config Setup

const webConfig = new ec2.InitConfig([
  ec2.InitPackage.yum("httpd"),
  ec2.InitPackage.yum("php"),
  ec2.InitService.enable("httpd")
]);

const appConfig = new ec2.InitConfig([
  ec2.InitFile.fromString("/var/www/html/app.php", "<?php phpinfo(); ?>"),
  ec2.InitCommand.shellCommand("chown -R apache:apache /var/www/html")
]);

const init = ec2.CloudFormationInit.fromConfigSets({
  configSets: {
    "install": ["web", "app"],
    "update": ["app"]
  },
  configs: {
    "web": webConfig,
    "app": appConfig
  }
});

const instance = new ec2.Instance(this, "ConfiguredInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.SMALL),
  machineImage: ec2.MachineImage.latestAmazonLinux(),
  init,
  initOptions: {
    configSets: ["install"],
    timeout: cdk.Duration.minutes(15)
  }
});

Complex Application Setup

import * as s3 from "@aws-cdk/aws-s3";
import * as s3deploy from "@aws-cdk/aws-s3-deployment";

const appBucket = new s3.Bucket(this, "AppBucket");

// Deploy application code to S3
new s3deploy.BucketDeployment(this, "DeployApp", {
  sources: [s3deploy.Source.asset("./app")],
  destinationBucket: appBucket
});

const serviceRestartHandle = new ec2.InitServiceRestartHandle();

const init = ec2.CloudFormationInit.fromElements(
  // Install packages
  ec2.InitPackage.yum("httpd"),
  ec2.InitPackage.yum("php"),
  ec2.InitPackage.yum("mysql"),
  
  // Create users and groups
  ec2.InitUser.new("appuser", {
    homeDir: "/home/appuser",
    groups: ["apache"]
  }),
  
  // Download application from S3
  ec2.InitSource.fromS3("/var/www/html", appBucket, "app.zip"),
  
  // Create configuration files
  ec2.InitFile.fromString(
    "/etc/httpd/conf.d/app.conf",
    `<VirtualHost *:80>
      DocumentRoot /var/www/html
      ServerName myapp.com
    </VirtualHost>`,
    {
      mode: "000644",
      owner: "root",
      group: "root",
      serviceRestartHandles: [serviceRestartHandle]
    }
  ),
  
  ec2.InitFile.fromString(
    "/var/www/html/config.php",
    `<?php
      define('DB_HOST', 'localhost');
      define('DB_USER', 'appuser');
      define('DB_PASS', 'password');
    ?>`,
    {
      mode: "000600",
      owner: "apache",
      group: "apache"
    }
  ),
  
  // Run setup commands
  ec2.InitCommand.shellCommand("chown -R apache:apache /var/www/html", {
    cwd: "/var/www"
  }),
  
  ec2.InitCommand.shellCommand("chmod +x /var/www/html/setup.sh"),
  ec2.InitCommand.shellCommand("/var/www/html/setup.sh", {
    env: {
      "APP_ENV": "production"
    },
    testCmd: "test -f /var/www/html/setup.complete"
  }),
  
  // Configure services
  ec2.InitService.enable("httpd", {
    enabled: true,
    ensureRunning: true,
    serviceRestartHandle: serviceRestartHandle
  }),
  
  ec2.InitService.enable("mysqld", {
    enabled: true,
    ensureRunning: true
  })
);

Windows Instance Init

const windowsInit = ec2.CloudFormationInit.fromElements(
  // Install IIS
  ec2.InitCommand.shellCommand("powershell.exe -Command Install-WindowsFeature -name Web-Server -IncludeManagementTools"),
  
  // Create application directory
  ec2.InitCommand.shellCommand("mkdir C:\\MyApp"),
  
  // Download application
  ec2.InitSource.fromS3("C:\\MyApp", appBucket, "windows-app.zip"),
  
  // Create website configuration
  ec2.InitFile.fromString(
    "C:\\inetpub\\wwwroot\\web.config",
    `<?xml version="1.0" encoding="UTF-8"?>
    <configuration>
      <appSettings>
        <add key="Environment" value="Production" />
      </appSettings>
    </configuration>`
  ),
  
  // Configure IIS site
  ec2.InitCommand.shellCommand("powershell.exe -Command New-Website -Name MyApp -Port 80 -PhysicalPath C:\\MyApp")
);

const windowsInstance = new ec2.Instance(this, "WindowsInstance", {
  vpc,
  instanceType: ec2.InstanceType.of(ec2.InstanceClass.M5, ec2.InstanceSize.LARGE),
  machineImage: ec2.MachineImage.latestWindows(
    ec2.WindowsVersion.WINDOWS_SERVER_2022_ENGLISH_FULL_BASE
  ),
  init: windowsInit,
  initOptions: {
    platform: ec2.InitPlatform.WINDOWS,
    timeout: cdk.Duration.minutes(20)
  }
});

Database Server Setup

const dbInit = ec2.CloudFormationInit.fromElements(
  // Install MySQL
  ec2.InitPackage.yum("mysql-server"),
  
  // Create database directories
  ec2.InitCommand.shellCommand("mkdir -p /var/lib/mysql/data"),
  ec2.InitCommand.shellCommand("chown -R mysql:mysql /var/lib/mysql"),
  
  // Create MySQL configuration
  ec2.InitFile.fromString(
    "/etc/my.cnf",
    `[mysqld]
datadir=/var/lib/mysql/data
socket=/var/lib/mysql/mysql.sock
user=mysql
server-id=1
log-bin=mysql-bin
bind-address=0.0.0.0

[mysql_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid`,
    {
      mode: "000644",
      owner: "root",
      group: "root"
    }
  ),
  
  // Initialize database
  ec2.InitCommand.shellCommand("mysql_install_db --user=mysql --datadir=/var/lib/mysql/data"),
  
  // Start MySQL service
  ec2.InitService.enable("mysqld", {
    enabled: true,
    ensureRunning: true
  }),
  
  // Set up database and users
  ec2.InitCommand.shellCommand(`mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'MySecurePassword123!';"`, {
    ignoreErrors: true
  }),
  ec2.InitCommand.shellCommand(`mysql -u root -pMySecurePassword123! -e "CREATE DATABASE myapp;"`)
);

Service Dependencies and Restart Handling

const webServiceHandle = new ec2.InitServiceRestartHandle();
const dbServiceHandle = new ec2.InitServiceRestartHandle();

const dependentInit = ec2.CloudFormationInit.fromElements(
  // Install packages
  ec2.InitPackage.yum("httpd"),
  ec2.InitPackage.yum("mysql-server"),
  
  // Configuration that requires web service restart
  ec2.InitFile.fromString(
    "/etc/httpd/conf.d/custom.conf",
    "ServerTokens Prod\nServerSignature Off",
    {
      serviceRestartHandles: [webServiceHandle]
    }
  ),
  
  // Configuration that requires database restart
  ec2.InitFile.fromString(
    "/etc/my.cnf",
    "[mysqld]\nmax_connections=200\ninnodb_buffer_pool_size=512M",
    {
      serviceRestartHandles: [dbServiceHandle]
    }
  ),
  
  // Services that will be restarted when their config changes
  ec2.InitService.enable("httpd", {
    enabled: true,
    ensureRunning: true,
    serviceRestartHandle: webServiceHandle
  }),
  
  ec2.InitService.enable("mysqld", {
    enabled: true,
    ensureRunning: true,
    serviceRestartHandle: dbServiceHandle
  })
);

Best Practices

  1. Error Handling: Use ignoreFailures: false in production to catch initialization errors
  2. Timeouts: Set appropriate timeouts for complex initialization processes
  3. Service Dependencies: Use restart handles to manage service dependencies
  4. Security: Avoid putting secrets in init files - use AWS Secrets Manager instead
  5. Logging: Enable printLog for troubleshooting during development
  6. Idempotency: Ensure init commands can be run multiple times safely
  7. Testing: Test init configurations thoroughly before production deployment
  8. Modular Configs: Break complex setups into multiple configs for maintainability
  9. Platform Specificity: Use appropriate commands for Linux vs Windows
  10. Resource Management: Clean up temporary files and resources after initialization