From 56f04786ab3c8ddd83ae014ff4cf2a0b217ce9f6 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Fri, 24 Nov 2023 14:04:33 +0100 Subject: [PATCH] New gatekeeper internal-service, for partitioning access --- gatekeeper-config.pr | 97 +++++++++++++++++++ syndicate-server/protocols/schema-bundle.bin | 3 + .../protocols/schemas/internalServices.prs | 2 + syndicate-server/src/main.rs | 1 + syndicate-server/src/services/gatekeeper.rs | 39 ++++++++ syndicate-server/src/services/mod.rs | 1 + 6 files changed, 143 insertions(+) create mode 100644 gatekeeper-config.pr create mode 100644 syndicate-server/src/services/gatekeeper.rs diff --git a/gatekeeper-config.pr b/gatekeeper-config.pr new file mode 100644 index 0000000..705113f --- /dev/null +++ b/gatekeeper-config.pr @@ -0,0 +1,97 @@ +# We will create a TCP listener on port 9222, which speaks unencrypted +# protocol and allows interaction with the default/system gatekeeper, which +# has a single noise binding for introducing encrypted interaction with a +# *second* gatekeeper, which finally allows resolution of references to +# other objects. + +# First, build a space where we place bindings for the inner gatekeeper to +# expose. +let ?inner-bindings = dataspace + +# Next, start the inner gatekeeper. +> +? ?inner-gatekeeper> [ + # Expose it via a noise binding at the outer/system gatekeeper. + + $inner-gatekeeper #f> +] + +# Now, expose the outer gatekeeper to the world, via TCP. The system +# gatekeeper is a primordial syndicate-server object bound to $gatekeeper. + $gatekeeper>> + +# Finally, let's expose some behaviour accessible via the inner gatekeeper. +# +# We will create a service dataspace called $world. +let ?world = dataspace + +# Running `syndicate-macaroon mint --oid a-service --phrase hello` yields: +# +# +# +# That's a root capability for the service. We use the corresponding +# sturdy.SturdyDescriptionDetail to bind it to $world. +# +$inner-bindings += + $world #f> + +# Now, we can hand out paths to our services involving an initial noise +# step and a subsequent sturdyref/macaroon step. +# +# For example, running `syndicate-macaroon` like this: +# +# syndicate-macaroon mint --oid a-service --phrase hello \ +# --caveat '> ]>>' +# +# generates +# +# > , ]>>], +# oid: a-service, +# sig: #[CXn7+rAoO3Xr6Y6Laap3OA]}> +# +# which is an attenuation of the root capability we bound that wraps all +# assertions and messages in a `` wrapper. +# +# All together, the `gatekeeper.Route` that Alice would use would be +# something like: +# +# ] +# +# > , ]>>], +# oid: a-service, +# sig: #[CXn7+rAoO3Xr6Y6Laap3OA] }>> +# +# Here's one for "bob": +# +# syndicate-macaroon mint --oid a-service --phrase hello \ +# --caveat '> ]>>' +# +# > , ]>>], +# oid: a-service, +# sig: #[/75BbF77LOiqNcvpzNHf0g]}> +# +# ] +# +# > , ]>>], +# oid: a-service, +# sig: #[/75BbF77LOiqNcvpzNHf0g] }>> +# +# We relay labelled to unlabelled information, enacting a chat protocol +# that enforces usernames. +$world [ + + # Assertions of presence have the username wiped out and replaced with the label. + ? > + + # Likewise utterance messages. + ?? > ! + + # We allow anyone to subscribe to presence and utterances. + ? ?o>> $o> + ? ?o>> $o> + +] diff --git a/syndicate-server/protocols/schema-bundle.bin b/syndicate-server/protocols/schema-bundle.bin index 1f7be8a..ddff480 100644 --- a/syndicate-server/protocols/schema-bundle.bin +++ b/syndicate-server/protocols/schema-bundle.bin @@ -4,6 +4,9 @@ ProcessDir ProcessEnv´³orµµ±present´³dict·³env´³named³env´³dictof´³refµ„³ EnvVariable„´³refµ„³EnvValue„„„„„„µ±invalid´³dict·³env´³named³env³any„„„„µ±absent´³dict·„„„„„³ CommandLine´³orµµ±shell´³atom³String„„µ±full´³refµ„³FullCommandLine„„„„³ EnvVariable´³orµµ±string´³atom³String„„µ±symbol´³atom³Symbol„„µ±invalid³any„„„³ FullProcess´³andµ´³dict·³argv´³named³argv´³refµ„³ CommandLine„„„„´³named³env´³refµ„³ ProcessEnv„„´³named³dir´³refµ„³ ProcessDir„„´³named³clearEnv´³refµ„³ClearEnv„„„„³ ReadyOnStart´³orµµ±present´³dict·³ readyOnStart´³named³ readyOnStart´³atom³Boolean„„„„„µ±invalid´³dict·³ readyOnStart´³named³ readyOnStart³any„„„„µ±absent´³dict·„„„„„³ RestartField´³orµµ±present´³dict·³restart´³named³restart´³refµ„³ RestartPolicy„„„„„µ±invalid´³dict·³restart´³named³restart³any„„„„µ±absent´³dict·„„„„„³ DaemonProcess´³rec´³lit³daemon„´³tupleµ´³named³id³any„´³named³config´³refµ„³DaemonProcessSpec„„„„„³ DaemonService´³rec´³lit³daemon„´³tupleµ´³named³id³any„„„„³ ProtocolField´³orµµ±present´³dict·³protocol´³named³protocol´³refµ„³Protocol„„„„„µ±invalid´³dict·³protocol´³named³protocol³any„„„„µ±absent´³dict·„„„„„³ RestartPolicy´³orµµ±always´³lit³always„„µ±onError´³lit³on-error„„µ±all´³lit³all„„µ±never´³lit³never„„„„³FullCommandLine´³ tuplePrefixµ´³named³program´³atom³String„„„´³named³args´³seqof´³atom³String„„„„³DaemonProcessSpec´³orµµ±simple´³refµ„³ CommandLine„„µ±oneShot´³rec´³lit³one-shot„´³tupleµ´³named³setup´³refµ„³ CommandLine„„„„„„µ±full´³refµ„³FullDaemonProcess„„„„³FullDaemonProcess´³andµ´³named³process´³refµ„³ FullProcess„„´³named³ readyOnStart´³refµ„³ ReadyOnStart„„´³named³restart´³refµ„³ RestartField„„´³named³protocol´³refµ„³ ProtocolField„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³internalServices„´³schema·³version°³ definitions·³ ConfigEnv´³dictof´³atom³Symbol„³any„³ +Gatekeeper´³rec´³lit³ +gatekeeper„´³tupleµ´³named³ bindspace´³embedded´³refµ³ +gatekeeper„³Bind„„„„„„³ HttpRouter´³rec´³lit³ http-router„´³tupleµ´³named³httpd´³embedded³any„„„„„³ TcpWithHttp´³rec´³lit³relay-listener„´³tupleµ´³named³addr´³refµ³TransportAddress„³Tcp„„´³named³ gatekeeper´³embedded´³refµ³ gatekeeper„³Resolve„„„´³named³httpd´³embedded´³refµ³http„³ HttpContext„„„„„„³ DebtReporter´³rec´³lit³ debt-reporter„´³tupleµ´³named³intervalSeconds´³atom³Double„„„„„³ ConfigWatcher´³rec´³lit³config-watcher„´³tupleµ´³named³path´³atom³String„„´³named³env´³refµ„³ ConfigEnv„„„„„³TcpWithoutHttp´³rec´³lit³relay-listener„´³tupleµ´³named³addr´³refµ³TransportAddress„³Tcp„„´³named³ diff --git a/syndicate-server/protocols/schemas/internalServices.prs b/syndicate-server/protocols/schemas/internalServices.prs index 7f39243..58665f4 100644 --- a/syndicate-server/protocols/schemas/internalServices.prs +++ b/syndicate-server/protocols/schemas/internalServices.prs @@ -1,6 +1,8 @@ version 1 . embeddedType EntityRef.Cap . +Gatekeeper = . + DebtReporter = . TcpRelayListener = TcpWithoutHttp / TcpWithHttp . diff --git a/syndicate-server/src/main.rs b/syndicate-server/src/main.rs index dd19fcb..9f68be9 100644 --- a/syndicate-server/src/main.rs +++ b/syndicate-server/src/main.rs @@ -127,6 +127,7 @@ async fn main() -> ActorResult { services::config_watcher::on_demand(t, Arc::clone(&server_config_ds)); services::daemon::on_demand(t, Arc::clone(&server_config_ds), Arc::clone(&log_ds)); services::debt_reporter::on_demand(t, Arc::clone(&server_config_ds)); + services::gatekeeper::on_demand(t, Arc::clone(&server_config_ds)); services::http_router::on_demand(t, Arc::clone(&server_config_ds)); services::tcp_relay_listener::on_demand(t, Arc::clone(&server_config_ds)); services::unix_relay_listener::on_demand(t, Arc::clone(&server_config_ds)); diff --git a/syndicate-server/src/services/gatekeeper.rs b/syndicate-server/src/services/gatekeeper.rs new file mode 100644 index 0000000..c0eb2ae --- /dev/null +++ b/syndicate-server/src/services/gatekeeper.rs @@ -0,0 +1,39 @@ +use preserves_schema::Codec; + +use std::sync::Arc; + +use syndicate::actor::*; +use syndicate::enclose; +use syndicate::preserves::rec; +use syndicate::preserves::value::NestedValue; + +use crate::gatekeeper; +use crate::language::Language; +use crate::language::language; +use crate::lifecycle; +use crate::schemas::internal_services::Gatekeeper; + +use syndicate_macros::during; + +pub fn on_demand(t: &mut Activation, ds: Arc) { + t.spawn(Some(AnyValue::symbol("gatekeeper_listener")), move |t| { + Ok(during!(t, ds, language(), >, |t: &mut Activation| { + t.spawn_link(Some(rec![AnyValue::symbol("gatekeeper"), language().unparse(&spec)]), + enclose!((ds) |t| run(t, ds, spec))); + Ok(()) + })) + }); +} + +fn run(t: &mut Activation, ds: Arc, spec: Gatekeeper) -> ActorResult { + let resolver = t.create(syndicate::entity(Arc::clone(&spec.bindspace)) + .on_asserted(gatekeeper::handle_resolves)); + ds.assert(t, language(), &syndicate::schemas::service::ServiceObject { + service_name: language().unparse(&spec), + object: AnyValue::domain(Cap::guard(Language::arc(), resolver)), + }); + gatekeeper::handle_binds(t, &spec.bindspace)?; + ds.assert(t, language(), &lifecycle::started(&spec)); + ds.assert(t, language(), &lifecycle::ready(&spec)); + Ok(()) +} diff --git a/syndicate-server/src/services/mod.rs b/syndicate-server/src/services/mod.rs index 00b0801..cd75eb7 100644 --- a/syndicate-server/src/services/mod.rs +++ b/syndicate-server/src/services/mod.rs @@ -1,6 +1,7 @@ pub mod config_watcher; pub mod daemon; pub mod debt_reporter; +pub mod gatekeeper; pub mod http_router; pub mod tcp_relay_listener; pub mod unix_relay_listener;