Published on

Enable SSM Agent On AWS

4 minutes read - ––– views
Authors

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.

Lets 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 introdused to the AWS SSM Agent. This will allow CLI access to instances using your accounts AWS credentials (and roles and perms if it has been setup as granular as that is).

How does this compare to SSH then... SSH will allow access to anyone with that SSH key. The keys 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 you 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 elasic IP.

How to prep your cloud application (using CDK)

  1. You need an application in AWS either running on Fargate or EC2.

  2. Use this 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
  3. 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 thats 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 gool utility written by some clever people at AWS which can help you debug. Amazon ECS exec checker