rustwebsocketaws-sdkrust-tokioaws-ssm

How do I create a terminal session from the WSS url that I got from `aws-sdk-ssm` client in Rust?


I want to connect to my ec2 instance using aws ssm sdk for rust. What is the best way to create an interactive terminal session? Here is the following code I am using to create an ssm session:

    pub async fn create_ssh_session(&self, instance_id: &str) -> Result<()> {
        let output = self
            .client
            .start_session()
            .document_name("SSM-SessionManagerRunShell")
            .target(instance_id)
            .send()
            .await?;

            let wss_url = output.stream_url().unwrap();
            let (mut ws_stream, response) = tokio_tungstenite::connect_async(Url::parse(wss_url)?).await?;

            // Print response to confirm successful connection
            println!("Connected: {}", response.status());

        
            let output = self
            .client
            .terminate_session()
            .session_id(output.session_id().unwrap())
            .send()
            .await?;
        // println!("{:#?}", output);
        Ok(())
    }

I have tried to connect using tokio tungstenite to connect to the WSS url but I am not sure if this is the best way.

EDIT: when I try to connect, it gives me status code 101 (switching protocols) what does this mean and after starting session with ssm I receive wss_url and the token. According to the documentation, it says the token is used to authenticate connection with managed node. I want to know how I can do so when creating the stream.


Solution

  • Instead of communicating directly with the ssm agent on the instance, I decided it would be simpler to interact with the session-manager-plugin as suggested by @john. There is no solid reference that I could find in regards to using session-manager-plugin from the command line and I referred to this question here.

    here is the basic workflow on how one can spawn a session using the aws sdk for rust with session-manager-plugin:

    pub async fn create_ssh_session(&self, instance_id: &str) -> Result<()> {
            // start session get session_id, token_value and stream_url
            let output = self
                .client
                .start_session()
                .document_name("SSM-SessionManagerRunShell")
                .target(instance_id)
                .send()
                .await?;
            
            // create ssm plugin json message
            let response = ResponseJson {
                SessionId: output.session_id().unwrap().to_string(),
                TokenValue: output.token_value().unwrap().to_string(), // Assuming `token` is defined elsewhere
                StreamUrl: output.stream_url().unwrap().to_string(),
            };
    
            // commenting code for reference 
            // let template =r#"{"Target" : "{instance_id}","DocumentName": "AWS-StartPortForwardingSession","Parameters" : {"portNumber": [22],"localPortNumber": [3232] }}"#;
            // let ssm_plugin_document = json!(template.replace("{instance_id}", instance_id.into()));
            // let plugin_string = serde_json::to_string(&ssm_plugin_document)?;
            let response_string = serde_json::to_string(&response)?;
            let mut session_manager_plugin = Command::new("session-manager-plugin");
            let run_command_output = session_manager_plugin
                .args([
                    response_string,
                    "ap-southeast-2".into(),
                    "StartSession".into(),
                    "https://ssm.ap-southeast-2.amazonaws.com/".into(),
                ])
                .spawn()?;
            let result = run_command_output.wait_with_output()?;
    
            let output = self
                .client
                .terminate_session()
                .session_id(output.session_id().unwrap())
                .send()
                .await?;
            Ok(())
        }
    

    I am simply spawning session-manager-plugin as a process with the right arguments using the SSM-SessionManagerRunShell document.