AWS CloudFormation Package Installation Failure: Why apt-get Packages Like Tomcat/Git Aren’t Installed on EC2 Launch


2 views

When your CloudFormation template defines package installations through AWS::CloudFormation::Init metadata but the packages don't actually get installed on the EC2 instance, you're likely missing critical bootstrapping components. Here's a complete technical breakdown.

The packages section in your metadata only defines what to install - you still need to trigger the installation process during instance launch. Add this UserData section to your instance definition:

"UserData": {
  "Fn::Base64": {
    "Fn::Join": [
      "",
      [
        "#!/bin/bash\n",
        "apt-get update -y\n",
        "apt-get install -y awscli\n",
        "/usr/local/bin/aws s3 cp s3://aws-codedeploy-us-east-1/latest/install . --region us-east-1\n",
        "chmod +x ./install\n",
        "./install auto\n",
        "/opt/aws/bin/cfn-init -v ",
        "         --stack ", { "Ref": "AWS::StackName" },
        "         --resource Tomcat ",
        "         --region ", { "Ref": "AWS::Region" }, "\n",
        "/opt/aws/bin/cfn-signal -e $? ",
        "         --stack ", { "Ref": "AWS::StackName" },
        "         --resource Tomcat ",
        "         --region ", { "Ref": "AWS::Region" }, "\n"
      ]
    ]
  }
}

Here's a corrected version that includes all necessary components for package installation:

{
  "Resources": {
    "TomcatInstance": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "ImageId": "ami-0abcdef1234567890",
        "InstanceType": "t2.micro",
        "UserData": {
          "Fn::Base64": {
            "Fn::Join": [
              "",
              [
                "#!/bin/bash\n",
                "apt-get update -y\n",
                "apt-get install -y python-setuptools\n",
                "mkdir -p /opt/aws/bin\n",
                "easy_install --script-dir /opt/aws/bin https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n",
                "/opt/aws/bin/cfn-init -v --stack ", { "Ref": "AWS::StackName" },
                " --resource TomcatInstance --region ", { "Ref": "AWS::Region" }, "\n",
                "/opt/aws/bin/cfn-signal -e $? --stack ", { "Ref": "AWS::StackName" },
                " --resource TomcatInstance --region ", { "Ref": "AWS::Region" }, "\n"
              ]
            ]
          }
        },
        "Metadata": {
          "AWS::CloudFormation::Init": {
            "config": {
              "packages": {
                "apt": {
                  "tomcat8": [],
                  "git": []
                }
              },
              "services": {
                "sysvinit": {
                  "tomcat8": {
                    "enabled": "true",
                    "ensureRunning": "true"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

After deployment, check these logs to troubleshoot:

# View cfn-init execution logs
cat /var/log/cfn-init.log

# Check cloud-init output
cat /var/log/cloud-init-output.log

# Verify package installation
dpkg -l tomcat8 git
  • Using outdated AMIs that don't include cloud-init
  • Missing IAM permissions for the instance to access CloudFormation metadata
  • Not waiting for package installation to complete before running dependent configurations
  • Using incorrect package names (e.g., tomcat6 vs tomcat8)

When working with AWS CloudFormation's cfn-init process, many developers encounter situations where packages specified in the Metadata section fail to install during instance launch. This commonly occurs with:

  • APT packages (Ubuntu/Debian)
  • YUM packages (Amazon Linux/RHEL)
  • Custom installation scripts

Your template shows the package declaration but lacks critical elements for actual execution. Here's what's missing:

\"Resources\": {
    \"TomcatInstance\": {
        \"Type\": \"AWS::EC2::Instance\",
        \"Metadata\": {
            \"AWS::CloudFormation::Init\": {
                \"config\": {
                    \"packages\": {
                        \"apt\": {
                            \"tomcat8\": [],
                            \"git\": []
                        }
                    }
                }
            }
        },
        \"Properties\": {
            \"UserData\": {
                \"Fn::Base64\": {
                    \"Fn::Join\": [\"\", [
                        \"#!/bin/bash\n\",
                        \"apt-get update -y\n\",
                        \"/opt/aws/bin/cfn-init -v \",
                        \"         --stack \", {\"Ref\": \"AWS::StackName\"}, \" \",
                        \"         --resource TomcatInstance \",
                        \"         --region \", {\"Ref\": \"AWS::Region\"}, \"\n\",
                        \"# Signal completion\n\",
                        \"/opt/aws/bin/cfn-signal -e $? \",
                        \"         --stack \", {\"Ref\": \"AWS::StackName\"}, \" \",
                        \"         --resource TomcatInstance \",
                        \"         --region \", {\"Ref\": \"AWS::Region\"}, \"\n\"
                    ]]
                }
            }
        }
    }
}

