Site icon Craig Andrews

Improve Security and Reduce Costs with AWS SSM Session Manager

AWS recently enhanced its Systems Manager offering with shell access to EC2 instances and then they enhanced it further with SSH tunnel support. With these improvements, it’s now possible to improve your application’s security posture while reducing it’s operational costs and simplifying setup/maintenance.

Systems Manager vs Bastion Hosts

Minimizing the attack surface, simplifying as much as possible, not sharing credentials, and having audit trails are key facets of information security. The classic approach to providing access for authorized personnel (such as system administrators, database administrators, sometimes developers) to AWS resources is by setting up a bastion host (sometimes called a “jump box”) which acts as a gateway to other AWS resources. This approach has significant disadvantages:

AWS’s new SSM features solve all of these problems.

Setting up Systems Manager

So how do you get rid of that bastion in favor of using SSM? I recently introduced SSM support into VersionPress On AWS (which I’ll use as an example here) as well client projects. The process is to configure the EC2 instance to be able to communicate with SSM; the following details how to do that stand alone EC2 instances as well as ones managed by Elastic Beanstalk.

Enabling EC2 Instances to use SSM

For EC2 instances, create a new Instance Profile pointing to a new IAM role that includes the AmazonSSMManagedInstanceCore policy. This allows the EC2 instance to communicate with SSM. In CloudFormation json:

"EC2IamRole": {
	"Type" : "AWS::IAM::Role",
	"Properties" : {
		"AssumeRolePolicyDocument": {
			"Version" : "2012-10-17",
			"Statement": [ {
				"Effect": "Allow",
				"Principal": {
				"Service": [ "ec2.amazonaws.com" ]
			},
			"Action": [ "sts:AssumeRole" ]
			} ]
		},
		"ManagedPolicyArns" : [
			"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
			"arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"
		]
	}
},
"EC2IamInstanceProfile": {
	"Type" : "AWS::IAM::InstanceProfile",
	"Properties" : {
		"Roles" : [
			{
				"Ref": "EC2IamRole"
			}
		]
	}
}

CloudWatchAgentServerPolicy is not strictly required, but it’s generally a good idea to allow EC2s to log to CloudWatch. Add any other roles as desired, of course.

For the EC2, in its properties, set IamInstanceProfile to EC2IamInstanceProfile:

"EC2Host": {
	"Type": "AWS::EC2::Instance",
	"Properties": {
		"IamInstanceProfile":{
			"Ref": "BastionIamInstanceProfile"
		}
	}
}

If you’re using an Amazon Linux AMI base AMIs dated 2017.09 or later or an Amazon Linux 2 AMI, then you’re done unless you want to make sure the latest version of the SSM agent gets installed. Otherwise, you need to install the SSM agent. Here’s how to do that using CloudFormation with EC2 user data assuming an Amazon Linux 1 or 2 AMI is used:

"EC2Host": {
	"Properties": {
		"UserData": {
			"Fn::Base64": {
				"Fn::Join": [
					"\n",
					[
						"#cloud-config",
						"",
						"runcmd:",
						{ "Fn::Sub" : "  - yum -y localinstall https://s3.${AWS::Region}.amazonaws.com/amazon-ssm-${AWS::Region}/latest/linux_amd64/amazon-ssm-agent.rpm" }
					]
				]
			}
		}
	}
}

Further instructions, including for other operations systems, is covered in the AWS documentation.

That’s it for EC2.

Enabling Beanstalk Instances to use SSM

For Elastic Beanstalk, the process is very similar to standalone EC2 instances. Create a new Instance Profile pointing to a new IAM role that includes the AmazonSSMManagedInstanceCore policy. In CloudFormation json:

"BeanstalkInstanceIamRole": {
	"Type" : "AWS::IAM::Role",
	"Properties" : {
		"AssumeRolePolicyDocument": {
			"Version" : "2012-10-17",
			"Statement": [ {
				"Effect": "Allow",
				"Principal": {
				"Service": [ "ec2.amazonaws.com" ]
			},
			"Action": [ "sts:AssumeRole" ]
			} ]
		},
		"ManagedPolicyArns" : [
			"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
			"arn:aws:iam::aws:policy/AWSElasticBeanstalkWebTier"
		]
	}
},
"BeanstalkInstanceIamInstanceProfile": {
	"Type" : "AWS::IAM::InstanceProfile",
	"Properties" : {
		"Roles" : [
			{
				"Ref": "BeanstalkInstanceIamRole"
			}
		]
	}
}

For the Beanstalk Environment, in its properties, in the namespace aws:autoscaling:launchconfiguration set IamInstanceProfile to BeanstalkInstanceIamInstanceProfile:

"BeanstalkEnvironment": {
	"Type": "AWS::ElasticBeanstalk::Environment",
	"Properties": {
		"OptionSettings": [
			{
				"Namespace": "aws:autoscaling:launchconfiguration",
				"OptionName": "IamInstanceProfile",
				"Value":
					{
						"Ref": "BeanstalkInstanceIamInstanceProfile"
					}
			}
		]
	}
}

If you’re using an Amazon Linux AMI base AMIs dated 2017.09 or later or an Amazon Linux 2 AMI, then you’re done. Otherwise, you need to install the SSM agent. Create an ebextension (named, for example, ssm-agent.config) like this to do so:

---
commands:
  01_install_amazon_ssm_agent:
    command: 'yum -y localinstall https://s3.`{ "Ref" : "AWS::Region"}`.amazonaws.com/amazon-ssm-`{ "Ref" : "AWS::Region"}`/latest/linux_amd64/amazon-ssm-agent.rpm'

That’s it – the Beanstalk managed EC2 instances should now be visible to SSM.

Using the SSM Console to Connect to Instances

The SSM Console allow you to connect to EC2 instances from the browser – there is no client software (other than the browser) involved. This eliminates the need to worry about SSH clients and firewalls.

To start a session, from the SSM console, go to Session Manager.

AWS Systems Manager > Start a session

Select the desired instance and click “Start Session”. The result is a shell in your browser.

AWS Systems Manager session started

Use an SSH Client to Connect to Instances Including File Transfers and Port Forwarding

The browser based access is nice, but it doesn’t allow for file transfers or port forwarding. To be able to do that, SSM supports SSH connections. To set that up:

With that setup in place, ssh to any SSH registered EC2 instance by running:

ssh ec2-user@i-012345679

Port forwarding also works. For example, I set up a tunnel to my RDS instance so I can use SQuirreL SQL to query my RDS database like this:

ssh ec2-user@i-012345679 -A -L5432:production-env-db.c5nl5xt26oh8.us-east-1.rds.amazonaws.com:5432

Finally, scp and sftp work for copying files both to and from EC2 instances:

scp myfile ec2-user@i-012345679:

Conclusion

Bastion hosts were a good solution, but now there is a better solution.

And it’s not just AWS that’s offering better alternatives to bastion hosts; Microsoft offers Azure Bastion which closely mirror’s AWS’s Systems Manager Session Manager.

Improve Security and Reduce Costs with AWS SSM Session Manager by Craig Andrews is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Exit mobile version