How to use AWS SSM Session Manager Plugin
Tags: aws, devops, security
Published: 2022-01-14 07:12:45

AWS System Manager Session Manager has been an awesome tool and in our organization we have quickly adopted AWS System Manager Session Manager in-lieu of bastion host.

However, if you ever tried to use the `StartSession` API for AWS SSM on any of the AWS SDKs, you will soon find out that the SDK calls will return you something like this: 

```
{
    "SessionId": "John-Doe-0dc5b7af96EXAMPLE",
    "StreamUrl": "wss://ssmmessages.us-east-2.amazonaws.com/v1/data-channel/John-Doe-0dc5b7af96EXAMPLE?role=publish_subscribe",
    "TokenValue": "a3f5ff34-9bc4-4d2c-a665-4d1c1EXAMPLE/39c3b3042cd2aEXAMPLE"
}
```

It's then left to the user to use the StreamUrl and TokenValue to establish a shell session themselves, there are various attempts to consume this response such as [this one](https://github.com/bertrandmartel/aws-ssm-session) where it uses the `xterm` npm package to establish a session in html.

Another way to consume this response, which we will explore here today, is to use the AWS SSM Sesison Manager plugin.

In the AWS documentation, there is an optional step to install the [AWS SSM Sesison Manager plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html), however, there isn't much documentation on what it does or how to use it. 

It turned out that this plugin is actually an [open source project on GitHub](https://github.com/aws/session-manager-plugin), and this tool is used to power the `start-session` AWS CLI command to establish shell session. The exact way to use it undocumentated, but one can check [AWS CLI's source code](https://github.com/aws/aws-cli/blob/45b0063b2d0b245b17a57fd9eebd9fcc87c4426a/awscli/customizations/sessionmanager.py) to see and example on how to use it.

So here is the exact way to use session manager plugin to start a session, in this example, we will use the AWS NodeJS SDK V3 and TypeScript.

```typescript
import { SSMClient, StartSessionCommand, StartSessionCommandInput } from "@aws-sdk/client-ssm";
import {spawn} from 'child_process'


const region = 'us-east-1';
const ec2InstanceId = 'i-123456';
const ssmDocumentName = 'custom-ssm-document-name';

/**
*  Send start-session API call and store the response
**/
const ssmClient = new SSMClient();
const startSessionParams : StartSessionCommandInput = { 
    Target: ec2InstanceId,
    DocumentName: ssmDocumentName,
}; 
const startSessionCommand = new StartSessionCommand(startSessionParams);
const startSessionResp = await ssmClient.send(startSessionCommand);


const ssmPluginArgs : string[] = [ 
    JSON.stringify(startSessionResp),
    region,
    'StartSession',
    '', // AWS CLI profile name goes here
    JSON.stringify(startSessionParams), 
    `https://ssm.${region}.amazonaws.com`
];

process.stdin.pause(); // pause stdin for the child process
const child = spawn('session-manager-plugin', ssmPluginArgs, {stdio: 'inherit'});

child.on('exit', function () {
    process.stdin.resume();
});
```

To illustrate this command in bash:
`session-manager-plugin <start-session-response-in-json> <region> StartSession <cli-profile-name> <start-session-parameters-in-json> <ssm-endpoint>`

and then it will start the shell session using the connection established by the `StartSession` API call. 

As a caution for anyone trying to integrate this command into your own application, make sure to intercept the `SIGINT` signal inside your application because being able to use `Ctrl + C` to stop an application in your server's session is defintely nice to have.