From f3748929e090505e0471517237dde195088841fa Mon Sep 17 00:00:00 2001 From: David Crespo Date: Wed, 10 Aug 2022 11:07:17 -0500 Subject: [PATCH 1/8] /policy for current silo, /global/policy for fleet --- nexus/src/app/silo.rs | 46 +++++++++++ nexus/src/external_api/http_entrypoints.rs | 66 +++++++++++++++- nexus/tests/integration_tests/endpoints.rs | 2 +- .../integration_tests/role_assignments.rs | 2 +- nexus/tests/output/nexus_tags.txt | 6 +- openapi/nexus.json | 76 +++++++++++++++++-- 6 files changed, 183 insertions(+), 15 deletions(-) diff --git a/nexus/src/app/silo.rs b/nexus/src/app/silo.rs index ddf08dfc7ef..222b886d05f 100644 --- a/nexus/src/app/silo.rs +++ b/nexus/src/app/silo.rs @@ -97,6 +97,26 @@ impl super::Nexus { Ok(shared::Policy { role_assignments }) } + pub async fn silo_fetch_policy_by_id( + &self, + opctx: &OpContext, + silo_id: Uuid, + ) -> LookupResult> { + let (.., authz_silo) = LookupPath::new(opctx, &self.db_datastore) + .silo_id(silo_id) + .lookup_for(authz::Action::ReadPolicy) + .await?; + let role_assignments = self + .db_datastore + .role_assignment_fetch_visible(opctx, &authz_silo) + .await? + .into_iter() + .map(|r| r.try_into().context("parsing database role assignment")) + .collect::, _>>() + .map_err(|error| Error::internal_error(&format!("{:#}", error)))?; + Ok(shared::Policy { role_assignments }) + } + pub async fn silo_update_policy( &self, opctx: &OpContext, @@ -123,6 +143,32 @@ impl super::Nexus { Ok(shared::Policy { role_assignments }) } + pub async fn silo_update_policy_by_id( + &self, + opctx: &OpContext, + silo_id: Uuid, + policy: &shared::Policy, + ) -> UpdateResult> { + let (.., authz_silo) = LookupPath::new(opctx, &self.db_datastore) + .silo_id(silo_id) + .lookup_for(authz::Action::ModifyPolicy) + .await?; + + let role_assignments = self + .db_datastore + .role_assignment_replace_visible( + opctx, + &authz_silo, + &policy.role_assignments, + ) + .await? + .into_iter() + .map(|r| r.try_into()) + .collect::, _>>()?; + + Ok(shared::Policy { role_assignments }) + } + // Users pub async fn silo_user_fetch( diff --git a/nexus/src/external_api/http_entrypoints.rs b/nexus/src/external_api/http_entrypoints.rs index 2b0a6af814a..a13b87ec0e1 100644 --- a/nexus/src/external_api/http_entrypoints.rs +++ b/nexus/src/external_api/http_entrypoints.rs @@ -80,6 +80,9 @@ type NexusApiDescription = ApiDescription>; /// Returns a description of the external nexus API pub fn external_api() -> NexusApiDescription { fn register_endpoints(api: &mut NexusApiDescription) -> Result<(), String> { + api.register(global_policy_view)?; + api.register(global_policy_update)?; + api.register(policy_view)?; api.register(policy_update)?; @@ -316,10 +319,10 @@ pub fn external_api() -> NexusApiDescription { /// Fetch the top-level IAM policy #[endpoint { method = GET, - path = "/policy", + path = "/global/policy", tags = ["policy"], }] -async fn policy_view( +async fn global_policy_view( rqctx: Arc>>, ) -> Result>, HttpError> { let apictx = rqctx.context(); @@ -342,10 +345,10 @@ struct ByIdPathParams { /// Update the top-level IAM policy #[endpoint { method = PUT, - path = "/policy", + path = "/global/policy", tags = ["policy"], }] -async fn policy_update( +async fn global_policy_update( rqctx: Arc>>, new_policy: TypedBody>, ) -> Result>, HttpError> { @@ -364,6 +367,61 @@ async fn policy_update( apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await } +/// Fetch the current silo's IAM policy +#[endpoint { + method = GET, + path = "/policy", + tags = ["silos"], + }] +pub async fn policy_view( + rqctx: Arc>>, +) -> Result>, HttpError> { + let apictx = rqctx.context(); + let nexus = &apictx.nexus; + let handler = async { + let opctx = OpContext::for_external_api(&rqctx).await?; + let authz_silo = opctx + .authn + .silo_required() + .internal_context("loading current silo")?; + let policy = + nexus.silo_fetch_policy_by_id(&opctx, authz_silo.id()).await?; + Ok(HttpResponseOk(policy.into())) + }; + apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await +} + +/// Update the current silo's IAM policy +#[endpoint { + method = PUT, + path = "/policy", + tags = ["silos"], +}] +async fn policy_update( + rqctx: Arc>>, + new_policy: TypedBody>, +) -> Result>, HttpError> { + let apictx = rqctx.context(); + let nexus = &apictx.nexus; + let new_policy = new_policy.into_inner(); + + let handler = async { + let nasgns = new_policy.role_assignments.len(); + // This should have been validated during parsing. + bail_unless!(nasgns <= shared::MAX_ROLE_ASSIGNMENTS_PER_RESOURCE); + let opctx = OpContext::for_external_api(&rqctx).await?; + let authz_silo = opctx + .authn + .silo_required() + .internal_context("loading current silo")?; + let policy = nexus + .silo_update_policy_by_id(&opctx, authz_silo.id(), &new_policy) + .await?; + Ok(HttpResponseOk(policy)) + }; + apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await +} + /// List silos /// /// Lists silos that are discoverable based on the current permissions. diff --git a/nexus/tests/integration_tests/endpoints.rs b/nexus/tests/integration_tests/endpoints.rs index 08a2e17100c..e840e1733d4 100644 --- a/nexus/tests/integration_tests/endpoints.rs +++ b/nexus/tests/integration_tests/endpoints.rs @@ -40,7 +40,7 @@ lazy_static! { format!("/hardware/sleds/{}", SLED_AGENT_UUID); // Global policy - pub static ref POLICY_URL: &'static str = "/policy"; + pub static ref POLICY_URL: &'static str = "/global/policy"; // Silo used for testing pub static ref DEMO_SILO_NAME: Name = "demo-silo".parse().unwrap(); diff --git a/nexus/tests/integration_tests/role_assignments.rs b/nexus/tests/integration_tests/role_assignments.rs index 1c59cb91ed2..552d7e2c4f4 100644 --- a/nexus/tests/integration_tests/role_assignments.rs +++ b/nexus/tests/integration_tests/role_assignments.rs @@ -108,7 +108,7 @@ async fn test_role_assignments_fleet(cptestctx: &ControlPlaneTestContext) { const ROLE: Self::RoleType = authz::FleetRole::Admin; const VISIBLE_TO_UNPRIVILEGED: bool = true; fn policy_url(&self) -> String { - String::from("/policy") + String::from("/global/policy") } fn verify_initial<'a, 'b, 'c, 'd>( diff --git a/nexus/tests/output/nexus_tags.txt b/nexus/tests/output/nexus_tags.txt index f670745a411..59e62d7bb80 100644 --- a/nexus/tests/output/nexus_tags.txt +++ b/nexus/tests/output/nexus_tags.txt @@ -99,8 +99,8 @@ organization_view_by_id /by-id/organizations/{id} API operations found with tag "policy" OPERATION ID URL PATH -policy_update /policy -policy_view /policy +global_policy_update /global/policy +global_policy_view /global/policy API operations found with tag "projects" OPERATION ID URL PATH @@ -132,6 +132,8 @@ session_sshkey_view /session/me/sshkeys/{ssh_key_name} API operations found with tag "silos" OPERATION ID URL PATH +policy_update /policy +policy_view /policy silo_create /silos silo_delete /silos/{silo_name} silo_identity_provider_create /silos/{silo_name}/saml-identity-providers diff --git a/openapi/nexus.json b/openapi/nexus.json index e1c11b06733..9c057d9daa8 100644 --- a/openapi/nexus.json +++ b/openapi/nexus.json @@ -569,6 +569,68 @@ } } }, + "/global/policy": { + "get": { + "tags": [ + "policy" + ], + "summary": "Fetch the top-level IAM policy", + "operationId": "global_policy_view", + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FleetRolePolicy" + } + } + } + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + }, + "put": { + "tags": [ + "policy" + ], + "summary": "Update the top-level IAM policy", + "operationId": "global_policy_update", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FleetRolePolicy" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FleetRolePolicy" + } + } + } + }, + "4XX": { + "$ref": "#/components/responses/Error" + }, + "5XX": { + "$ref": "#/components/responses/Error" + } + } + } + }, "/hardware/racks": { "get": { "tags": [ @@ -5912,9 +5974,9 @@ "/policy": { "get": { "tags": [ - "policy" + "silos" ], - "summary": "Fetch the top-level IAM policy", + "summary": "Fetch current silo's IAM policy", "operationId": "policy_view", "responses": { "200": { @@ -5922,7 +5984,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/FleetRolePolicy" + "$ref": "#/components/schemas/SiloRolePolicy" } } } @@ -5937,15 +5999,15 @@ }, "put": { "tags": [ - "policy" + "silos" ], - "summary": "Update the top-level IAM policy", + "summary": "Update current silo's IAM policy", "operationId": "policy_update", "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/FleetRolePolicy" + "$ref": "#/components/schemas/SiloRolePolicy" } } }, @@ -5957,7 +6019,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/FleetRolePolicy" + "$ref": "#/components/schemas/SiloRolePolicy" } } } From 43395506dd1c0d52762835d987313a439437220f Mon Sep 17 00:00:00 2001 From: David Crespo Date: Wed, 10 Aug 2022 11:47:18 -0500 Subject: [PATCH 2/8] clippy!!! --- nexus/src/external_api/http_entrypoints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nexus/src/external_api/http_entrypoints.rs b/nexus/src/external_api/http_entrypoints.rs index a13b87ec0e1..417cb662acb 100644 --- a/nexus/src/external_api/http_entrypoints.rs +++ b/nexus/src/external_api/http_entrypoints.rs @@ -386,7 +386,7 @@ pub async fn policy_view( .internal_context("loading current silo")?; let policy = nexus.silo_fetch_policy_by_id(&opctx, authz_silo.id()).await?; - Ok(HttpResponseOk(policy.into())) + Ok(HttpResponseOk(policy)) }; apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await } From e531ea18b93c79f1e59c96726db5d0bf7f2919c1 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Wed, 10 Aug 2022 13:56:02 -0500 Subject: [PATCH 3/8] verify policy endpoint (well, it fails) --- nexus/tests/integration_tests/endpoints.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/nexus/tests/integration_tests/endpoints.rs b/nexus/tests/integration_tests/endpoints.rs index e840e1733d4..34ba47fdc8c 100644 --- a/nexus/tests/integration_tests/endpoints.rs +++ b/nexus/tests/integration_tests/endpoints.rs @@ -40,7 +40,7 @@ lazy_static! { format!("/hardware/sleds/{}", SLED_AGENT_UUID); // Global policy - pub static ref POLICY_URL: &'static str = "/global/policy"; + pub static ref GLOBAL_POLICY_URL: &'static str = "/global/policy"; // Silo used for testing pub static ref DEMO_SILO_NAME: Name = "demo-silo".parse().unwrap(); @@ -520,7 +520,7 @@ lazy_static! { pub static ref VERIFY_ENDPOINTS: Vec = vec![ // Global IAM policy VerifyEndpoint { - url: *POLICY_URL, + url: *GLOBAL_POLICY_URL, visibility: Visibility::Public, unprivileged_access: UnprivilegedAccess::None, allowed_methods: vec![ @@ -676,6 +676,21 @@ lazy_static! { ), ], }, + VerifyEndpoint { + url: "/policy", + visibility: Visibility::Protected, + unprivileged_access: UnprivilegedAccess::None, + allowed_methods: vec![ + AllowedMethod::Get, + AllowedMethod::Put( + serde_json::to_value( + &shared::Policy:: { + role_assignments: vec![] + } + ).unwrap() + ), + ], + }, VerifyEndpoint { url: "/users", From f0b7175d62fbf30bf1eddb40b67ebc080ac79768 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Wed, 10 Aug 2022 14:22:18 -0500 Subject: [PATCH 4/8] test silo role assignments with `/policy` endpoint --- .../integration_tests/role_assignments.rs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/nexus/tests/integration_tests/role_assignments.rs b/nexus/tests/integration_tests/role_assignments.rs index 552d7e2c4f4..9db99c25111 100644 --- a/nexus/tests/integration_tests/role_assignments.rs +++ b/nexus/tests/integration_tests/role_assignments.rs @@ -218,6 +218,59 @@ async fn test_role_assignments_silo(cptestctx: &ControlPlaneTestContext) { run_test(client, SiloRoleAssignmentTest {}).await; } +// same as above except for /policy, where silo is implicit in auth +#[nexus_test] +async fn test_role_assignments_silo_implicit( + cptestctx: &ControlPlaneTestContext, +) { + struct SiloRoleAssignmentTest; + impl RoleAssignmentTest for SiloRoleAssignmentTest { + type RoleType = authz::SiloRole; + const ROLE: Self::RoleType = authz::SiloRole::Admin; + const VISIBLE_TO_UNPRIVILEGED: bool = true; + fn policy_url(&self) -> String { + "/policy".to_string() + } + + fn verify_initial<'a, 'b, 'c, 'd>( + &'a self, + _: &'b ClientTestContext, + _current_policy: &'c shared::Policy, + ) -> BoxFuture<'d, ()> + where + 'a: 'd, + 'b: 'd, + 'c: 'd, + { + async { + // TODO-coverage TODO-security There is currently nothing that + // requires the ability to modify a Silo. Once there is, we + // should test it here. + } + .boxed() + } + + fn verify_privileged<'a, 'b, 'c>( + &'a self, + _: &'b ClientTestContext, + ) -> BoxFuture<'c, ()> + where + 'a: 'c, + 'b: 'c, + { + async { + // TODO-coverage TODO-security There is currently nothing that + // requires the ability to modify a Silo. Once there is, we + // should test it here. + } + .boxed() + } + } + + let client = &cptestctx.external_client; + run_test(client, SiloRoleAssignmentTest {}).await; +} + #[nexus_test] async fn test_role_assignments_organization( cptestctx: &ControlPlaneTestContext, From 03719aed2952d100888818739a0b4ad49334d66b Mon Sep 17 00:00:00 2001 From: David Crespo Date: Wed, 10 Aug 2022 15:26:32 -0500 Subject: [PATCH 5/8] update openapi spec --- openapi/nexus.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openapi/nexus.json b/openapi/nexus.json index 9c057d9daa8..74366ef974f 100644 --- a/openapi/nexus.json +++ b/openapi/nexus.json @@ -5976,7 +5976,7 @@ "tags": [ "silos" ], - "summary": "Fetch current silo's IAM policy", + "summary": "Fetch the current silo's IAM policy", "operationId": "policy_view", "responses": { "200": { @@ -6001,7 +6001,7 @@ "tags": [ "silos" ], - "summary": "Update current silo's IAM policy", + "summary": "Update the current silo's IAM policy", "operationId": "policy_update", "requestBody": { "content": { From 1ce5a09ae6bc1c5a7b2b619459a6e4b71f7ce015 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Wed, 10 Aug 2022 17:02:31 -0500 Subject: [PATCH 6/8] welp. it was supposed to be public readonly all along --- nexus/tests/integration_tests/endpoints.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nexus/tests/integration_tests/endpoints.rs b/nexus/tests/integration_tests/endpoints.rs index 34ba47fdc8c..2c9924c693c 100644 --- a/nexus/tests/integration_tests/endpoints.rs +++ b/nexus/tests/integration_tests/endpoints.rs @@ -678,8 +678,8 @@ lazy_static! { }, VerifyEndpoint { url: "/policy", - visibility: Visibility::Protected, - unprivileged_access: UnprivilegedAccess::None, + visibility: Visibility::Public, + unprivileged_access: UnprivilegedAccess::ReadOnly, allowed_methods: vec![ AllowedMethod::Get, AllowedMethod::Put( From aa1ee4bd96c75b979f11fd2d395a2a75700fac29 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Wed, 10 Aug 2022 23:04:32 -0500 Subject: [PATCH 7/8] share common code. why not --- nexus/src/app/silo.rs | 36 ++++++++++------------ nexus/src/external_api/http_entrypoints.rs | 2 +- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/nexus/src/app/silo.rs b/nexus/src/app/silo.rs index 222b886d05f..b26f3f6fce7 100644 --- a/nexus/src/app/silo.rs +++ b/nexus/src/app/silo.rs @@ -77,15 +77,13 @@ impl super::Nexus { // Role assignments - pub async fn silo_fetch_policy( + async fn silo_fetch_policy( &self, opctx: &OpContext, - silo_name: &Name, + silo_lookup: db::lookup::Silo<'_>, ) -> LookupResult> { - let (.., authz_silo) = LookupPath::new(opctx, &self.db_datastore) - .silo_name(silo_name) - .lookup_for(authz::Action::ReadPolicy) - .await?; + let (.., authz_silo) = + silo_lookup.lookup_for(authz::Action::ReadPolicy).await?; let role_assignments = self .db_datastore .role_assignment_fetch_visible(opctx, &authz_silo) @@ -97,24 +95,24 @@ impl super::Nexus { Ok(shared::Policy { role_assignments }) } + pub async fn silo_fetch_policy_by_name( + &self, + opctx: &OpContext, + silo_name: &Name, + ) -> LookupResult> { + let lookup = + LookupPath::new(opctx, &self.db_datastore).silo_name(silo_name); + self.silo_fetch_policy(opctx, lookup).await + } + pub async fn silo_fetch_policy_by_id( &self, opctx: &OpContext, silo_id: Uuid, ) -> LookupResult> { - let (.., authz_silo) = LookupPath::new(opctx, &self.db_datastore) - .silo_id(silo_id) - .lookup_for(authz::Action::ReadPolicy) - .await?; - let role_assignments = self - .db_datastore - .role_assignment_fetch_visible(opctx, &authz_silo) - .await? - .into_iter() - .map(|r| r.try_into().context("parsing database role assignment")) - .collect::, _>>() - .map_err(|error| Error::internal_error(&format!("{:#}", error)))?; - Ok(shared::Policy { role_assignments }) + let lookup = + LookupPath::new(opctx, &self.db_datastore).silo_id(silo_id); + self.silo_fetch_policy(opctx, lookup).await } pub async fn silo_update_policy( diff --git a/nexus/src/external_api/http_entrypoints.rs b/nexus/src/external_api/http_entrypoints.rs index 417cb662acb..ac1093d1e04 100644 --- a/nexus/src/external_api/http_entrypoints.rs +++ b/nexus/src/external_api/http_entrypoints.rs @@ -560,7 +560,7 @@ async fn silo_policy_view( let handler = async { let opctx = OpContext::for_external_api(&rqctx).await?; - let policy = nexus.silo_fetch_policy(&opctx, silo_name).await?; + let policy = nexus.silo_fetch_policy_by_name(&opctx, silo_name).await?; Ok(HttpResponseOk(policy)) }; apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await From 69ae4c1204d2ccfa93c4cd4d557becf75aa372b4 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Wed, 10 Aug 2022 23:26:32 -0500 Subject: [PATCH 8/8] clean it up. we are ready --- nexus/src/app/mod.rs | 10 ++++ nexus/src/app/silo.rs | 56 ++-------------------- nexus/src/external_api/http_entrypoints.rs | 17 ++++--- 3 files changed, 24 insertions(+), 59 deletions(-) diff --git a/nexus/src/app/mod.rs b/nexus/src/app/mod.rs index 50b1db65356..1ad0a3f34de 100644 --- a/nexus/src/app/mod.rs +++ b/nexus/src/app/mod.rs @@ -454,6 +454,16 @@ impl Nexus { let mid = self.samael_max_issue_delay.lock().unwrap(); *mid } + + // Convenience function that exists solely because writing + // LookupPath::new(&opctx, &nexus.datastore()) in an endpoint handler feels + // like too much + pub fn db_lookup<'a>( + &'a self, + opctx: &'a OpContext, + ) -> db::lookup::LookupPath { + db::lookup::LookupPath::new(opctx, &self.db_datastore) + } } /// For unimplemented endpoints, indicates whether the resource identified diff --git a/nexus/src/app/silo.rs b/nexus/src/app/silo.rs index b26f3f6fce7..52fe72ec8b9 100644 --- a/nexus/src/app/silo.rs +++ b/nexus/src/app/silo.rs @@ -77,7 +77,7 @@ impl super::Nexus { // Role assignments - async fn silo_fetch_policy( + pub async fn silo_fetch_policy( &self, opctx: &OpContext, silo_lookup: db::lookup::Silo<'_>, @@ -95,62 +95,14 @@ impl super::Nexus { Ok(shared::Policy { role_assignments }) } - pub async fn silo_fetch_policy_by_name( - &self, - opctx: &OpContext, - silo_name: &Name, - ) -> LookupResult> { - let lookup = - LookupPath::new(opctx, &self.db_datastore).silo_name(silo_name); - self.silo_fetch_policy(opctx, lookup).await - } - - pub async fn silo_fetch_policy_by_id( - &self, - opctx: &OpContext, - silo_id: Uuid, - ) -> LookupResult> { - let lookup = - LookupPath::new(opctx, &self.db_datastore).silo_id(silo_id); - self.silo_fetch_policy(opctx, lookup).await - } - pub async fn silo_update_policy( &self, opctx: &OpContext, - silo_name: &Name, - policy: &shared::Policy, - ) -> UpdateResult> { - let (.., authz_silo) = LookupPath::new(opctx, &self.db_datastore) - .silo_name(silo_name) - .lookup_for(authz::Action::ModifyPolicy) - .await?; - - let role_assignments = self - .db_datastore - .role_assignment_replace_visible( - opctx, - &authz_silo, - &policy.role_assignments, - ) - .await? - .into_iter() - .map(|r| r.try_into()) - .collect::, _>>()?; - - Ok(shared::Policy { role_assignments }) - } - - pub async fn silo_update_policy_by_id( - &self, - opctx: &OpContext, - silo_id: Uuid, + silo_lookup: db::lookup::Silo<'_>, policy: &shared::Policy, ) -> UpdateResult> { - let (.., authz_silo) = LookupPath::new(opctx, &self.db_datastore) - .silo_id(silo_id) - .lookup_for(authz::Action::ModifyPolicy) - .await?; + let (.., authz_silo) = + silo_lookup.lookup_for(authz::Action::ModifyPolicy).await?; let role_assignments = self .db_datastore diff --git a/nexus/src/external_api/http_entrypoints.rs b/nexus/src/external_api/http_entrypoints.rs index ac1093d1e04..caabbf9f2ed 100644 --- a/nexus/src/external_api/http_entrypoints.rs +++ b/nexus/src/external_api/http_entrypoints.rs @@ -384,8 +384,9 @@ pub async fn policy_view( .authn .silo_required() .internal_context("loading current silo")?; - let policy = - nexus.silo_fetch_policy_by_id(&opctx, authz_silo.id()).await?; + + let lookup = nexus.db_lookup(&opctx).silo_id(authz_silo.id()); + let policy = nexus.silo_fetch_policy(&opctx, lookup).await?; Ok(HttpResponseOk(policy)) }; apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await @@ -414,9 +415,9 @@ async fn policy_update( .authn .silo_required() .internal_context("loading current silo")?; - let policy = nexus - .silo_update_policy_by_id(&opctx, authz_silo.id(), &new_policy) - .await?; + let lookup = nexus.db_lookup(&opctx).silo_id(authz_silo.id()); + let policy = + nexus.silo_update_policy(&opctx, lookup, &new_policy).await?; Ok(HttpResponseOk(policy)) }; apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await @@ -560,7 +561,8 @@ async fn silo_policy_view( let handler = async { let opctx = OpContext::for_external_api(&rqctx).await?; - let policy = nexus.silo_fetch_policy_by_name(&opctx, silo_name).await?; + let lookup = nexus.db_lookup(&opctx).silo_name(silo_name); + let policy = nexus.silo_fetch_policy(&opctx, lookup).await?; Ok(HttpResponseOk(policy)) }; apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await @@ -588,8 +590,9 @@ async fn silo_policy_update( // This should have been validated during parsing. bail_unless!(nasgns <= shared::MAX_ROLE_ASSIGNMENTS_PER_RESOURCE); let opctx = OpContext::for_external_api(&rqctx).await?; + let lookup = nexus.db_lookup(&opctx).silo_name(silo_name); let policy = - nexus.silo_update_policy(&opctx, silo_name, &new_policy).await?; + nexus.silo_update_policy(&opctx, lookup, &new_policy).await?; Ok(HttpResponseOk(policy)) }; apictx.external_latencies.instrument_dropshot_handler(&rqctx, handler).await