Skip to content

Commit 404ba25

Browse files
h4x3rotabclaude
andcommitted
ct_monitor: Use HTTP endpoint instead of pRPC for acme-info
The gateway exposes /acme-info as an HTTP endpoint, but ct_monitor was using pRPC which expects Tproxy.* method names due to the gateway's `trim: "Tproxy."` configuration. This caused 405 Method Not Allowed errors. Switch to using the HTTP /acme-info endpoint directly, which returns JSON with hex-encoded public keys. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ed57afa commit 404ba25

3 files changed

Lines changed: 41 additions & 13 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ct_monitor/Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ license.workspace = true
1212
[dependencies]
1313
anyhow.workspace = true
1414
clap = { workspace = true, features = ["derive"] }
15+
hex = { workspace = true, features = ["alloc", "std"] }
1516
hex_fmt.workspace = true
1617
regex.workspace = true
1718
reqwest = { workspace = true, default-features = false, features = ["json", "rustls-tls", "charset", "hickory-dns"] }
@@ -21,6 +22,3 @@ tokio = { workspace = true, features = ["full"] }
2122
tracing.workspace = true
2223
tracing-subscriber.workspace = true
2324
x509-parser.workspace = true
24-
25-
dstack-gateway-rpc.workspace = true
26-
ra-rpc = { workspace = true, default-features = false, features = ["client"] }

ct_monitor/src/main.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
use anyhow::{bail, Context, Result};
66
use clap::Parser;
7-
use dstack_gateway_rpc::gateway_client::GatewayClient;
8-
use ra_rpc::client::RaClient;
97
use regex::Regex;
108
use serde::{Deserialize, Serialize};
119
use std::collections::BTreeSet;
@@ -15,6 +13,13 @@ use x509_parser::prelude::*;
1513

1614
const BASE_URL: &str = "https://crt.sh";
1715

16+
#[derive(Debug, Deserialize)]
17+
struct AcmeInfoResponse {
18+
#[allow(dead_code)]
19+
account_uri: String,
20+
hist_keys: Vec<String>,
21+
}
22+
1823
struct Monitor {
1924
gateway_uri: String,
2025
domain: String,
@@ -48,12 +53,38 @@ impl Monitor {
4853
}
4954

5055
async fn refresh_known_keys(&mut self) -> Result<()> {
51-
info!("fetching known public keys from {}", self.gateway_uri);
52-
// TODO: Use RA-TLS
53-
let tls_no_check = true;
54-
let rpc = GatewayClient::new(RaClient::new(self.gateway_uri.clone(), tls_no_check)?);
55-
let info = rpc.acme_info().await?;
56-
self.known_keys = info.hist_keys.into_iter().collect();
56+
let acme_info_url = format!("{}/acme-info", self.gateway_uri.trim_end_matches('/'));
57+
info!("fetching known public keys from {}", acme_info_url);
58+
59+
let client = reqwest::Client::builder()
60+
.danger_accept_invalid_certs(true) // TODO: Use RA-TLS verification
61+
.build()
62+
.context("failed to build http client")?;
63+
64+
let response = client
65+
.get(&acme_info_url)
66+
.send()
67+
.await
68+
.context("failed to fetch acme-info")?;
69+
70+
if !response.status().is_success() {
71+
bail!(
72+
"failed to fetch acme-info: HTTP {}",
73+
response.status().as_u16()
74+
);
75+
}
76+
77+
let info: AcmeInfoResponse = response
78+
.json()
79+
.await
80+
.context("failed to parse acme-info response")?;
81+
82+
self.known_keys = info
83+
.hist_keys
84+
.into_iter()
85+
.map(|hex_key| hex::decode(&hex_key).context("invalid hex in hist_keys"))
86+
.collect::<Result<BTreeSet<_>>>()?;
87+
5788
info!("got {} known public keys", self.known_keys.len());
5889
for key in self.known_keys.iter() {
5990
debug!(" {}", hex_fmt::HexFmt(key));

0 commit comments

Comments
 (0)