Tom Lei
Posted on January 14, 2022
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 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, 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, 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 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.
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.
Posted on January 14, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.