You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Rust的AWS SSM SDK从WSS URL创建交互式终端会话并认证?

Rust版AWS SSM SDK创建EC2交互式终端会话指南

一、tokio_tungstenite的适用性及最佳实践

tokio_tungstenite是Rust生态中适配Tokio异步 runtime的WebSocket客户端,完全适合用于SSM会话的WSS连接——AWS SSM会话本身就是基于WebSocket协议实现终端数据双向传输,和你使用的异步版AWS SSM SDK天然兼容,这是合理的技术选型。

你当前的代码存在核心问题:建立WebSocket连接后立即终止会话,无法实现交互式终端功能。要完成完整的交互式会话,需要同时处理两个异步任务:

  • 读取本地终端输入并发送到WebSocket流
  • 接收WebSocket返回的SSM实例输出并打印到本地终端

以下是优化后的代码示例,包含认证处理、双向消息传输及会话生命周期管理:

use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio_tungstenite::tungstenite::Message;
use aws_sdk_ssm::Client;
use std::error::Error;

pub async fn create_ssh_session(client: &Client, instance_id: &str) -> Result<(), Box<dyn Error>> {
    // 启动SSM会话
    let session_output = client
        .start_session()
        .document_name("SSM-SessionManagerRunShell")
        .target(instance_id)
        .send()
        .await?;

    let wss_url = session_output.stream_url().ok_or("Failed to get stream URL")?;
    let session_token = session_output.token().ok_or("Failed to get session token")?;
    let session_id = session_output.session_id().ok_or("Failed to get session ID")?;

    // 构建带认证头的WebSocket请求
    let url = url::Url::parse(wss_url)?;
    let request = http::Request::get(url)
        .header("X-Aws-Ssm-Session-Token", session_token)
        .body(())?;

    // 建立WebSocket连接
    let (mut ws_stream, response) = tokio_tungstenite::connect_async(request).await?;
    println!("Connected: {}", response.status());

    // 任务1:读取本地终端输入并发送到SSM会话
    let mut stdin = BufReader::new(tokio::io::stdin()).lines();
    let mut ws_sender = ws_stream.split().0;
    let input_task = tokio::spawn(async move {
        while let Some(line) = stdin.next_line().await.unwrap() {
            if let Err(e) = ws_sender.send(Message::Text(format!("{}\n", line))).await {
                eprintln!("Failed to send message: {}", e);
                break;
            }
        }
    });

    // 任务2:接收SSM会话输出并打印到本地终端
    let mut ws_receiver = ws_stream.split().1;
    let output_task = tokio::spawn(async move {
        while let Some(msg) = ws_receiver.next().await {
            match msg {
                Ok(Message::Text(text)) => print!("{}", text),
                Ok(Message::Binary(data)) => print!("{}", String::from_utf8_lossy(&data)),
                Err(e) => {
                    eprintln!("Failed to receive message: {}", e);
                    break;
                }
                _ => {},
            }
        }
    });

    // 等待任一任务结束(比如用户退出输入)
    tokio::select! {
        _ = input_task => {},
        _ = output_task => {},
    }

    // 终止SSM会话
    client
        .terminate_session()
        .session_id(session_id)
        .send()
        .await?;

    Ok(())
}

二、状态码101(Switching Protocols)的含义

101是HTTP协议的正常响应状态码,代表服务器同意客户端的协议切换请求。在WebSocket连接流程中:

  1. 客户端先发送HTTP请求,携带Upgrade: websocket和Connection: Upgrade头,请求从HTTP协议切换到WebSocket协议
  2. 服务器返回101响应,确认协议切换完成
  3. 后续通信不再使用HTTP格式,改用WebSocket帧传输数据

这个状态码说明你的WebSocket握手已经成功,无需担心。

三、Session Token的认证方式

SSM返回的Session Token是验证会话合法性的凭证,需要在WebSocket握手请求中通过自定义请求头传递:

  • 头名称:X-Aws-Ssm-Session-Token
  • 头值:start_session接口返回的token字段值

在代码中,你需要通过http::Request构建自定义请求(而非直接传入URL),将Token添加到请求头中,如上述示例代码所示。这样SSM服务端就能验证你的会话权限,允许建立数据流连接。

内容的提问来源于stack exchange,提问作者Souldiv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 22:22:43