Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion devolutions-agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ tap = "1.0"
tempfile = "3"
tokio-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12", "ring"] }
tokio-stream = "0.1"
tonic = { version = "0.12", features = ["transport"] }
tonic = { version = "0.12", features = ["transport", "tls-native-roots"] }
tracing = "0.1"
url = { version = "2.5", features = ["serde"] }
x509-parser = "0.16"
Expand Down
47 changes: 46 additions & 1 deletion devolutions-agent/src/psu_agent/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl PsuAgent {
}

async fn run_single_connection(&self, shutdown_signal: &mut ShutdownSignal, app_token: &str) -> anyhow::Result<()> {
let endpoint = Endpoint::from_shared(self.server_url.clone())?;
let endpoint = psu_endpoint(&self.server_url)?;
let channel = endpoint
.connect()
.await
Expand Down Expand Up @@ -314,6 +314,11 @@ impl PsuAgent {
}
}

fn psu_endpoint(server_url: &str) -> Result<Endpoint, tonic::transport::Error> {
let _ = rustls::crypto::ring::default_provider().install_default();
Endpoint::new(server_url.to_owned())
}

pub(crate) fn agent_message(agent_id: &str, connection_id: &str, payload: AgentPayload) -> AgentMessage {
AgentMessage {
request_id: Uuid::new_v4().simple().to_string(),
Expand Down Expand Up @@ -432,8 +437,48 @@ async fn get_powershell_version(executable: &str) -> String {

#[cfg(test)]
mod tests {
use tokio::io::AsyncReadExt as _;
use tokio::net::TcpListener;

use super::*;

async fn first_connection_byte(scheme: &str) -> u8 {
let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind endpoint");
let url = format!("{scheme}://{}", listener.local_addr().expect("listener address"));
let endpoint = psu_endpoint(&url).expect("create endpoint");
let connection = tokio::spawn(async move { endpoint.connect().await });

let first_byte = tokio::time::timeout(Duration::from_secs(5), async {
let (mut stream, _) = listener.accept().await.expect("accept connection");
let mut byte = [0];
stream.read_exact(&mut byte).await.expect("read client preface");
byte[0]
})
.await
.expect("client did not connect");

connection.abort();
first_byte
}

#[tokio::test]
async fn https_endpoint_starts_tls_handshake() {
assert_eq!(
first_connection_byte("https").await,
0x16,
"HTTPS connection must start with a TLS ClientHello"
);
}

#[tokio::test]
async fn http_endpoint_starts_http2_preface() {
assert_eq!(
first_connection_byte("http").await,
b'P',
"HTTP connection must start with the HTTP/2 preface"
);
}

#[test]
fn connect_request_omits_authorization_without_app_token() {
let request = connect_request((), None).expect("create request");
Expand Down
2 changes: 2 additions & 0 deletions package/AgentLinux/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ docker run --rm `
devolutions/devolutions-agent:latest
```

For HTTPS, set `PSU_SERVER_URL` to an `https://` URL and trust the PSU server certificate in the container's system certificate store.

| Environment variable | Default |
| --- | --- |
| `PSU_SERVER_URL` | Empty |
Expand Down
Loading