<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>SSM on HabibiOps</title><link>https://habibiops.com/tags/ssm/</link><description>Recent content in SSM on HabibiOps</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Thu, 30 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://habibiops.com/tags/ssm/index.xml" rel="self" type="application/rss+xml"/><item><title>AWS Systems Manager Session Manager Port Forwarding</title><link>https://habibiops.com/p/aws-systems-manager-session-manage-port-forwarding/</link><pubDate>Thu, 30 Apr 2026 00:00:00 +0000</pubDate><guid>https://habibiops.com/p/aws-systems-manager-session-manage-port-forwarding/</guid><description>&lt;img src="https://habibiops.com/p/aws-systems-manager-session-manage-port-forwarding/assets/ssm-cover.drawio.svg" alt="Featured image of post AWS Systems Manager Session Manager Port Forwarding" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;In the &lt;a class="link" href="https://habibiops.com/p/aws-client-vpn-endpoint-setup/" target="_blank" rel="noopener"
&gt;previous post&lt;/a&gt;, we discussed how to use the AWS VPN
client to connect to private subnets in a VPC. We used Entra ID to perform federated user-based authentication. This
technique is useful for enterprises using federated authentication, but there is another way to achieve the same result
using AWS Systems Manager Session Manager (SSM) and port forwarding.&lt;/p&gt;
&lt;h2 id="architecture"&gt;Architecture
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://habibiops.com/p/aws-systems-manager-session-manage-port-forwarding/assets/ssm.svg"
loading="lazy"
alt="SSM Port Forwarding to DB"
&gt;&lt;/p&gt;
&lt;p&gt;The diagram above shows the main components used for the SSM port forwarding session setup. The diagram shows the
following components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The bastion host EC2 instance that is located in the private subnet and that is used to initiate the port forwarding
session with the attached IAM role&lt;/li&gt;
&lt;li&gt;The EC2 instance security group that allows inbound traffic only from the VPC CIDR range&lt;/li&gt;
&lt;li&gt;The RDS instance in the private subnet that will be used as the target for the port forwarding session&lt;/li&gt;
&lt;li&gt;The RDS security group that allows inbound traffic on the DB port (5432) only from the bastion host EC2 instance&lt;/li&gt;
&lt;li&gt;The SSM session manager document that will be used to initiate the port forwarding session&lt;/li&gt;
&lt;li&gt;The NAT gateway that will be used to route traffic from the private subnet to the internet&lt;/li&gt;
&lt;li&gt;The development local machine that will be used to connect to the RDS instance&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="rds-db-connection-with-ssm-port-forwarding"&gt;RDS DB Connection with SSM Port Forwarding
&lt;/h2&gt;&lt;p&gt;The following parameters are required for the port forwarding session:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AWS Region (e.g. eu-central-1)&lt;/li&gt;
&lt;li&gt;EC2 instance id (e.g. i-04e29d6b82ca52fbc)&lt;/li&gt;
&lt;li&gt;RDS host (e.g. mytestdb-instance-1.clzjs8sy98st.eu-central-1.rds.amazonaws.com)&lt;/li&gt;
&lt;li&gt;RDS port (e.g. 5432)&lt;/li&gt;
&lt;li&gt;RDS username (e.g. postgres)&lt;/li&gt;
&lt;li&gt;RDS password (e.g. arn:aws:secretsmanager:eu-central-1:123456789012:secret:rds!)&lt;/li&gt;
&lt;li&gt;RDS cluster identifier (e.g. cluster-506ac9d4-c6f0-5421-911f-85dec405f14a-A12ncL)&lt;/li&gt;
&lt;li&gt;RDS DB name (e.g. mytestdb)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Install
the &lt;a class="link" href="https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html" target="_blank" rel="noopener"
&gt;session manager aws cli plugin&lt;/a&gt;
locally and start a new session. Keep the session running and execute further commands from a new terminal session:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ aws ssm start-session --target i-04e29d6b82ca52fbc --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters &lt;span class="s1"&gt;&amp;#39;{&amp;#34;portNumber&amp;#34;:[&amp;#34;5432&amp;#34;],&amp;#34;localPortNumber&amp;#34;:[&amp;#34;1053&amp;#34;],&amp;#34;host&amp;#34;:[&amp;#34;mytestdb-instance-1.clzjs8sy98st.eu-central-1.rds.amazonaws.com&amp;#34;]}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Starting session with SessionId: 429fec6e-29cc-422b-892f-9b8a6973c131-a5xit52zpidhlt7bb95rglflzy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Port &lt;span class="m"&gt;1053&lt;/span&gt; opened &lt;span class="k"&gt;for&lt;/span&gt; sessionId 429fec6e-29cc-422b-892f-9b8a6973c131-a5xit52zpidhlt7bb95rglflzy.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Waiting &lt;span class="k"&gt;for&lt;/span&gt; connections...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Export the correct AWS region and RDS parameters in a new terminal session to connect from a local client:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;eu-central-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;RDS_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;RDS_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;5432&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;RDS_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;RDS_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;mytestdb&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;PGPASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;aws secretsmanager get-secret-value --secret-id &lt;span class="s1"&gt;&amp;#39;arn:aws:secretsmanager:eu-central-1:123456789012:secret:rds!cluster-506ac9d4-c6f0-5421-911f-85dec405f14a-A12ncL&amp;#39;&lt;/span&gt; --query SecretString --output text &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s1"&gt;&amp;#39;.password&amp;#39;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;PGPASSWORD&lt;/code&gt; environment variable is automatically picked up by &lt;code&gt;psql&lt;/code&gt; when connecting to a PostgreSQL server.
Connect using &lt;code&gt;psql&lt;/code&gt; to &lt;code&gt;localhost&lt;/code&gt; and port &lt;code&gt;5432&lt;/code&gt; that match the forwarded session that was initiated:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ psql -h &lt;span class="nv"&gt;$RDS_HOST&lt;/span&gt; -p &lt;span class="nv"&gt;$RDS_PORT&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;dbname=&lt;/span&gt;&lt;span class="nv"&gt;$RDS_DB&lt;/span&gt;&lt;span class="s2"&gt; user=&lt;/span&gt;&lt;span class="nv"&gt;$RDS_USERNAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;psql-18 &lt;span class="o"&gt;(&lt;/span&gt;18.3 &lt;span class="o"&gt;(&lt;/span&gt;Homebrew&lt;span class="o"&gt;)&lt;/span&gt;, server 17.7&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SSL connection &lt;span class="o"&gt;(&lt;/span&gt;protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off, ALPN: postgresql&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Type &lt;span class="s2"&gt;&amp;#34;help&amp;#34;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; help.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;mytestdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt; &lt;span class="se"&gt;\d&lt;/span&gt;t
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; List of tables
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Schema &lt;span class="p"&gt;|&lt;/span&gt; Name &lt;span class="p"&gt;|&lt;/span&gt; Type &lt;span class="p"&gt;|&lt;/span&gt; Owner
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--------+-------------+-------+----------
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;public &lt;span class="p"&gt;|&lt;/span&gt; dummy_table &lt;span class="p"&gt;|&lt;/span&gt; table &lt;span class="p"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; row&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;mytestdb&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The connection was established, and the describe table command shows the proper output.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;This post demonstrates how to use AWS Systems Manager Session Manager to establish a port forwarding session to a remote
DB host. This is useful for scenarios where you need to connect to a remote DB instance from a local development machine
for debugging or testing purposes. No ssh connection or public internet-facing endpoints are required for this scenario
which makes it a practical solution with minimal overhead.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://aws.amazon.com/blogs/mt/use-port-forwarding-in-aws-systems-manager-session-manager-to-connect-to-remote-hosts/" target="_blank" rel="noopener"
&gt;https://aws.amazon.com/blogs/mt/use-port-forwarding-in-aws-systems-manager-session-manager-to-connect-to-remote-hosts/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>