How to login to EC2 instances without SSH

In previous posts, we showed you how to deploy a private key pair to allow you to login to an
EC2 instance. Since september 2018, the AWS Session Manager supports logging into any instance, directly from the command line without SSH. In this
blog we will show you how to configure this using CloudFormation.

To login to an EC2 instance using the AWS Session manager, you need to do three things:

  • Install the AWS SSM agent
  • Grant session manager permissions
  • Enable audit logging

install the AWS SSM agent

We are lazy and use an Amazon Linux based instance, which has the agent already installed.For other
AMIs, please consult the documentation.
In CloudFormation, we add the instance:

<span style="font-weight:bold">Parameters</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">  </span><span style="font-weight:bold">AmiId</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">    </span><span style="font-weight:bold">Type</span>:<span style="color:#bbb"> </span><span style="color:#b84">'AWS::SSM::Parameter::Value<aws::EC2::Image::Id>'</span><span style="color:#bbb">
</span><span style="color:#bbb">    </span><span style="font-weight:bold">Default</span>:<span style="color:#bbb"> </span><span style="color:#b84">'/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2'</span><span style="color:#bbb">
</span><span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="font-weight:bold">Resources</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">  </span><span style="font-weight:bold">Instance</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">    </span><span style="font-weight:bold">Type</span>:<span style="color:#bbb"> </span><span style="color:#b84">'AWS::EC2::Instance'</span><span style="color:#bbb">
</span><span style="color:#bbb">    </span><span style="font-weight:bold">Properties</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">      </span><span style="font-weight:bold">ImageId</span>:<span style="color:#bbb"> </span>!Ref<span style="color:#bbb"> </span><span style="color:#b84">'AmiId'</span><span style="color:#bbb">
</span><span style="color:#bbb">      </span><span style="font-weight:bold">IamInstanceProfile</span>:<span style="color:#bbb"> </span>!Ref<span style="color:#bbb"> </span><span style="color:#b84">'IamInstanceProfile'</span><span style="color:#bbb">
</span>

grant session manager permissions

The agent needs the following permissions to enable the session manager:

- <span style="font-weight:bold">Effect</span>:<span style="color:#bbb"> </span>Allow<span style="color:#bbb">
</span><span style="color:#bbb">  </span><span style="font-weight:bold">Action</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">    </span>- ssmmessages:CreateControlChannel<span style="color:#bbb">
</span><span style="color:#bbb">    </span>- ssmmessages:CreateDataChannel<span style="color:#bbb">
</span><span style="color:#bbb">    </span>- ssmmessages:OpenControlChannel<span style="color:#bbb">
</span><span style="color:#bbb">    </span>- ssmmessages:OpenDataChannel<span style="color:#bbb">
</span><span style="color:#bbb">  </span><span style="font-weight:bold">Resource</span>:<span style="color:#bbb"> </span><span style="color:#b84">'*'</span><span style="color:#bbb">
</span><span style="color:#bbb"></span>- <span style="font-weight:bold">Effect</span>:<span style="color:#bbb"> </span>Allow<span style="color:#bbb">
</span><span style="color:#bbb">  </span><span style="font-weight:bold">Action</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">    </span>- s3:GetEncryptionConfiguration<span style="color:#bbb">
</span><span style="color:#bbb">  </span><span style="font-weight:bold">Resource</span>:<span style="color:#bbb"> </span><span style="color:#b84">'*'</span><span style="color:#bbb">
</span>

To keep things small and simple, we associate the AmazonEC2RoleforSSM role with the instance profile, which
includes the above permissions:

<span style="font-weight:bold">InstanceRole</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">  </span><span style="font-weight:bold">Type</span>:<span style="color:#bbb"> </span>AWS::IAM::Role<span style="color:#bbb">
</span><span style="color:#bbb">  </span><span style="font-weight:bold">Properties</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">    </span><span style="font-weight:bold">AssumeRolePolicyDocument</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">      </span><span style="font-weight:bold">Statement</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">    </span>- <span style="font-weight:bold">Effect</span>:<span style="color:#bbb"> </span>Allow<span style="color:#bbb">
</span><span style="color:#bbb">      </span><span style="font-weight:bold">Principal</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">        </span><span style="font-weight:bold">Service</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">          </span>- ec2.amazonaws.com<span style="color:#bbb">
</span><span style="color:#bbb">      </span><span style="font-weight:bold">Action</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">        </span>- sts:AssumeRole<span style="color:#bbb">
</span><span style="color:#bbb">    </span><span style="font-weight:bold">Path</span>:<span style="color:#bbb"> </span>/<span style="color:#bbb">
</span><span style="color:#bbb">    </span><span style="font-weight:bold">ManagedPolicyArns</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">      </span>- arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM<span style="color:#bbb">
</span>

Enable audit logging

AWS Session Manager allows you to store the session logs on either S3, CloudWatch or both.
To enable audit logging you need to create an SSM Document named SSM-SessionManagerRunShell:

