Old AMIs on your AWS Account
Tags: aws, cli, npm, javascript
Published: 2021-10-05 14:26:18

If you're using Amazon Web Services (AWS), there's a pretty reasonable chance that you're also explicitly using an [Amazon Machine Image](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) (AMI) -- the format that AWS uses to make a virtual machine image. And if you've been using AWS for more than a few months, you might have some resources that were built with an old AMI. Maybe it was current when you created the instance or launch configuration, but has been aging since then.

If you're using an old AMI and you haven't been patching it, or if you have been patching it but the release is no longer supported, your resources might be vulnerable to attack. [Patch management](https://www.rapid7.com/fundamentals/patch-management/) is crucial to keeping a long-running server secure. Of course, just because an AMI is old doesn't mean it hasn't been patched. Amazon Linux and Ubuntu both have an option for a [rolling release](https://en.wikipedia.org/wiki/Rolling_release) model that can keep an old AMI relatively secure. If you've invested a lot into devops, you might also have a continuous deployment pipeline that rebuilds [phoenix servers](https://martinfowler.com/bliki/PhoenixServer.html) on a regular basis, which might include updating the AMI.

You might also be using AMIs, but not explicitly. You might be implicitly using AMIs through [Fargate](https://docs.aws.amazon.com/AmazonECS/latest/userguide/what-is-fargate.html) or [Lambda](https://aws.amazon.com/lambda/), for instance. Getting out of the business of configuring and patching server instances is part of the value proposition of the 'serverless' model. There are still servers and patches, but you, the AWS user, don't need to care about them. 

But if you're using AMIs and you're not sure that you've been keeping on top of the support timelines and the patch management, then it's probably also a good idea to consider how old those AMIs might be.

## Finding Old AMIs
If you are using AMIs, how can you find out if the AMIs you're using are current?  You can look at the AMI metadata:

- `CreationDate`
    - This tells you when the AMI was created.
    - A creation date that isn't recent doesn't mean that image is unsupported or cannot be well-patched, but if you're still using an image created years ago, this might at least suggest that you need to take a closer look.
    - If this image is still well-supported, you might still want to look at devops practices that allow you to rebuild old servers using more current images on a regular basis.
- `DeprecationTime`
    - AWS [recently added](https://aws.amazon.com/about-aws/whats-new/2021/06/amazon-ec2-adds-new-ami-property-to-flag-outdated-amis/) a new piece of metadata that allows the image creator / maintainer [to indicate](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ami-deprecate.html) the date/time on which the image is deprecated.
    - This is more explicit than the creation date, but because it's new, there may well be many old images that are borderline abandoned and that don't have this date set.

So, if you gather a list of all the AMIs that you're using, you can look at these two fields to get hints about which images need a closer examination. An image created a year or more ago, or marked as deprecated are both worth examining to see if they're well-patched and well-supported.

## A Simple Tool
If looking up all the AMIs in use on your account and checking the metadata sounds like a lot of work, then you're in luck. After reading about the new `DeprecationTime` data point, I made a small JavaScript tool, `oldamis` ([github](https://github.com/geoffreywiseman/oldamis), [npm](https://www.npmjs.com/package/@codiform/oldamis)) that looks up AMIs and checks both of those data points for you. You can run it with `npx` if you have NPM installed:

```
❯ npx @codiform/oldamis
   ___    _       _        _      __  __   ___
  / _ \  | |   __| |      / \    |  \/  | |_ _|  ___
 | | | | | |  / _` |     / _ \   | |\/| |  | |  / __|
 | |_| | | | | (_| |    / ___ \  | |  | |  | |  \__ \
  \___/  |_|  \__,_|   /_/   \_\ |_|  |_| |___| |___/

ami ami-730ebd17 is old (created 2016-08-22T19:58:21.000-04:00), sources:
  - instance i-13e13eeb963a78ab9
ami ami-0cde1f5ee149df291 is ok, sources:
  - instance i-a3c31bb5ebbd4790d
  - instance i-11aff774c13d785ef
  - instance i-486d7a5e0171e6749
ami ami-0f1c5116668d961c3 is ok, sources:
  - instance i-8f434ca2c2c36dfb5
  - instance i-4b344522536719e4f
  - launch config demo-launch-config-2340234
```

This isn't a sophisticated tool -- it's a proof of concept. Organizations that want to monitor this sort of thing should probably be looking at monitoring or policy-as-code tools that can be configured to look at this and many, many other things that could go wrong with your AWS account. That said, if you're not sure how old the AMIs you're using are right now, and this tool makes your life easier, I'm happy to hear it.

Just to be clear, `oldamis` doesn't record information about your account, intercept data, or use your credentials in sneaky ways. The tool respects your privacy and its open-source, so you're welcome to dig into the code before running it, just to make sure.

## How it's made

I made `oldamis` with the [AWS JavaScript SDK v3](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/index.html). I've done a bunch of AWS automation using Python and Boto3 and wanted to try a different language and SDK for a change, and refresh my knowledge of publishing an NPM module.  There were a few hiccups, but all in all it worked well, and there's a good library for mocking API calls, which I've found to be somewhat important when you're writing a tool that is a thin layer over AWS API calls.

As an example, once `oldamis` has figured out which AMIs you might be using, it uses the DescribeImages api call to get the `DeprecationTime` and `CreationDate`:

```javascript
const getAmiDates = async (amis) => {
    const command = new DescribeImagesCommand({
        "ImageIds": amis,
        "IncludeDeprecated": true
    });
    const response = await ec2Client.send(command);
    return response.Images.reduce((o, img) => {
        const {ImageId, DeprecationTime, CreationDate} = img;
        o[ImageId] = {DeprecationTime, CreationDate};
        return o;
    }, {})
}
```

After getting the response it transforms the results into a smaller data structure for consumption by the CLI that looks like this:

```json
{
    "ami-730ebd17": {
        "CreationDate": "2016-08-22T19:58:21.000-04:00",
        "DeprecationTime": null
    }
}
```

There's more to it, but if you want to see more code samples, then I invite you to check out the GitHub repository. Contributions and feedback are welcome.

The `oldami` tool uses [chalk](https://github.com/chalk/chalk) to colorize the output and [figlet](https://github.com/patorjk/figlet.js) for the banner.