Bugfix/ssl proxy to ssl (#2956)

* fix registry rm command

* fix bind with addSsl on ssl proto

* fix bind with addSsl on ssl proto

* Add pre-release version migrations

* fix os build

* add mime to package deps

* update lockfile

* more ssl fixes

* add waitFor

* improve restart lockup

* beta.26

* fix dependency health check logic

* handle missing health check

* fix port forwards

---------

Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
Dominion5254
2025-06-04 19:41:21 -06:00
committed by GitHub
parent 02413a4fac
commit ab6ca8e16a
40 changed files with 1240 additions and 816 deletions

View File

@@ -26,7 +26,7 @@ pub async fn restart(
ProcedureId { procedure_id }: ProcedureId,
) -> Result<(), Error> {
let context = context.deref()?;
context.restart(procedure_id).await?;
context.restart(procedure_id, false).await?;
Ok(())
}

View File

@@ -71,11 +71,6 @@ pub async fn mount(
if is_mountpoint(&mountpoint).await? {
unmount(&mountpoint, true).await?;
}
Command::new("chown")
.arg("100000:100000")
.arg(&mountpoint)
.invoke(crate::ErrorKind::Filesystem)
.await?;
IdMapped::new(Bind::new(source).with_type(filetype), 0, 100000, 65536)
.mount(
mountpoint,

View File

@@ -1,6 +1,8 @@
use std::collections::BTreeSet;
use std::net::IpAddr;
use imbl_value::InternedString;
use ipnet::IpNet;
use itertools::Itertools;
use openssl::pkey::{PKey, Private};
@@ -8,6 +10,7 @@ use crate::service::effects::callbacks::CallbackHandler;
use crate::service::effects::prelude::*;
use crate::service::rpc::CallbackId;
use crate::util::serde::Pem;
use crate::HOST_IP;
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, TS, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
@@ -57,6 +60,13 @@ pub async fn get_ssl_certificate(
.iter()
.map(InternedString::from_display)
.chain(m.as_domains().keys()?)
.chain(
m.as_hostname_info()
.de()?
.values()
.flatten()
.map(|h| h.to_san_hostname()),
)
.collect::<Vec<_>>())
})
.map(|a| a.and_then(|a| a))
@@ -70,6 +80,28 @@ pub async fn get_ssl_certificate(
if !packages.contains(internal) {
return Err(errfn(&*hostname));
}
} else if let Ok(ip) = hostname.parse::<IpAddr>() {
if IpNet::new(HOST_IP.into(), 24)
.with_kind(ErrorKind::ParseNetAddress)?
.contains(&ip)
{
Ok(())
} else if db
.as_public()
.as_server_info()
.as_network()
.as_network_interfaces()
.as_entries()?
.into_iter()
.flat_map(|(_, net)| net.as_ip_info().transpose_ref())
.flat_map(|net| net.as_subnets().de().log_err())
.flatten()
.any(|s| s.addr() == ip)
{
Ok(())
} else {
Err(errfn(&*hostname))
}?;
} else {
if !allowed_hostnames.contains(hostname) {
return Err(errfn(&*hostname));
@@ -128,6 +160,11 @@ pub async fn get_ssl_key(
let context = context.deref()?;
let package_id = &context.seed.id;
let algorithm = algorithm.unwrap_or(Algorithm::Ecdsa);
let container_ip = if let Some(lxc) = context.seed.persistent_container.lxc_container.get() {
Some(lxc.ip().await?)
} else {
None
};
let cert = context
.seed
@@ -135,7 +172,7 @@ pub async fn get_ssl_key(
.db
.mutate(|db| {
let errfn = |h: &str| Error::new(eyre!("unknown hostname: {h}"), ErrorKind::NotFound);
let allowed_hostnames = db
let mut allowed_hostnames = db
.as_public()
.as_package_data()
.as_idx(package_id)
@@ -148,11 +185,19 @@ pub async fn get_ssl_key(
.iter()
.map(InternedString::from_display)
.chain(m.as_domains().keys()?)
.chain(
m.as_hostname_info()
.de()?
.values()
.flatten()
.map(|h| h.to_san_hostname()),
)
.collect::<Vec<_>>())
})
.map(|a| a.and_then(|a| a))
.flatten_ok()
.try_collect::<_, BTreeSet<_>, _>()?;
allowed_hostnames.extend(container_ip.as_ref().map(InternedString::from_display));
for hostname in &hostnames {
if let Some(internal) = hostname
.strip_suffix(".embassy")

View File

@@ -1,5 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINn5jiv9VFgEwdUJsDksSTAjPKwkl2DCmCmumu4D1GnNoAoGCCqGSM49
AwEHoUQDQgAE5KuqP+Wdn8pzmNMxK2hya6mKj1H0j5b47y97tIXqf5ajTi8koRPl
yao3YcqdtBtN37aw4rVlXVwEJIozZgyiyA==
-----END EC PRIVATE KEY-----

View File

@@ -1,13 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIB9DCCAZmgAwIBAgIUIWsFiA8JqIqeUo+Psn91oCQIcdwwCgYIKoZIzj0EAwIw
TzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNPMRowGAYDVQQKDBFTdGFydDkgTGFi
cywgSW5jLjEXMBUGA1UEAwwOZmFrZW5hbWUubG9jYWwwHhcNMjQwMjE0MTk1MTUz
WhcNMjUwMjEzMTk1MTUzWjBPMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ08xGjAY
BgNVBAoMEVN0YXJ0OSBMYWJzLCBJbmMuMRcwFQYDVQQDDA5mYWtlbmFtZS5sb2Nh
bDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOSrqj/lnZ/Kc5jTMStocmupio9R
9I+W+O8ve7SF6n+Wo04vJKET5cmqN2HKnbQbTd+2sOK1ZV1cBCSKM2YMosijUzBR
MB0GA1UdDgQWBBR+qd4W//H34Eg90yAPjYz3nZK79DAfBgNVHSMEGDAWgBR+qd4W
//H34Eg90yAPjYz3nZK79DAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kA
MEYCIQDNSN9YWkGbntG+nC+NzEyqE9FcvYZ8TaF3sOnthqSVKwIhAM2N+WJG/p4C
cPl4HSPPgDaOIhVZzxSje2ycb7wvFtpH
-----END CERTIFICATE-----

View File

@@ -1142,23 +1142,6 @@ pub async fn cli_attach(
None
};
let (kill, thread_kill) = tokio::sync::oneshot::channel();
let (thread_send, recv) = tokio::sync::mpsc::channel(4 * CAP_1_KiB);
let stdin_thread: NonDetachingJoinHandle<()> = tokio::task::spawn_blocking(move || {
use std::io::Read;
let mut stdin = stdin.lock().bytes();
while thread_kill.is_empty() {
if let Some(b) = stdin.next() {
thread_send.blocking_send(b).unwrap();
} else {
break;
}
}
})
.into();
let mut stdin = Some(recv);
let guid: Guid = from_value(
context
.call_remote::<RpcContext>(
@@ -1178,6 +1161,25 @@ pub async fn cli_attach(
)?;
let mut ws = context.ws_continuation(guid).await?;
let (kill, thread_kill) = tokio::sync::oneshot::channel();
let (thread_send, recv) = tokio::sync::mpsc::channel(4 * CAP_1_KiB);
let stdin_thread: NonDetachingJoinHandle<()> = tokio::task::spawn_blocking(move || {
use std::io::Read;
let mut stdin = stdin.lock().bytes();
while thread_kill.is_empty() {
if let Some(b) = stdin.next() {
if let Err(_) = thread_send.blocking_send(b) {
break;
}
} else {
break;
}
}
})
.into();
let mut stdin = Some(recv);
let mut current_in = "stdin";
let mut current_out = "stdout".to_owned();
ws.send(Message::Text(current_in.into()))

View File

@@ -161,12 +161,6 @@ impl PersistentContainer {
.rootfs_dir()
.join("media/startos/volumes")
.join(volume);
tokio::fs::create_dir_all(&mountpoint).await?;
Command::new("chown")
.arg("100000:100000")
.arg(&mountpoint)
.invoke(crate::ErrorKind::Filesystem)
.await?;
let mount = MountGuard::mount(
&IdMapped::new(
Bind::new(data_dir(DATA_DIR, &s9pk.as_manifest().id, volume)),
@@ -182,12 +176,6 @@ impl PersistentContainer {
}
let mountpoint = lxc_container.rootfs_dir().join("media/startos/assets");
tokio::fs::create_dir_all(&mountpoint).await?;
Command::new("chown")
.arg("100000:100000")
.arg(&mountpoint)
.invoke(crate::ErrorKind::Filesystem)
.await?;
let assets = if let Some(sqfs) = s9pk
.as_archive()
.contents()
@@ -215,12 +203,6 @@ impl PersistentContainer {
.rootfs_dir()
.join("media/startos/assets")
.join(Path::new(asset).with_extension(""));
tokio::fs::create_dir_all(&mountpoint).await?;
Command::new("chown")
.arg("100000:100000")
.arg(&mountpoint)
.invoke(crate::ErrorKind::Filesystem)
.await?;
let Some(sqfs) = entry.as_file() else {
continue;
};
@@ -271,12 +253,6 @@ impl PersistentContainer {
.and_then(|e| e.as_file())
.or_not_found(sqfs_path.display())?;
let mountpoint = image_path.join(image);
tokio::fs::create_dir_all(&mountpoint).await?;
Command::new("chown")
.arg("100000:100000")
.arg(&mountpoint)
.invoke(ErrorKind::Filesystem)
.await?;
images.insert(
image.clone(),
Arc::new(

View File

@@ -1,3 +1,4 @@
use futures::future::BoxFuture;
use futures::FutureExt;
use super::TempDesiredRestore;
@@ -12,7 +13,7 @@ use crate::util::future::RemoteCancellable;
pub(super) struct Restart;
impl Handler<Restart> for ServiceActor {
type Response = ();
type Response = BoxFuture<'static, Option<()>>;
fn conflicts_with(_: &Restart) -> ConflictBuilder<Self> {
ConflictBuilder::everything().except::<GetActionInput>()
}
@@ -65,14 +66,18 @@ impl Handler<Restart> for ServiceActor {
if let Some(t) = old {
t.abort().await;
}
if transition.await.is_none() {
tracing::warn!("Service {} has been cancelled", &self.0.id);
}
transition.boxed()
}
}
impl Service {
#[instrument(skip_all)]
pub async fn restart(&self, id: Guid) -> Result<(), Error> {
self.actor.send(id, Restart).await
pub async fn restart(&self, id: Guid, wait: bool) -> Result<(), Error> {
let fut = self.actor.send(id, Restart).await?;
if wait {
if fut.await.is_none() {
tracing::warn!("Restart has been cancelled");
}
}
Ok(())
}
}