<span style="color:#bbb">  </span><span style="font-weight:bold">SessionManagerPreferences</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">    </span><span style="font-weight:bold">Type</span>:<span style="color:#bbb"> </span>Custom::SSMDocument<span style="color:#bbb">
</span><span style="color:#bbb">    </span><span style="font-weight:bold">Properties</span>:<span style="color:#bbb">
</span><span style="color:#bbb"></span><span style="color:#bbb">      </span><span style="font-weight:bold">Name</span>:<span style="color:#bbb"> </span>SSM-SessionManagerRunShell<span style="color:#bbb">
</span><span style="color:#bbb">      </span><span style="font-weight:bold">DocumentType</span>:<span style="color:#bbb"> </span>Session<span style="color:#bbb">
</span><span style="color:#bbb">      </span><span style="font-weight:bold">Content</span>:<span style="color:#bbb"> </span>!Sub<span style="color:#bbb"> </span><span style="color:#b84">>
</span><span style="color:#b84">       </span><span style="color:#b84"> </span><span style="color:#b84">{ "schemaVersion": "1.0",</span><span style="color:#bbb">
</span><span style="color:#bbb">          </span><span style="font-weight:bold">"content": </span><span style="color:#b84">"Session Manager Preferences"</span>,<span style="color:#bbb">
</span><span style="color:#bbb">          </span><span style="font-weight:bold">"sessionType": </span><span style="color:#b84">"Standard_Stream"</span>,<span style="color:#bbb">
</span><span style="color:#bbb">          </span><span style="font-weight:bold">"inputs": </span>{<span style="color:#bbb">
</span><span style="color:#bbb">            </span><span style="font-weight:bold">"s3BucketName": </span><span style="color:#b84">"${SessionLogBucket}"</span>,<span style="color:#bbb">
</span><span style="color:#bbb">            </span><span style="font-weight:bold">"s3KeyPrefix": </span><span style="color:#b84">""</span>,<span style="color:#bbb">
</span><span style="color:#bbb">            </span><span style="font-weight:bold">"s3EncryptionEnabled": </span><span style="font-weight:bold">false</span>,<span style="color:#bbb">
</span><span style="color:#bbb">            </span><span style="font-weight:bold">"cloudWatchLogGroupName": </span><span style="color:#b84">"${SessionLogGroup}"</span>,<span style="color:#bbb">
</span><span style="color:#bbb">            </span><span style="font-weight:bold">"cloudWatchEncryptionEnabled": </span><span style="font-weight:bold">false</span><span style="color:#bbb">
</span><span style="color:#bbb">          </span>}<span style="color:#bbb">
</span><span style="color:#bbb">        </span>}<span style="color:#bbb">
</span>

Note that we had to create a custom CloudFormation provider to create the document, as the standard
CloudFormation resource does not allow you to specify the document name.

starting a session

Once deployed you can login to your instance by typing:

$ aws ssm start-session --target <instance-id>

demo

The complete CloudFormation template can be found on github. To
test, type:

$ git clone https://github.com/binxio/blog-login-to-ec2-instances-without-ssh
$ <span style="color:#999">cd</span> blog-login-to-ec2-instances-without-ssh
$ make
create demo in default VPC vpc-12313137, subnets subnet-privatea,subnet-privateb,subnet-privatec using security group sg-default.
<span style="font-weight:bold">{</span>
    <span style="color:#b84">"StackId"</span>: <span style="color:#b84">"arn:aws:cloudformation:eu-central-1:111111111111:stack/ec2-session-manager/207b6890-26dc-11e9-b214-021298c8e4cc"</span>
<span style="font-weight:bold">}</span>

<span style="font-weight:bold">[</span>
    <span style="color:#b84">"aws ssm start-session --target i-0c25d8bf100a5d1da"</span>, 
    <span style="color:#b84">"</span><span style="color:#b84">aws logs get-log-events --log-group-name ec2-session-manager-SessionLogGroup-L9G8VSLL6XCK --log-stream-name </span><span style="color:#008080">$SESSION_ID</span><span style="color:#b84">"</span>, 
    <span style="color:#b84">"</span><span style="color:#b84">aws s3 cp s3://ec2-session-manager-sessionlogbucket-q8c1pz8q6u6g/</span><span style="color:#008080">$SESSION_ID</span><span style="color:#b84">.log -</span><span style="color:#b84">"</span>
<span style="font-weight:bold">]</span>

copy the outputed start-session command:

$ aws ssm start-session --target i-12311231123132

Starting session with SessionId: mvanholsteijn-0d9ce5dd2172522f7

sh-4.2$  sudo tail /var/log/amazon/ssm/*.log

You can explicit grant or deny users to start a session, through the action ssm:StartSession.

view session log

To view the session log from s3, type:

SESSION_ID=mvanholsteijn-0d9ce5dd2172522f7
aws s3 cp s3://ec2-session-manager-sessionlogbucket-q8c1pz8q6u6g/$SESSION_ID.log -

It will take a few minutes after closing the session, for the log to appear.

Conclusion

The AWS Session Manager simplifies logging into any of your EC2 instance which has the
SSM agent installed, without SSH. It saves complicating your
infrastructure with user- and ssh key management. Once support for tunneling is available,
we can say goodbye to the concept of a bastion host.

If you still want to login using SSH, we recommend the blog on how to deploy a private key pair.

Mark van Holsteijn is a senior software systems architect, and CTO of binx.io. He is passionate about removing waste in the software delivery process and keeping things clear and simple.
Share this article: Tweet this post / Post on LinkedIn