How To Secure Access To Your Infrastructure Using AWS Session Manager And A Bastion Host
Securing cloud infrastructure is essential, but traditional bastion host setups often come with challenges. What if I told you that you could still leverage bastion hosts without the hassles? Dive in to find out how!
In this guide, I’ll show you how to leverage Terraform to effortlessly build a bastion host in AWS, using AWS Systems Manager Session Manager and Amazon EC2 Instance Connect for secure, streamlined access.
From setup and configuration to automation and troubleshooting, you’ll learn the NaNLABS way of building a secure, scalable, and easy-to-manage bastion host.
Ready to harness the power of AWS and Terraform to elevate your infrastructure security? Let’s dive in.
Table of Contents
How can a bastion host contribute to securing your infrastructure?
How to automate and scale the bastion host in larger infrastructure setups?
Conclusion: Combine AWS and Host Bastion powers to secure your infrastructure
How can a bastion host contribute to securing your infrastructure?
A bastion host acts as a secure gateway to your private network resources. However, traditional bastion hosts often require open inbound ports and complex SSH key management. At NaNLABS, we’ve come up with a solution that allows you to leverage bastion hosts without weakening your security posture.
This solution leverages AWS Systems Session Manager and Amazon EC2 Instance Connect to:
Provides a safer way to handle inbound port traffic
Eliminate long-lived SSH key management
Secure access to AWS network resources
Streamline operational processes
By combining these tools, we can enhance your infrastructure security, while simplifying access management.
Let’s dive so you can see how to implement our solution to your infrastructure!
Need extra help to enhance your infrastructure security? We’ve got you! Reach out to enhance your infrastructure security!
NaNLABS’ approach to bastion hosts in AWS environments
Terraform module roadmap to bootstrap a bastion host in AWS
A bastion host, sometimes called a jump box, is a server that provides a single point of access from an external network to resources located in a private network. This module uses AWS Systems Manager Session Manager and Amazon EC2 Instance Connect to securely connect to an Amazon EC2 bastion host without exposing any inbound ports or managing long-lived SSH keys.
Usage example
Target technology stack
VPC with at least one private subnet
3 VPC (Interface) Endpoints with corresponding security groups and security group rules
EC2 Instance (t3.nano) with Ubuntu 24.04 installed with associated:
IAM role
IAM instance profile
security group
Target architecture
Let me guide you through how the Bastion host interacts with AWS services:
Deployment of the EC2 instance: First, we deploy a single isolated EC2 instance (t3.nano) with Ubuntu 24.04, installed inside the private subnet in the created VPC. The instance doesn’t expose any ports or have a public IP assigned.
Communication via VPC Endpoints: The EC2 instance uses VPC Interface Endpoints, which are private connections to AWS services (like Systems Manager and EC2), so it remains isolated while allowing secure interactions with AWS.
Role-based Access Control: You assume an IAM role with policies granting specific permissions for authenticating, authorizing, and connecting to the EC2 instance, following the least privilege principle. Separately, the EC2 instance assumes an IAM role, which defines its permissions for interacting with other AWS resources. This setup ensures minimal, controlled access, requiring any additional access to be explicitly granted by assigning policies to the respective IAM roles for both users and the EC2 instance.
This setup establishes a secure way to manage and interact with resources within an AWS VPC without direct internet exposure, leveraging IAM for secure, role-based access.
EC2 Instance Provisioning
The created EC2 instance is provisioned using cloud-init. You can customize the instance provisioning by modifying the content of the cloud_init
template file at templates/cloud_init.tpl
.
Connecting to the Bastion Host Using Session Manager
Now let’s walk through the steps to securely connect to the bastion host using AWS Session Manager, IAM roles, and SSH keys.
Prerequisites
AWS Command Line Interface v2: Ensure the AWS CLI is installed on your local machine. Check the AWS CLI Installation Guide for more information.
Session Manager Plugin: Ensure the Session Manager Plugin is installed on your local machine. Check the AWS Session Manager Plugin Installation Guide for more information.
Setup Local Environment
Install tools
Follow the prerequisites section to install AWS CLI and Session Manager plugin.Configure SSH connection
Follow the documentation to update the SSH configuration file to allow SSH connections through Session Manager. It enables a proxy command to initiate a Session Manager session, seamlessly transferring all data through the established connection.Generate SSH keys
Generate local SSH private and public keys. For example, use the following command:ssh-keygen -t rsa -f my_key
It will generate a pair of private and public SSH keys, which will be used to connect to the bastion host. Setting a password to protect access to the private key and storing both keys in a secure location is recommended.
Connect To the Bastion Host
Follow these 4 steps to connect to the bastion host:
Assume IAM Role
Assume an IAM role that has permissions to authenticate, authorize, and connect to the EC2 instance.Obtain the instance ID
You must obtain the EC2 instance ID to connect to the deployed bastion host. You can retrieve it in several ways, such as by navigating to the EC2 dashboard in the AWS Console or by using the AWS CLI command:aws ec2 describe-instances
To further filter results you can use the following command:
Replace$BASTION_HOST_TAG
with the tag used to mark the bastion host. Copy obtained EC2 instance ID for later use.Upload SSH keys
To connect to the bastion host, first, upload your public SSH key to the host using EC2 Instance Connect. Run the following command, replacing:$INSTANCE_ID
with the EC2 instance ID obtained in the previous step$PUBLIC_KEY_FILE
with the path to your public key file (e.g.,my_key.pub
).
Be sure to use the public key and NOT the private key.<script src="https://gist.github.com/sarahjdn/8db85bd0fc21a0ab95fe129d92470b9a.js"></script>
You should see a message confirming the successful upload of the SSH key. The key is temporarily stored in the EC2 instance metadata for 60 seconds. After this period, it is automatically removed, and any attempts to connect will result in a 'Permission denied' error. If that happens, you can resend the key using the same command.
This means you have 60 seconds to establish the SSH connection after uploading the key. Follow the next step to proceed.
Connect via SSH through Session Manager
In this final step, you'll connect to the bastion host using SSH. Use the following command, replacing:
$PRIVATE_KEY_FILE
with the path to your private key (e.g., my_key)$INSTANCE_ID
with the EC2 instance ID obtained earlier.
Confirm the connection by typing 'yes'. This will establish the SSH connection using the previously configured Session Manager.
You’re in!
Additional Useful Commands
List Active Sessions
To list all active sessions:
Terminate a Session
To terminate a specific session, you need the session ID. First, list the active sessions to get the session ID:
Then terminate the session using the session ID:
Example Script For Complete Workflow
Here’s a full example script that retrieves the Bastion instance ID, uploads the SSH public key, and initiates a Session Manager session:
Optional Steps
The following steps are optional and can help enhance the security of the Bastion host or simplify the connection process.
Quick Connection Using Script
To simplify the process of connecting to the Bastion host, you can use theconnect.sh
script. This script automates the tasks of generating an SSH key pair, uploading the public key to the Bastion host, and establishing an SSH connection through AWS Systems Manager.
Run the script with the following command:<script src="https://gist.github.com/sarahjdn/bdfe5d4a16e6cb3d2be5815077b4a48a.js"></script>
Replace
<instance-id>
with the ID of the Bastion host instance. The script will automatically:Generate an SSH key pair.
Upload the public key to the Bastion host.
Establish an SSH connection using the private key.
Use the
-h
--help
flag to see the available options:Use Other SSH Options to Open Connection
There are various options available for connecting to the Bastion host. For example, you can use the -D 8888 option to establish an SSH connection with local 'dynamic' application-level port forwarding on port 8888. Refer to this link for a detailed explanation.https://gist.github.com/sarahjdn/cf3f6725d241600dc765e16c199e62da
This type of connection sets up a SOCKS proxy, allowing you to forward traffic from your local browser through the bastion host, for example. Refer to the main pages of ssh command to see all options.
How to automate and scale the bastion host in larger infrastructure setups?
The previous pattern can be adopted as part of a larger infrastructure code and deployed in an automated way using CI/CD tools. You can modify the code to change the type of deployed EC2 instance to adjust its parameters to your specific needs.
Automating and scaling the bastion host as part of a larger infrastructure setup offers several key benefits such as:
Improved security: Automation ensures that security practices, such as key management and access controls, are consistently applied. It reduces the risk of human error, ensuring that security settings are always up-to-date.
Consistency: By automating the deployment and configuration of bastion hosts, you ensure that each instance is set up consistently across your environment, reducing configuration drift and minimizing the risk of misconfigurations.
Cost efficiency: Automation allows you to scale bastion hosts up or down based on demand, ensuring you’re only paying for the resources you need at any given time.
Operational efficiency: Automating the creation and management of bastion hosts can free up time for your teams to focus on other critical tasks. It also streamlines the process of rotating keys, applying updates, and scaling infrastructure.
Easier disaster recovery: If a bastion host fails, automation allows you to quickly replace it or spin up new instances, reducing downtime and ensuring that access remains uninterrupted.
Troubleshooting
Occasionally, you may encounter a TargetNotConnected
error when attempting to connect to the Bastion host.
Here’s how to resolve the issue:
Follow the Reboot your instance documentation from AWS to reboot the deployed bastion host.
Refer to the Connect to the Bastion Host section of this article and try to reconnect.
Additional Resources
Here are some additional resources to help you optimize your setup:
Conclusion: Combine AWS and Host Bastion powers to secure your infrastructure.
Security doesn't have to be a hurdle—it can be a catalyst for better software and smoother operations. By embracing regular code scanning, you're not just preventing problems; you're empowering your team to innovate confidently.
At NaNLABS, we're passionate about helping you succeed. We're your friendly sidekick, bringing expertise and a top-class partnership to amplify your strengths.
Ready to elevate your security game? Let's connect and co-create extraordinary solutions together.