Skip to content

Commit 26c6640

Browse files
committed
Create a synthetic authz resource for trust quorum and use it
1 parent 5552f18 commit 26c6640

13 files changed

Lines changed: 289 additions & 131 deletions

File tree

dev-tools/omdb/src/bin/omdb/db.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ use nexus_db_model::VolumeResourceUsage;
112112
use nexus_db_model::VpcSubnet;
113113
use nexus_db_model::Zpool;
114114
use nexus_db_model::to_db_typed_uuid;
115+
use nexus_db_queries::authz;
115116
use nexus_db_queries::context::OpContext;
116117
use nexus_db_queries::db;
117118
use nexus_db_queries::db::DataStore;
@@ -151,6 +152,7 @@ use omicron_common::api::external;
151152
use omicron_common::api::external::DataPageParams;
152153
use omicron_common::api::external::Generation;
153154
use omicron_common::api::external::InstanceState;
155+
use omicron_common::api::external::LookupType;
154156
use omicron_common::api::external::MacAddr;
155157
use omicron_uuid_kinds::CollectionUuid;
156158
use omicron_uuid_kinds::DatasetUuid;
@@ -8165,8 +8167,13 @@ async fn cmd_db_trust_quorum_list_configs(
81658167
}
81668168

81678169
let limit = fetch_opts.fetch_limit;
8170+
let authz_tq = authz::TrustQuorumConfig::new(authz::Rack::new(
8171+
authz::FLEET,
8172+
args.rack_id.into_untyped_uuid(),
8173+
LookupType::ById(args.rack_id.into_untyped_uuid()),
8174+
));
81688175
let configs = datastore
8169-
.tq_list_config(opctx, args.rack_id, &first_page::<i64>(limit))
8176+
.tq_list_config(opctx, authz_tq, &first_page::<i64>(limit))
81708177
.await
81718178
.context("listing trust quorum configurations")?;
81728179

nexus/auth/src/authz/api_resources.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,58 @@ impl AuthorizedResource for Inventory {
681681
}
682682
}
683683

684+
/// Synthetic resource for to model accessing trust quorum configurations for a
685+
/// given rack
686+
#[derive(Clone, Debug, Eq, PartialEq)]
687+
pub struct TrustQuorumConfig(Rack);
688+
689+
impl TrustQuorumConfig {
690+
pub fn new(rack: Rack) -> TrustQuorumConfig {
691+
TrustQuorumConfig(rack)
692+
}
693+
694+
pub fn rack(&self) -> &Rack {
695+
&self.0
696+
}
697+
}
698+
699+
impl oso::PolarClass for TrustQuorumConfig {
700+
fn get_polar_class_builder() -> oso::ClassBuilder<Self> {
701+
oso::Class::builder()
702+
.with_equality_check()
703+
.add_attribute_getter("rack", |config: &TrustQuorumConfig| {
704+
config.0.clone()
705+
})
706+
}
707+
}
708+
709+
impl AuthorizedResource for TrustQuorumConfig {
710+
fn load_roles<'fut>(
711+
&'fut self,
712+
opctx: &'fut OpContext,
713+
authn: &'fut authn::Context,
714+
roleset: &'fut mut RoleSet,
715+
) -> futures::future::BoxFuture<'fut, Result<(), Error>> {
716+
// There are no roles on this resource, but we still need to load the
717+
// Rack-related roles.
718+
self.rack().load_roles(opctx, authn, roleset)
719+
}
720+
721+
fn on_unauthorized(
722+
&self,
723+
_: &Authz,
724+
error: Error,
725+
_: AnyActor,
726+
_: Action,
727+
) -> Error {
728+
error
729+
}
730+
731+
fn polar_class(&self) -> oso::Class {
732+
Self::get_polar_class()
733+
}
734+
}
735+
684736
/// Synthetic resource describing the list of Certificates associated with a
685737
/// Silo
686738
#[derive(Clone, Debug, Eq, PartialEq)]

nexus/auth/src/authz/omicron.polar

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,17 @@ resource DeviceAuthRequestList {
611611
has_relation(fleet: Fleet, "parent_fleet", collection: DeviceAuthRequestList)
612612
if collection.fleet = fleet;
613613

614+
# Describes the policy for creating and managing trust quorum configurations
615+
# This may change in a multirack future to a per rack parent
616+
resource TrustQuorumConfig {
617+
permissions = [ "read", "modify" ];
618+
relations = { parent_fleet: Fleet };
619+
"read" if "viewer" on "parent_fleet";
620+
"modify" if "admin" on "parent_fleet";
621+
}
622+
has_relation(fleet: Fleet, "parent_fleet", config: TrustQuorumConfig)
623+
if config.rack.fleet = fleet;
624+
614625
# Describes the policy for creating and managing Silo certificates
615626
resource SiloCertificateList {
616627
permissions = [ "list_children", "create_child" ];

nexus/auth/src/authz/oso_generic.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ pub fn make_omicron_oso(log: &slog::Logger) -> Result<OsoInit, anyhow::Error> {
126126
AlertClassList::get_polar_class(),
127127
ScimClientBearerTokenList::get_polar_class(),
128128
MulticastGroupList::get_polar_class(),
129+
TrustQuorumConfig::get_polar_class(),
129130
];
130131
for c in classes {
131132
oso_builder = oso_builder.register_class(c)?;

nexus/db-queries/src/db/datastore/rack.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ use omicron_common::api::external::UserId;
6969
use omicron_common::api::internal::shared::PrivateIpConfig;
7070
use omicron_common::bail_unless;
7171
use omicron_uuid_kinds::GenericUuid;
72-
use omicron_uuid_kinds::RackUuid;
7372
use omicron_uuid_kinds::SiloUserUuid;
7473
use omicron_uuid_kinds::SledUuid;
7574
use omicron_uuid_kinds::ZpoolUuid;
@@ -980,10 +979,15 @@ impl DataStore {
980979

981980
// Insert the initial trust quorum configuration
982981
if let Some(tq_config) = rack_init.initial_trust_quorum_configuration {
982+
let authz_tq = authz::TrustQuorumConfig::new(authz::Rack::new(
983+
authz::FLEET,
984+
rack_id,
985+
LookupType::ById(rack_id),
986+
));
983987
Self::tq_insert_rss_config_after_handoff(
984988
opctx,
985989
&conn,
986-
RackUuid::from_untyped_uuid(rack_id),
990+
authz_tq,
987991
tq_config.members,
988992
tq_config.coordinator
989993
).await.map_err(|e| {

0 commit comments

Comments
 (0)