diff --git a/compute_tools/src/spec.rs b/compute_tools/src/spec.rs index 1d19f2738d..a76af21e9f 100644 --- a/compute_tools/src/spec.rs +++ b/compute_tools/src/spec.rs @@ -8,13 +8,12 @@ use compute_api::responses::{ use compute_api::spec::ComputeSpec; use reqwest::StatusCode; use tokio_postgres::Client; -use tracing::{error, info, instrument, warn}; +use tracing::{error, info, instrument}; use crate::config; use crate::metrics::{CPLANE_REQUESTS_TOTAL, CPlaneRequestRPC, UNKNOWN_HTTP_STATUS}; use crate::migration::MigrationRunner; use crate::params::PG_HBA_ALL_MD5; -use crate::pg_helpers::*; // Do control plane request and return response if any. In case of error it // returns a bool flag indicating whether it makes sense to retry the request @@ -212,122 +211,3 @@ pub async fn handle_migrations(client: &mut Client) -> Result<()> { Ok(()) } - -/// Connect to the database as superuser and pre-create anon extension -/// if it is present in shared_preload_libraries -#[instrument(skip_all)] -pub async fn handle_extension_anon( - spec: &ComputeSpec, - db_owner: &str, - db_client: &mut Client, - grants_only: bool, -) -> Result<()> { - info!("handle extension anon"); - - if let Some(libs) = spec.cluster.settings.find("shared_preload_libraries") { - if libs.contains("anon") { - if !grants_only { - // check if extension is already initialized using anon.is_initialized() - let query = "SELECT anon.is_initialized()"; - match db_client.query(query, &[]).await { - Ok(rows) => { - if !rows.is_empty() { - let is_initialized: bool = rows[0].get(0); - if is_initialized { - info!("anon extension is already initialized"); - return Ok(()); - } - } - } - Err(e) => { - warn!( - "anon extension is_installed check failed with expected error: {}", - e - ); - } - }; - - // Create anon extension if this compute needs it - // Users cannot create it themselves, because superuser is required. - let mut query = "CREATE EXTENSION IF NOT EXISTS anon CASCADE"; - info!("creating anon extension with query: {}", query); - match db_client.query(query, &[]).await { - Ok(_) => {} - Err(e) => { - error!("anon extension creation failed with error: {}", e); - return Ok(()); - } - } - - // check that extension is installed - query = "SELECT extname FROM pg_extension WHERE extname = 'anon'"; - let rows = db_client.query(query, &[]).await?; - if rows.is_empty() { - error!("anon extension is not installed"); - return Ok(()); - } - - // Initialize anon extension - // This also requires superuser privileges, so users cannot do it themselves. - query = "SELECT anon.init()"; - match db_client.query(query, &[]).await { - Ok(_) => {} - Err(e) => { - error!("anon.init() failed with error: {}", e); - return Ok(()); - } - } - } - - // check that extension is installed, if not bail early - let query = "SELECT extname FROM pg_extension WHERE extname = 'anon'"; - match db_client.query(query, &[]).await { - Ok(rows) => { - if rows.is_empty() { - error!("anon extension is not installed"); - return Ok(()); - } - } - Err(e) => { - error!("anon extension check failed with error: {}", e); - return Ok(()); - } - }; - - let query = format!("GRANT ALL ON SCHEMA anon TO {}", db_owner); - info!("granting anon extension permissions with query: {}", query); - db_client.simple_query(&query).await?; - - // Grant permissions to db_owner to use anon extension functions - let query = format!("GRANT ALL ON ALL FUNCTIONS IN SCHEMA anon TO {}", db_owner); - info!("granting anon extension permissions with query: {}", query); - db_client.simple_query(&query).await?; - - // This is needed, because some functions are defined as SECURITY DEFINER. - // In Postgres SECURITY DEFINER functions are executed with the privileges - // of the owner. - // In anon extension this it is needed to access some GUCs, which are only accessible to - // superuser. But we've patched postgres to allow db_owner to access them as well. - // So we need to change owner of these functions to db_owner. - let query = format!(" - SELECT 'ALTER FUNCTION '||nsp.nspname||'.'||p.proname||'('||pg_get_function_identity_arguments(p.oid)||') OWNER TO {};' - from pg_proc p - join pg_namespace nsp ON p.pronamespace = nsp.oid - where nsp.nspname = 'anon';", db_owner); - - info!("change anon extension functions owner to db owner"); - db_client.simple_query(&query).await?; - - // affects views as well - let query = format!("GRANT ALL ON ALL TABLES IN SCHEMA anon TO {}", db_owner); - info!("granting anon extension permissions with query: {}", query); - db_client.simple_query(&query).await?; - - let query = format!("GRANT ALL ON ALL SEQUENCES IN SCHEMA anon TO {}", db_owner); - info!("granting anon extension permissions with query: {}", query); - db_client.simple_query(&query).await?; - } - } - - Ok(()) -} diff --git a/compute_tools/src/spec_apply.rs b/compute_tools/src/spec_apply.rs index e5f7aebbf8..80506b13cb 100644 --- a/compute_tools/src/spec_apply.rs +++ b/compute_tools/src/spec_apply.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use anyhow::{Context, Result}; use compute_api::responses::ComputeStatus; -use compute_api::spec::{ComputeAudit, ComputeFeature, ComputeSpec, Database, PgIdent, Role}; +use compute_api::spec::{ComputeAudit, ComputeSpec, Database, PgIdent, Role}; use futures::future::join_all; use tokio::sync::RwLock; use tokio_postgres::Client; @@ -26,7 +26,7 @@ use crate::spec_apply::ApplySpecPhase::{ RunInEachDatabase, }; use crate::spec_apply::PerDatabasePhase::{ - ChangeSchemaPerms, DeleteDBRoleReferences, DropLogicalSubscriptions, HandleAnonExtension, + ChangeSchemaPerms, DeleteDBRoleReferences, DropLogicalSubscriptions, }; impl ComputeNode { @@ -238,7 +238,6 @@ impl ComputeNode { let mut phases = vec![ DeleteDBRoleReferences, ChangeSchemaPerms, - HandleAnonExtension, ]; if spec.drop_subscriptions_before_start && !drop_subscriptions_done { @@ -458,7 +457,6 @@ impl Debug for DB { pub enum PerDatabasePhase { DeleteDBRoleReferences, ChangeSchemaPerms, - HandleAnonExtension, /// This is a shared phase, used for both i) dropping dangling LR subscriptions /// before dropping the DB, and ii) dropping all subscriptions after creating /// a fresh branch. @@ -1012,98 +1010,6 @@ async fn get_operations<'a>( ] .into_iter(); - Ok(Box::new(operations)) - } - // TODO: remove this completely https://github.com/neondatabase/cloud/issues/22663 - PerDatabasePhase::HandleAnonExtension => { - // Only install Anon into user databases - let db = match &db { - DB::SystemDB => return Ok(Box::new(empty())), - DB::UserDB(db) => db, - }; - // Never install Anon when it's not enabled as feature - if !spec.features.contains(&ComputeFeature::AnonExtension) { - return Ok(Box::new(empty())); - } - - // Only install Anon when it's added in preload libraries - let opt_libs = spec.cluster.settings.find("shared_preload_libraries"); - - let libs = match opt_libs { - Some(libs) => libs, - None => return Ok(Box::new(empty())), - }; - - if !libs.contains("anon") { - return Ok(Box::new(empty())); - } - - let db_owner = db.owner.pg_quote(); - - let operations = vec![ - // Create anon extension if this compute needs it - // Users cannot create it themselves, because superuser is required. - Operation { - query: String::from("CREATE EXTENSION IF NOT EXISTS anon CASCADE"), - comment: Some(String::from("creating anon extension")), - }, - // Initialize anon extension - // This also requires superuser privileges, so users cannot do it themselves. - Operation { - query: String::from("SELECT anon.init()"), - comment: Some(String::from("initializing anon extension data")), - }, - Operation { - query: format!("GRANT ALL ON SCHEMA anon TO {}", db_owner), - comment: Some(String::from( - "granting anon extension schema permissions", - )), - }, - Operation { - query: format!( - "GRANT ALL ON ALL FUNCTIONS IN SCHEMA anon TO {}", - db_owner - ), - comment: Some(String::from( - "granting anon extension schema functions permissions", - )), - }, - // We need this, because some functions are defined as SECURITY DEFINER. - // In Postgres SECURITY DEFINER functions are executed with the privileges - // of the owner. - // In anon extension this it is needed to access some GUCs, which are only accessible to - // superuser. But we've patched postgres to allow db_owner to access them as well. - // So we need to change owner of these functions to db_owner. - Operation { - query: format!( - include_str!("sql/anon_ext_fn_reassign.sql"), - db_owner = db_owner, - ), - comment: Some(String::from( - "change anon extension functions owner to database_owner", - )), - }, - Operation { - query: format!( - "GRANT ALL ON ALL TABLES IN SCHEMA anon TO {}", - db_owner, - ), - comment: Some(String::from( - "granting anon extension tables permissions", - )), - }, - Operation { - query: format!( - "GRANT ALL ON ALL SEQUENCES IN SCHEMA anon TO {}", - db_owner, - ), - comment: Some(String::from( - "granting anon extension sequences permissions", - )), - }, - ] - .into_iter(); - Ok(Box::new(operations)) } } diff --git a/libs/compute_api/src/spec.rs b/libs/compute_api/src/spec.rs index 868a14edeb..11615b73a1 100644 --- a/libs/compute_api/src/spec.rs +++ b/libs/compute_api/src/spec.rs @@ -179,9 +179,6 @@ pub enum ComputeFeature { /// track short-lived connections as user activity. ActivityMonitorExperimental, - /// Pre-install and initialize anon extension for every database in the cluster - AnonExtension, - /// Allow to configure rsyslog for Postgres logs export PostgresLogsExport, diff --git a/libs/compute_api/tests/cluster_spec.json b/libs/compute_api/tests/cluster_spec.json index ccd015ad19..37de24be5b 100644 --- a/libs/compute_api/tests/cluster_spec.json +++ b/libs/compute_api/tests/cluster_spec.json @@ -208,7 +208,6 @@ ], "remote_extensions": { "library_index": { - "anon": "anon", "postgis-3": "postgis", "libpgrouting-3.4": "postgis", "postgis_raster-3": "postgis", @@ -217,12 +216,6 @@ "address_standardizer-3": "postgis" }, "extension_data": { - "anon": { - "archive_path": "5834329303/v15/extensions/anon.tar.zst", - "control_data": { - "anon.control": "# PostgreSQL Anonymizer (anon) extension\ncomment = ''Data anonymization tools''\ndefault_version = ''1.1.0''\ndirectory=''extension/anon''\nrelocatable = false\nrequires = ''pgcrypto''\nsuperuser = false\nmodule_pathname = ''$libdir/anon''\ntrusted = true\n" - } - }, "postgis": { "archive_path": "5834329303/v15/extensions/postgis.tar.zst", "control_data": { @@ -238,7 +231,6 @@ } }, "custom_extensions": [ - "anon" ], "public_extensions": [ "postgis"