Secure RDS Access Without Bastion Hosts: Using AWS SSM Session Manager
Accessing databases securely in AWS environments has traditionally relied on bastion hosts and IP whitelisting. While effective, this approach comes with operational friction, security risks, and a heavy dependency on DevOps teams for IP management. This blog post introduces a modern, secure alternative that Trestle adopted recently: using AWS Systems Manager Session Manager for port-forwarded access to Amazon RDS — no public IPs or bastions required.
Why Drop the Bastion Host?
Bastion hosts:
- Require manual IP whitelisting
- Are potential entry points for attackers
- Need monitoring, patching, and auditing
Instead, SSM Session Manager:
- Uses IAM-based access (no SSH keys)
- Works over HTTPS
- Logs activity via CloudTrail
- Supports port forwarding to access private services like RDS
Solution Architecture
- A lightweight EC2 instance (no public IP) is placed in the same VPC/subnet as your RDS.
- IAM Identity Center (SSO) is used to authenticate developers.
- Developers start SSM sessions with port forwarding.
- A Lambda function sends Slack alerts on new sessions and terminations.
Prerequisites
- IAM Identity Center (SSO) enabled
- SSO permission set allows ssm:StartSession
- A tagged EC2 instance with:
- AmazonSSMManagedInstanceCore role attached
- Internet/NAT Gateway access (or VPC endpoints, optional)
- PostgreSQL client (psql) installed
- Session Manager Plugin installed:
brew install --cask session-manager-pluginHow It Works (Developer Workflow)
aws ssm start-session \
--region us-west-2 \
--target i-0abc123456789def0 \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters host="rds-instance.internal",portNumber="5432",localPortNumber="5432"
Then connect using:
psql -h localhost -p 5432 -U <user> -d <dbname>Slack Alert Integration
A Lambda function listens for both StartSession and TerminateSession events via CloudTrail, and sends alerts to Slack.
Example: Session Started
:rotating_light: SSM Session Started
• User: arn:aws:iam::123:user/dev
• Source IP: 192.0.2.55
• Instance: i-0abc123
• Region: us-west-2
• Time: 2025-06-17T11:22Z
• Document: AWS-StartPortForwardingSessionToRemoteHost
• Remote Host: rds-instance.internalExample: Session Terminated
:white_check_mark: SSM Session Terminated
• User: arn:aws:iam::123:user/dev
• Session ID: ssm-session-1234567890abcdef
• Time: 2025-06-17T12:10ZLambda Setup for Alerts
- Create an AWS Lambda function in Python or Node.js.
- Subscribe it to a CloudWatch Event Rule filtering for:
- ssm.amazonaws.com events with StartSession or TerminateSession
- Send alert to Slack via webhook using requests or axios
Optional Enhancements:
- Include MFA status from mfaAuthenticated
- Parse parameters.host from StartSession for alert context
- Track sourceIPAddress from CloudTrail event
IAM Policy (Scoped Access)
{
"Effect": "Allow",
"Action": "ssm:StartSession",
"Resource": [
"arn:aws:ec2:us-west-2:123456789012:instance/i-0abc123456789def0",
"arn:aws:ssm:us-west-2::document/AWS-StartPortForwardingSessionToRemoteHost"
]
}Alternative to saml2aws
While tools like saml2aws are popular in some legacy setups, we recommend IAM Identity Center because:
- Officially supported by AWS
- MFA is centrally enforced
- Sessions are auditable
- Easier Slack/CloudTrail integration
Optional Enhancements
- Alert on TerminateSession events
- Include mfaAuthenticated: false flag in alerts
- Auto-tag sessions for traceability
- Store session metadata in DynamoDB for audit history
Summary
By replacing bastion hosts with SSM port forwarding and Slack alerts, you:
- Eliminate manual IP whitelisting
- Improve security posture
- Enable faster, self-service developer access
- Maintain full auditability
Welcome to the future of secure, ephemeral cloud database access — no bastions required.