How do I use the results of an SSM port forwarding session started with ruby?

1k Views Asked by At

I'm having trouble reconciling the differences between using the aws cli and the ruby sdk to make ssm connections to an instance. For example, if I try using the command like like this:

aws ssm start-session \
  --target 'i-abc123' \
  --document-name AWS-StartPortForwardingSession \
  --parameters '{
    "portNumber": ["3000"], 
    "localPortNumber": ["13000"]
  }'
Starting session with SessionId: username-def456
Port 13000 opened for sessionId username-def456.
Waiting for connections...

Connection accepted for session [username-def456]

the tool will pause as it opens up a port forwarding session from port 3000 on the destination instance to port 13000 on my local machine. I can then open up a web browser on my machine and point it at http://localhost:13000 to browse around an app running on the remote instance. Also, I can look at the AWS console UI and see that there's an active session until I Ctrl-C

The trouble I'm having is when I try to use the ruby sdk to do the same thing:

result = ssm.start_session(
  target: 'i-abc123',  
  document_name: 'AWS-StartPortForwardingSession',  
  parameters: {  
    'portNumber' => %w[3000],    
    'localPortNumber' => %w[13000]    
  }    
)  

The result object is a struct that looks like the following:

=> #<struct Aws::SSM::Types::StartSessionResponse
 session_id="username-def456",
 token_value="...",
 stream_url="wss://ssmmessages.us-east-1.amazonaws.com/v1/data-channel/username-def456? 
 role=publish_subscribe">

Again, I can see in the console UI that there is an active session. However, if I try to browse to http://localhost:13000 on my machine, the browser can't reach anything. How do I use the resulting stream url and token to actually create a connection to the ec2 instance?

additional details:

  • core gem version for the ruby sdk: 3.109.2
  • aws cli version - aws-cli/2.1.16
  • aws ssm agent version - amazon-ssm-agent-3.0.356.0-1.x86_64
1

There are 1 best solutions below

1
On

What you get back from the API is a reference to a web socket. So you either need to create your own web socket to local listener proxy or use the session-manager-plugin as the aws cli utility does.

I recently figured out how to use the session-manager-plugin, the following snippet is Python but should be obvious enough to figure it out.

def start_aws_ssm_plugin(self, create_session_response, parameters, profile, region):
    print('start_aws_ssm_plugin() called: ' + str( create_session_response))

    arg0 = '"' + self.config.get_ssm_plugin() + '"'
    arg1 = '"' + str(create_session_response).replace('\'', '\\"') + '"'
    arg2 = region
    arg3 = 'StartSession'
    arg4 = profile
    arg5 = '"' + str(parameters).replace('\'', '\\"') + '"'
    arg6 = 'https://ssm.{region}.amazonaws.com'.format(region=region)

    command = arg0 + ' ' + arg1 + ' ' + arg2 + ' ' + arg3 + ' ' + arg4 + ' ' + arg5 + ' ' + arg6

    print(command)
    # print('session-manager-plugin', arg1, arg2, arg3, arg4, arg5, arg6)

    pid = subprocess.Popen(command).pid
    return pid

# end def

(And yes, this was just a quick and dirty prototype.;))