refactor: whitelist in-db config settings

This commit is contained in:
steve-chavez
2023-05-28 10:21:13 -05:00
committed by Steve Chavez
parent 009250006e
commit 8a3686d86b
3 changed files with 66 additions and 29 deletions
+3 -10
View File
@@ -358,21 +358,14 @@ parser optPath env dbSettings roleSettings =
(C.Key -> C.Parser C.Value a -> C.Parser C.Config b) -> (C.Key -> C.Parser C.Value a -> C.Parser C.Config b) ->
C.Key -> (C.Value -> a) -> C.Parser C.Config b C.Key -> (C.Value -> a) -> C.Parser C.Config b
overrideFromDbOrEnvironment necessity key coercion = overrideFromDbOrEnvironment necessity key coercion =
case reloadableDbSetting <|> M.lookup envVarName env of case dbConf <|> M.lookup envVarName env of
Just dbOrEnvVal -> pure $ justIfMaybe $ coercion $ C.String dbOrEnvVal Just dbOrEnvVal -> pure $ justIfMaybe $ coercion $ C.String dbOrEnvVal
Nothing -> necessity key (coercion <$> C.value) Nothing -> necessity key (coercion <$> C.value)
where where
dashToUnderscore '-' = '_' dashToUnderscore '-' = '_'
dashToUnderscore c = c dashToUnderscore c = c
envVarName = "PGRST_" <> (toUpper . dashToUnderscore <$> toS key) envVarName = "PGRST_" <> (toUpper . dashToUnderscore <$> toS key)
reloadableDbSetting = dbConf = lookup (T.pack $ dashToUnderscore <$> toS key) dbSettings
let dbSettingName = T.pack $ dashToUnderscore <$> toS key in
if dbSettingName `notElem` [
"server_host", "server_port", "server_unix_socket", "server_unix_socket_mode", "admin_server_port", "log_level",
"db_uri", "db_channel_enabled", "db_channel", "db_pool", "db_pool_acquisition_timeout",
"db_pool_max_lifetime", "db_pool_max_idletime", "db_config"]
then lookup dbSettingName dbSettings
else Nothing
coerceText :: C.Value -> Text coerceText :: C.Value -> Text
coerceText (C.String s) = s coerceText (C.String s) = s
+60 -19
View File
@@ -21,12 +21,40 @@ import qualified Hasql.Statement as SQL
import qualified Hasql.Transaction as SQL import qualified Hasql.Transaction as SQL
import qualified Hasql.Transaction.Sessions as SQL import qualified Hasql.Transaction.Sessions as SQL
import Text.InterpolatedString.Perl6 (q) import Text.InterpolatedString.Perl6 (q, qc)
import Protolude import Protolude
type RoleSettings = (HM.HashMap ByteString (HM.HashMap ByteString ByteString)) type RoleSettings = (HM.HashMap ByteString (HM.HashMap ByteString ByteString))
prefix :: Text
prefix = "pgrst."
-- | In-db settings names
dbSettingsNames :: [Text]
dbSettingsNames =
(prefix <>) <$>
["db_anon_role"
,"db_extra_search_path"
,"db_max_rows"
,"db_plan_enabled"
,"db_pre_request"
,"db_prepared_statements"
,"db_root_spec"
,"db_schemas"
,"db_tx_end"
,"db_use_legacy_gucs"
,"jwt_aud"
,"jwt_role_claim_key"
,"jwt_secret"
,"jwt_secret_is_base64"
,"openapi_mode"
,"openapi_security_active"
,"openapi_server_proxy_uri"
,"raw_media_types"
,"server_trace_header"
]
queryPgVersion :: Bool -> Session PgVersion queryPgVersion :: Bool -> Session PgVersion
queryPgVersion prepared = statement mempty $ pgVersionStatement prepared queryPgVersion prepared = statement mempty $ pgVersionStatement prepared
@@ -39,33 +67,40 @@ pgVersionStatement = SQL.Statement sql HE.noParams versionRow
queryDbSettings :: Bool -> Session [(Text, Text)] queryDbSettings :: Bool -> Session [(Text, Text)]
queryDbSettings prepared = queryDbSettings prepared =
let transaction = if prepared then SQL.transaction else SQL.unpreparedTransaction in let transaction = if prepared then SQL.transaction else SQL.unpreparedTransaction in
transaction SQL.ReadCommitted SQL.Read $ SQL.statement mempty $ dbSettingsStatement prepared transaction SQL.ReadCommitted SQL.Read $ SQL.statement dbSettingsNames $ dbSettingsStatement prepared
-- | Get db settings from the connection role. Global settings will be overridden by database specific settings. -- | Get db settings from the connection role. Global settings will be overridden by database specific settings.
dbSettingsStatement :: Bool -> SQL.Statement () [(Text, Text)] -- i.e. Doing:
dbSettingsStatement = SQL.Statement sql HE.noParams decodeSettings -- ALTER ROLE authenticator IN DATABASE postgres SET <prefix>jwt_aud = 'val';
-- ALTER ROLE authenticator SET <prefix>jwt_aud = 'overridden';
-- Will result in <prefix>jwt_aud = 'overridden'
--
-- A setting on the database only will have no effect
-- ALTER DATABASE postgres SET <prefix>jwt_aud = 'xx'
dbSettingsStatement :: Bool -> SQL.Statement [Text] [(Text, Text)]
dbSettingsStatement = SQL.Statement sql (arrayParam HE.text) decodeSettings
where where
sql = [q| sql = [qc|
WITH WITH
role_setting (database, setting) AS ( role_setting AS (
SELECT setdatabase, SELECT setdatabase as database,
unnest(setconfig) unnest(setconfig) as setting
FROM pg_catalog.pg_db_role_setting FROM pg_catalog.pg_db_role_setting
WHERE setrole = CURRENT_USER::regrole::oid WHERE setrole = CURRENT_USER::regrole::oid
AND setdatabase IN (0, (SELECT oid FROM pg_catalog.pg_database WHERE datname = CURRENT_CATALOG)) AND setdatabase IN (0, (SELECT oid FROM pg_catalog.pg_database WHERE datname = CURRENT_CATALOG))
), ),
kv_settings (database, k, v) AS ( kv_settings AS (
SELECT database, SELECT database,
substr(setting, 1, strpos(setting, '=') - 1), substr(setting, 1, strpos(setting, '=') - 1) as k,
substr(setting, strpos(setting, '=') + 1) substr(setting, strpos(setting, '=') + 1) as v
FROM role_setting FROM role_setting
WHERE setting LIKE 'pgrst.%'
) )
SELECT DISTINCT ON (key) SELECT DISTINCT ON (key)
replace(k, 'pgrst.', '') AS key, replace(k, '{prefix}', '') AS key,
v AS value v AS value
FROM kv_settings FROM kv_settings
ORDER BY key, database DESC; WHERE k = ANY($1)
ORDER BY key, database DESC;
|] |]
decodeSettings = HD.rowList $ (,) <$> column HD.text <*> column HD.text decodeSettings = HD.rowList $ (,) <$> column HD.text <*> column HD.text
@@ -111,3 +146,9 @@ compositeArrayColumn = arrayColumn . HD.composite
arrayColumn :: HD.Value a -> HD.Row [a] arrayColumn :: HD.Value a -> HD.Row [a]
arrayColumn = column . HD.listArray . HD.nonNullable arrayColumn = column . HD.listArray . HD.nonNullable
param :: HE.Value a -> HE.Params a
param = HE.param . HE.nonNullable
arrayParam :: HE.Value a -> HE.Params [a]
arrayParam = param . HE.foldableArray . HE.nonNullable
+3
View File
@@ -40,6 +40,9 @@ ALTER ROLE db_config_authenticator SET pgrst.db_channel_enabled = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_channel = 'ignored'; ALTER ROLE db_config_authenticator SET pgrst.db_channel = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_pool = 'ignored'; ALTER ROLE db_config_authenticator SET pgrst.db_pool = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_pool_timeout = 'ignored'; ALTER ROLE db_config_authenticator SET pgrst.db_pool_timeout = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_pool_acquisition_timeout = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_pool_max_lifetime = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_pool_max_idletime = 'ignored';
ALTER ROLE db_config_authenticator SET pgrst.db_config = 'ignored'; ALTER ROLE db_config_authenticator SET pgrst.db_config = 'ignored';
-- other authenticator reloadable config options -- other authenticator reloadable config options