Enable SSM Agent On AWS

Rohan Büchner

Rohan Büchner / April 13, 2022

READING TIME––– views

I recently needed to debug a deployed kafka-connect image that was running on AWS Fargate.

All of the infrastructure has been written using the AWS CDK.

Some context:

I'll assume we're coming from an area of 0 knowledge, in general when going through AWS blog posts/courses you'll notice you'll either use SSH or AWS Web Console access.

Allow me to provide a better / more secure approach.

Let us assume you have some hyper-secure service that needs to run on AWS in a private subnet.
You create your `VPC` and private subnet and deploy your application.
You now need to debug it (and need more than just logs)
How do you do the above?

- Redeploy the whole stack into a public subnet so you can enable SSH or use the web interface (or other means?)

I do know about you, but that sound like a pain in the ass.

I was then introduced to the AWS SSM Agent. This will allow CLI access to instances using your account AWS credentials (and roles and perms if it has been set up as granular as that is).

How does this compare to SSH then... SSH will allow access to anyone with that SSH key. The key's security is baked into the key itself (if a password was added), then that is it.

SSM on the other hand like stated previously is linked to your AWS account and thus can be managed via the AWS roles and perms, AND the real benefit
is not limited to having a bastion in the public subnet acting as a proxy or moving your application into a public stack with a static or elastic IP.

How to prep your cloud application (using CDK)

1. You need an application in AWS either running on Fargate or EC2.
2. Use the following CDK snippet to enable SSM on your Fargate or EC2 instance.

import { Construct } from 'constructs';
import {
    CfnService,
    Ec2Service,
    FargateService,
} from 'aws-cdk-lib/aws-ecs';
import { Policy, PolicyStatement } from 'aws-cdk-lib/aws-iam';

export interface EnableSSMProps {
    service: FargateService | Ec2Service | any;
}

export class EnableSSM extends Construct {
    constructor(scope: Construct, id: string, props: EnableSSMProps | any) {
        super(scope, id);

        // this is a hack.. the current CDK lib doesnt expose the ability to set the enableExecuteCommand
        // https://github.com/aws/aws-cdk/issues/15197#issuecomment-916504689
        const serviceInstance = props.service.node.children.filter(
            (child: any) =>
                ['FargateService', 'Ec2Service'].includes(
                    child.constructor.name,
                ),
        )[0];
        const cfnService = serviceInstance.node.defaultChild as CfnService;
        cfnService.enableExecuteCommand = true;

        serviceInstance.taskDefinition.taskRole.attachInlinePolicy(
            new Policy(this, 'ssm-message-policy', {
                statements: [
                    new PolicyStatement({
                        actions: [
                            'ssmmessages:CreateControlChannel',
                            'ssmmessages:CreateDataChannel',
                            'ssmmessages:OpenControlChannel',
                            'ssmmessages:OpenDataChannel',
                        ],
                        resources: ['*'],
                    }),
                ],
            }),
        );
    }
}

3. Pass either your CDK Fargate or EC2 service instance as a property into the function above.

new EnableSSM(this, 'enable-service-ssm', {
  service: instance.fargateService,
});

4. Deploy/Update your CDK stack using the regular process.

How to enable/use SSM from your local machine:

  1. You might need to install the AWS CLI SSM plugin
  2. Make sure your AWS profile is loaded into your terminal session
aws ecs execute-command
--region <your_application_region> \
--cluster <your_fargate_cluster> \
--task <your_esc_task_id> \
--command "sh" \
--interactive  #this is needed when using the sh command

And that's it. Once the last command is run, you should be inside your container.

Bonus Points:

If you do encounter any issues. I have discovered a really good utility written by some clever people at AWS that can help you debug. Amazon ECS exec checker