Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion nexus/auth/src/authz/api_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,49 @@ impl AuthorizedResource for ScimClientBearerTokenList {
}
}

/// Synthetic resource for authorization to list Subnet Pools.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SubnetPoolList;

/// Singleton representing the [`SubnetPoolList`] itself for authz
/// purposes.
pub const SUBNET_POOL_LIST: SubnetPoolList = SubnetPoolList;

impl oso::PolarClass for SubnetPoolList {
fn get_polar_class_builder() -> oso::ClassBuilder<Self> {
oso::Class::builder()
.with_equality_check()
.add_attribute_getter("fleet", |_: &SubnetPoolList| FLEET)
}
}
Comment on lines +1240 to +1246
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to add a comment here or anything, since this looks like it's probably really straightforward if you know some basics, but could you give me (or point me at) a quick tutorial on Oso sometime?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dave Pacheco would be the best person for detailed questions, but we have a debugging guide here and some general background in the block comment starting here.


impl AuthorizedResource for SubnetPoolList {
fn load_roles<'fut>(
&'fut self,
opctx: &'fut OpContext,
authn: &'fut authn::Context,
roleset: &'fut mut RoleSet,
) -> futures::future::BoxFuture<'fut, Result<(), Error>> {
// There are no roles on the SubnetPoolList, only permissions.
// But we still need to load the Fleet-related roles to verify that
// the actor's role on the Fleet (possibly conferred from a Silo role).
load_roles_for_resource_tree(&FLEET, opctx, authn, roleset).boxed()
}

fn on_unauthorized(
&self,
_: &Authz,
error: Error,
_: AnyActor,
_: Action,
) -> Error {
error
}

fn polar_class(&self) -> oso::Class {
Self::get_polar_class()
}
}
// Main resource hierarchy: Projects and their resources

authz_resource! {
Expand Down Expand Up @@ -1322,7 +1365,8 @@ authz_resource! {
// resources (instances, disks, etc.) within the existing network.
//
// Resources in this category: VPCs, Subnets, Routers, Router Routes,
// Internet Gateways, and their child resources (IP pools, IP addresses)
// Internet Gateways, and their child resources (IP pools, IP addresses),
// Floating IPs, and External Subnets.
// ============================================================================

authz_resource! {
Expand Down Expand Up @@ -1389,6 +1433,14 @@ authz_resource! {
polar_snippet = InProjectLimited,
}

authz_resource! {
name = "ExternalSubnet",
parent = "Project",
primary_key = { uuid_kind = ExternalSubnetKind },
roles_allowed = false,
polar_snippet = InProjectFull,
}

// MulticastGroup Authorization
//
// MulticastGroups are **fleet-scoped resources** with an implicit lifecycle:
Expand Down Expand Up @@ -1450,6 +1502,14 @@ authz_resource! {
polar_snippet = FleetChild,
}

authz_resource! {
name = "SubnetPool",
parent = "Fleet",
primary_key = { uuid_kind = SubnetPoolKind },
roles_allowed = false,
polar_snippet = FleetChild,
}

// Miscellaneous resources nested directly below "Fleet"

authz_resource! {
Expand Down
19 changes: 19 additions & 0 deletions nexus/auth/src/authz/omicron.polar
Original file line number Diff line number Diff line change
Expand Up @@ -861,3 +861,22 @@ resource VpcList {
}
has_relation(project: Project, "containing_project", collection: VpcList)
if collection.project = project;

# Describes the policy for accessing "/v1/system/subnet-pools" in the API
resource SubnetPoolList {
permissions = [
"list_children",
"modify",
"create_child",
];

# Fleet Administrators can create or modify the Subnet Pools list.
relations = { parent_fleet: Fleet };
"modify" if "admin" on "parent_fleet";
"create_child" if "admin" on "parent_fleet";

# Fleet Viewers can list External Subnet Pools
"list_children" if "viewer" on "parent_fleet";
}
has_relation(fleet: Fleet, "parent_fleet", subnet_pool_list: SubnetPoolList)
if subnet_pool_list.fleet = fleet;
3 changes: 3 additions & 0 deletions nexus/auth/src/authz/oso_generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ pub fn make_omicron_oso(log: &slog::Logger) -> Result<OsoInit, anyhow::Error> {
SiloUserList::get_polar_class(),
SiloUserSessionList::get_polar_class(),
SiloUserTokenList::get_polar_class(),
SubnetPoolList::get_polar_class(),
UpdateTrustRootList::get_polar_class(),
TargetReleaseConfig::get_polar_class(),
AlertClassList::get_polar_class(),
Expand Down Expand Up @@ -149,6 +150,7 @@ pub fn make_omicron_oso(log: &slog::Logger) -> Result<OsoInit, anyhow::Error> {
RouterRoute::init(),
VpcSubnet::init(),
FloatingIp::init(),
ExternalSubnet::init(),
// Silo-level resources
Image::init(),
SiloImage::init(),
Expand All @@ -170,6 +172,7 @@ pub fn make_omicron_oso(log: &slog::Logger) -> Result<OsoInit, anyhow::Error> {
IdentityProvider::init(),
SamlIdentityProvider::init(),
Sled::init(),
SubnetPool::init(),
TufRepo::init(),
TufArtifact::init(),
TufTrustRoot::init(),
Expand Down
32 changes: 32 additions & 0 deletions nexus/db-lookup/src/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,16 @@ impl<'a> LookupPath<'a> {
) -> ScimClientBearerToken<'a> {
ScimClientBearerToken::PrimaryKey(Root { lookup_root: self }, id)
}

/// Select a resource of type [`SubnetPool`], identified by its UUID.
pub fn subnet_pool_id(self, id: SubnetPoolUuid) -> SubnetPool<'a> {
SubnetPool::PrimaryKey(Root { lookup_root: self }, id)
}

/// Select a resource of type [`SubnetPool`], identified by its Name.
pub fn subnet_pool_name(self, name: Name) -> SubnetPool<'a> {
SubnetPool::OwnedName(Root { lookup_root: self }, name)
}
}

/// Represents the head of the selection path for a resource
Expand Down Expand Up @@ -904,6 +914,28 @@ lookup_resource! {
visible_outside_silo = true
}

lookup_resource! {
name = "SubnetPool",
ancestors = [],
lookup_by_name = true,
soft_deletes = true,
primary_key_columns = [
{ column_name = "id", uuid_kind = SubnetPoolKind }
],
visible_outside_silo = true
}

lookup_resource! {
name = "ExternalSubnet",
ancestors = [ "Silo", "Project" ],
lookup_by_name = true,
soft_deletes = true,
primary_key_columns = [
{ column_name = "id", uuid_kind = ExternalSubnetKind }
],
visible_outside_silo = false,
}

// Helpers for unifying the interfaces around images

pub enum ImageLookup<'a> {
Expand Down
Loading
Loading