The SSH Key Dilemma
You've been there. You need to access an EC2 instance immediately, but the SSH keys are nowhere to be found. Maybe they were lost during a team handover, never shared, or the person who created them has left the company. Traditional SSH access feels impossible.
Meanwhile, the production issue waits for no one. AWS Systems Manager (SSM) Session Manager provides a secure way to access EC2 instances without needing SSH keys or open inbound ports. It's like having a master key that works across all your instances, with full audit logging and centralized control.
Solutions
Option 1: EC2 Instance Connect (Limited)
The quick fix that often causes more problems later. You generate a temporary SSH key through the AWS console, connect to your instance, and hope you remember to save the private key.
Problems with this approach:
- No audit trail of who accessed what
- Temporary keys become permanent solutions
- Hard to rotate keys across multiple instances
- Security risk if keys aren't properly secured
Option 2: Use a Bastion Host
The traditional "jump server" approach. You SSH into a hardened bastion host, then from there to your production instances. This method has been the standard practice for decades in enterprise environments.
How it works:
# First hop: SSH to bastion
ssh -i bastion-key.pem user@bastion.company.com
# Second hop: SSH to production instance from bastion
ssh -i production-key.pem user@10.0.1.100
Problems with this approach:
Single Point of Failure
- If the bastion host goes down, all access is lost
- Network issues affecting the bastion impact entire infrastructure
- Maintenance windows require complete access shutdown
- DDoS attacks on bastion can cripple your entire operation
Complex Key Management Managing SSH keys in a bastion setup quickly becomes overwhelming. You need separate keys for both the bastion and production instances, and rotating those keys across multiple servers turns into a painful, error-prone process. Team members are forced to juggle multiple key files, increasing the risk of mismanagement or leaks. When keys are lost, it often requires a full re-provisioning effort, which can be time-consuming and disruptive. On top of that, there’s no centralized way to instantly revoke access, making it harder to enforce security controls effectively.
Additional Infrastructure Costs Running a bastion host introduces extra infrastructure overhead that quickly adds up. It requires its own EC2 instance (often at least a t3.medium), along with additional EBS volumes for logging and storage. You also need to implement enhanced monitoring and security specifically for the bastion, since it becomes a critical entry point into your systems. To ensure availability, you may need a load balancer or Elastic IP, and on top of that, you must plan for backup and disaster recovery. Altogether, this turns what should be a simple access mechanism into a costly and maintenance-heavy component.
Still Requires SSH Key Management
- You haven't eliminated the core problem
- SSH keys still exist and can be lost or compromised
- No audit trail of who accessed what, when
- SSH port (22) must remain open, creating attack surface
- Manual process for onboarding/offboarding team members
Real-world bastion failures I've seen:
- Company A: Bastion host corrupted during AWS outage, entire engineering team locked out for 6 hours
- Company B: Bastion SSH keys accidentally committed to GitHub, requiring emergency key rotation across 50+ instances
- Company C: Bastion became the target of brute force attacks, costing $2,000 in unexpected data transfer fees
- Company D: Junior engineer accidentally terminated bastion instance during cleanup, production access lost for 3 days
The operational overhead:
- Regular bastion security patches and updates
- Log rotation and storage management
- Monitoring for unauthorized access attempts
- Backup and restore procedures
- Compliance audits specifically for the bastion
While bastion hosts work, they're essentially putting a bandage on the fundamental problem: SSH key management doesn't scale and creates security risks.
Option 3: AWS Systems Manager Session Manager (Recommended)
Session Manager is AWS's answer to secure, scalable access management. It eliminates SSH keys entirely while providing better security and logging.
Why Session Manager is the Best Option
No SSH Keys or Bastion Required
Session Manager uses the existing SSM Agent on your EC2 instances, so no additional software installation is needed. No open ports, no bastion hosts, no SSH key juggling.
Enterprise-Grade Security
Every session is logged to CloudTrail and can be audited later. You can terminate sessions instantly, revoke access, and enforce time-based access policies.
Centralized Access Management
Manage who can access which instances from one place. Perfect for teams with compliance requirements or when contractors need temporary access.
Step-by-Step: Enable Session Manager Access
Step 1: Verify Instance Registration
First, ensure your EC2 instance is already registered with Session Manager:
- Go to AWS Systems Manager Console
- Navigate to Session Manager in the left sidebar
- Click Start session and select your target instance
If your instance appears, you can connect directly. If not, follow the next steps.
Step 2: Create IAM Policy for Session Manager
Session Manager needs specific IAM permissions to function. Create a policy that allows the necessary actions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel",
"ssm:UpdateInstanceInformation"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3:::your-bucket-name/s3-prefix/*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetEncryptionConfiguration"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "arn:aws:kms:your-region:your-account-id:key/your-key-id"
}
]
}
Policy Notes:
- Replace
your-bucket-nameands3-prefixwith your actual values - The KMS resource should match your actual key ARN
- This policy covers session management, logging, and S3 access
Step 3: Create IAM Role for EC2 Access
Create an IAM role that trusts Session Manager:
- Go to IAM Console → Policies → Create Policy
- Select JSON tab and paste the policy from Step 2
- Name the policy something like
EC2SessionManagerRole - Select AWS service as trusted entity → EC2
- Click Next: Tags (optional) → Create Policy
Step 4: Attach IAM Role to EC2 Instance
- Go to EC2 Console → select your target instance
- Choose Actions → Security → Modify IAM Role
- Select the role you just created (
EC2SessionManagerRole) - Click Update IAM Role
Step 5: Connect via Session Manager
Now for the moment of truth:
- Go to AWS Systems Manager → Session Manager
- Wait a few minutes for instances to appear (they need the SSM Agent)
- Click Start session and select your instance
- Click Connect
You now have shell access to your EC2 instance - no SSH keys required.
Advanced Session Manager Features
Port Forwarding
Need to access a web service running on your instance? Session Manager supports port forwarding:
# Start session with port forwarding
aws ssm start-session \
--target i-1234567890abcdef0 \
--document-name "MySession" \
--region us-east-1 \
--port-forwarding 8080
File Transfer
Need to upload or download files? Use Session Manager's built-in file transfer:
# Upload file to instance
aws ssm start-session \
--target i-1234567890abcdef0 \
--document-name "FileTransfer" \
--resource 'arn:aws:s3:::my-bucket/path/to/file.txt'
Session Logging
Every Session Manager action is logged to CloudTrail:
{
"eventSource": "ssm.amazonaws.com",
"eventName": "StartSession",
"requestParameters": {
"target": "i-1234567890abcdef0",
"documentName": "MySession"
},
"responseElements": {
"sessionId": "i-1234567890abcdef0-1a2b3c4d5e6f7g8h9"
}
}
Troubleshooting Common Issues
Instance Not Appearing in Session Manager
Causes:
- SSM Agent not installed or running
- Instance doesn't have internet connectivity
- IAM role not properly attached
- Wrong region selected
Solutions:
- Verify SSM Agent status:
sudo systemctl status amazon-ssm-agent - Check instance profile and region configuration
- Ensure IAM role attachment is correct
- Wait 5-10 minutes after role changes
Connection Timeouts
Causes:
- Session Manager idle timeout (default 60 minutes)
- Network connectivity issues
- Instance under heavy load
Solutions:
- Use
--max-durationto extend session time - Check instance performance and network latency
- Use AWS CLI instead of console for better reliability
Permission Denied Errors
Common error messages:
- "User is not authorized to perform: ssm:StartSession"
- "AccessDeniedException" when starting sessions
Solutions:
- Verify IAM policy syntax and attachments
- Check for explicit deny statements in other policies
- Ensure the user/role has necessary permissions
Security Best Practices
Principle of Least Privilege
Only grant the minimum permissions necessary for Session Manager to work:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:StartSession"
],
"Resource": "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0"
}
]
}
Session Duration Limits
Configure appropriate session timeouts based on use case:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:StartSession"
],
"Resource": "arn:aws:ec2:*:*:*",
"Condition": {
"DateGreaterThan": {
"aws:CurrentTime": "2024-01-01T00:00:00Z",
"aws:RequestedSessionDuration": "3600"
}
}
}
]
}
This limits sessions to 1 hour for regular users and 15 minutes for elevated access.
Audit and Compliance
Every session creates a CloudTrail event:
- Who accessed which instance
- When the session started and ended
- What actions were performed
- Session duration and termination reason
This provides complete auditability for compliance requirements like SOC 2, ISO 27001, and internal security policies.
Comparison: Session Manager vs Traditional SSH
| Feature | SSH Keys | Session Manager |
|---|---|---|
| Security | Keys can be lost/copied | IAM-based, no keys stored |
| Audit Trail | Manual logging required | Automatic CloudTrail logging |
| Access Control | Manual key rotation | Instant revocation possible |
| Port Requirements | Open SSH port needed | No open ports required |
| Scalability | Complex key management | Centralized access control |
| Cost | Bastion host overhead | Included with AWS account |
| Compliance | Hard to audit | Built-in compliance logging |
Real-World Implementation
Here's how a typical enterprise implements Session Manager:
Architecture Overview
┌─────────────────┐
│ AWS Account │
│ │
│ ┌─────────────┴─────────────┐
│ │ Production │ Staging │
│ │ VPC │ VPC │
│ │ ┌─────┐ │ ┌─────┐ │
│ │ │ EC2 │ │ │ EC2 │ │
│ │ │ Instances│ │ │ Instances│ │
│ │ └─────┘ │ └─────┘ │
│ │ │ │
│ └─────────────┴─────────────┘
│ │
│ Session Manager │
│ (Central Access) │
└─────────────────┘
Implementation Steps
- Standardize AMIs with SSM Agent pre-installed
- Create IAM roles for different environments (dev, staging, prod)
- Implement session policies with time-based access
- Train teams on Session Manager usage
- Monitor access through CloudTrail dashboards
Results Achieved
- 95% reduction in SSH key management overhead
- 100% auditability for all access attempts
- Zero bastion host costs
- Instant access revocation for terminated employees
- Compliance with SOC 2 and ISO 27001
Conclusion
AWS Session Manager transforms how teams access EC2 instances. It eliminates the security risks of SSH key management while providing better control, auditability, and scalability.
The next time you're scrambling for SSH keys, remember: Session Manager isn't just a convenience feature—it's a security best practice.
Start using it today, and make SSH key loss a problem of the past.
Reference: AWS Systems Manager User Guide