Провижининг ноды: пробрасывает port/decoy_host/auth в SSH-команду запуска
init_node.sh раньше запускал образ вообще без CLI-аргументов — все провижинингованные ноды молча использовали дефолты и не требовали авторизации, несмотря на то что admin-панель как будто настраивала per-node SNI/порт. Заодно убирает захардкоженный IP control plane. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -86,11 +86,24 @@ impl NodeService {
|
||||
ssh_password: &str,
|
||||
) -> Result<VpnNode, AppError> {
|
||||
let node = self.repo.add_vpn_node_pending(payload).await?;
|
||||
self.spawn_provisioning(node.id, node.ip_address.clone(), ssh_password.to_string());
|
||||
self.spawn_provisioning(
|
||||
node.id,
|
||||
node.ip_address.clone(),
|
||||
ssh_password.to_string(),
|
||||
node.port,
|
||||
node.sni_domain.clone(),
|
||||
);
|
||||
Ok(node)
|
||||
}
|
||||
|
||||
fn spawn_provisioning(&self, node_id: Uuid, ip_address: String, password: String) {
|
||||
fn spawn_provisioning(
|
||||
&self,
|
||||
node_id: Uuid,
|
||||
ip_address: String,
|
||||
password: String,
|
||||
port: i32,
|
||||
sni_domain: Option<String>,
|
||||
) {
|
||||
let repo = self.repo.clone();
|
||||
let semaphore = self.deploy_semaphore.clone();
|
||||
|
||||
@@ -101,7 +114,7 @@ impl NodeService {
|
||||
};
|
||||
|
||||
let provision_result = tokio::task::spawn_blocking(move || {
|
||||
Self::provision_node_via_ssh(&ip_address, &password)
|
||||
Self::provision_node_via_ssh(&ip_address, &password, port, sni_domain.as_deref())
|
||||
})
|
||||
.await;
|
||||
|
||||
@@ -123,7 +136,12 @@ impl NodeService {
|
||||
});
|
||||
}
|
||||
|
||||
fn provision_node_via_ssh(ip: &str, password: &str) -> Result<(), AppError> {
|
||||
fn provision_node_via_ssh(
|
||||
ip: &str,
|
||||
password: &str,
|
||||
port: i32,
|
||||
sni_domain: Option<&str>,
|
||||
) -> Result<(), AppError> {
|
||||
use std::fs;
|
||||
|
||||
// 1. Просто считываем уже гарантированно созданный на старте сервера ключ
|
||||
@@ -138,6 +156,25 @@ impl NodeService {
|
||||
let gh_token = std::env::var("GHCR_TOKEN").map_err(|_| {
|
||||
AppError::Internal("GHCR_TOKEN не задан — провижининг ноды невозможен".into())
|
||||
})?;
|
||||
// Секрет и публичный URL этого же бэкенда — нода должна ходить именно
|
||||
// сюда для проверки токенов/лимитов (--require-auth), а не работать
|
||||
// без авторизации, как было раньше при отсутствии этих переменных.
|
||||
let proxy_internal_secret = std::env::var("PROXY_INTERNAL_SECRET").map_err(|_| {
|
||||
AppError::Internal(
|
||||
"PROXY_INTERNAL_SECRET не задан — провижининг ноды с --require-auth невозможен"
|
||||
.into(),
|
||||
)
|
||||
})?;
|
||||
let backend_url = std::env::var("WEB_APP_BASE_URL").map_err(|_| {
|
||||
AppError::Internal("WEB_APP_BASE_URL не задан — провижининг ноды невозможен".into())
|
||||
})?;
|
||||
// Домен-декой конкретно этой ноды — если админ не указал при добавлении,
|
||||
// используем тот же дефолт, что и сам netrunner-proxy без --decoy-host
|
||||
// (netrunner_core::net::DEFAULT_DECOY_HOST в том, отдельном репозитории —
|
||||
// здесь недоступен как зависимость, поэтому продублирован явно).
|
||||
const DEFAULT_DECOY_HOST: &str = "www.debian.org";
|
||||
let sni_domain = sni_domain.unwrap_or(DEFAULT_DECOY_HOST);
|
||||
|
||||
// Если скрипт инициализации отсутствует — жёстко падаем, а не деплоим
|
||||
// полуживую ноду заглушкой `echo`.
|
||||
let init_script = fs::read_to_string("templates/init_node.sh").map_err(|e| {
|
||||
@@ -161,8 +198,8 @@ impl NodeService {
|
||||
);
|
||||
|
||||
let full_command = format!(
|
||||
"NODE_IP='{}' GH_TOKEN='{}'\n{}\n{}",
|
||||
ip, gh_token, init_script, harden_script
|
||||
"NODE_IP='{}' GH_TOKEN='{}' NODE_PORT='{}' SNI_DOMAIN='{}' BACKEND_URL='{}' PROXY_INTERNAL_SECRET='{}'\n{}\n{}",
|
||||
ip, gh_token, port, sni_domain, backend_url, proxy_internal_secret, init_script, harden_script
|
||||
);
|
||||
|
||||
Self::exec_ssh_command(&sess, &full_command)?;
|
||||
|
||||
Reference in New Issue
Block a user