For package installation to work properly:

  1. UserData Execution: Must explicitly call cfn-init in the instance's UserData
  2. IAM Permissions: The EC2 instance role needs cloudformation:DescribeStackResource
  3. Package Availability: Verify packages exist in your distribution's repositories

Here's a functional template demonstrating proper package installation:

{
    \"AWSTemplateFormatVersion\": \"2010-09-09\",
    \"Resources\": {
        \"WebServerInstance\": {
            \"Type\": \"AWS::EC2::Instance\",
            \"Metadata\": {
                \"AWS::CloudFormation::Init\": {
                    \"configSets\": {
                        \"install_all\": [\"install_packages\"]
                    },
                    \"install_packages\": {
                        \"packages\": {
                            \"yum\": {
                                \"httpd\": [],
                                \"git\": []
                            }
                        },
                        \"services\": {
                            \"sysvinit\": {
                                \"httpd\": {
                                    \"enabled\": \"true\",
                                    \"ensureRunning\": \"true\"
                                }
                            }
                        }
                    }
                }
            },
            \"Properties\": {
                \"ImageId\": \"ami-0c55b159cbfafe1f0\",
                \"InstanceType\": \"t2.micro\",
                \"UserData\": {
                    \"Fn::Base64\": {
                        \"Fn::Join\": [\"\", [
                            \"#!/bin/bash -xe\n\",
                            \"# Install cfn bootstrap tools\n\",
                            \"yum install -y aws-cfn-bootstrap\n\",
                            \"# Run cfn-init\n\",
                            \"/opt/aws/bin/cfn-init -v --stack \", {\"Ref\": \"AWS::StackName\"}, \" \",
                            \"--resource WebServerInstance --region \", {\"Ref\": \"AWS::Region\"}, \" \",
                            \"--configsets install_all\n\",
                            \"# Signal completion\n\",
                            \"/opt/aws/bin/cfn-signal -e $? --stack \", {\"Ref\": \"AWS::StackName\"}, \" \",
                            \"--resource WebServerInstance --region \", {\"Ref\": \"AWS::Region\"}, \"\n\"
                        ]]
                    }
                },
                \"IamInstanceProfile\": {\"Ref\": \"EC2InstanceProfile\"}
            }
        },
        \"EC2InstanceProfile\": {
            \"Type\": \"AWS::IAM::InstanceProfile\",
            \"Properties\": {
                \"Roles\": [{\"Ref\": \"EC2InstanceRole\"}]
            }
        },
        \"EC2InstanceRole\": {
            \"Type\": \"AWS::IAM::Role\",
            \"Properties\": {
                \"AssumeRolePolicyDocument\": {
                    \"Version\": \"2012-10-17\",
                    \"Statement\": [{
                        \"Effect\": \"Allow\",
                        \"Principal\": {\"Service\": [\"ec2.amazonaws.com\"]},
                        \"Action\": [\"sts:AssumeRole\"]
                    }]
                },
                \"ManagedPolicyArns\": [
                    \"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore\",
                    \"arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy\"
                ],
                \"Policies\": [{
                    \"PolicyName\": \"CloudFormationAccess\",
                    \"PolicyDocument\": {
                        \"Version\": \"2012-10-17\",
                        \"Statement\": [{
                            \"Effect\": \"Allow\",
                            \"Action\": [\"cloudformation:DescribeStackResource\"],
                            \"Resource\": \"*\"
                        }]
                    }
                }]
            }
        }
    }
}

If packages still don't install:

  • Check /var/log/cloud-init-output.log for execution errors
  • Verify cfn-init was actually executed (search logs for "cfn-init")
  • Ensure your base AMI has the AWS CloudFormation helper scripts installed
  • Confirm network connectivity to package repositories