add config option server-unix-socket-mode (#1415)

* added config option server-unix-socket-mode to enable custom socket permissions

* added server-unix-socket-mode input validation
This commit is contained in:
Dan Amoroso
2019-11-23 10:52:33 -05:00
committed by Steve Chavez
parent f9c64d9f65
commit 2e6c78d723
5 changed files with 38 additions and 6 deletions
+1
View File
@@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added ### Added
- #1415, Add support for user defined socket permission via `server-unix-socket-mode` config option - @Dansvidania
- #1383, Add support for HEAD request - @steve-chavez - #1383, Add support for HEAD request - @steve-chavez
- #1378, Add support for `Prefer: count=planned` and `Prefer: count=estimated` on GET /table - @steve-chavez - #1378, Add support for `Prefer: count=planned` and `Prefer: count=estimated` on GET /table - @steve-chavez
+13 -6
View File
@@ -12,6 +12,7 @@ import Control.AutoUpdate (defaultUpdateSettings, mkAutoUpdate,
import Control.Retry (RetryStatus, capDelay, import Control.Retry (RetryStatus, capDelay,
exponentialBackoff, retrying, exponentialBackoff, retrying,
rsPreviousDelay) rsPreviousDelay)
import Data.Either.Combinators (whenLeft)
import Data.IORef (IORef, atomicWriteIORef, newIORef, import Data.IORef (IORef, atomicWriteIORef, newIORef,
readIORef) readIORef)
import Data.String (IsString (..)) import Data.String (IsString (..))
@@ -31,6 +32,8 @@ import Network.Wai.Handler.Warp (defaultSettings, runSettings,
import System.Directory (removeFile) import System.Directory (removeFile)
import System.IO (BufferMode (..), hSetBuffering) import System.IO (BufferMode (..), hSetBuffering)
import System.IO.Error (isDoesNotExistError) import System.IO.Error (isDoesNotExistError)
import System.Posix.Files (setFileMode)
import System.Posix.Types (FileMode)
import PostgREST.App (postgrest) import PostgREST.App (postgrest)
import PostgREST.Config (AppConfig (..), configPoolTimeout', import PostgREST.Config (AppConfig (..), configPoolTimeout',
@@ -163,6 +166,7 @@ main = do
port = configPort conf port = configPort conf
proxy = configProxyUri conf proxy = configProxyUri conf
maybeSocketAddr = configSocket conf maybeSocketAddr = configSocket conf
socketFileMode = configSocketMode conf
pgSettings = toS (configDatabase conf) -- is the db-uri pgSettings = toS (configDatabase conf) -- is the db-uri
roleClaimKey = configRoleClaimKey conf roleClaimKey = configRoleClaimKey conf
appSettings = appSettings =
@@ -171,13 +175,15 @@ main = do
. setServerName (toS $ "postgrest/" <> prettyVersion) $ . setServerName (toS $ "postgrest/" <> prettyVersion) $
defaultSettings defaultSettings
whenLeft socketFileMode panic
-- Checks that the provided proxy uri is formated correctly -- Checks that the provided proxy uri is formated correctly
when (isMalformedProxyUri $ toS <$> proxy) $ when (isMalformedProxyUri $ toS <$> proxy) $
panic panic
"Malformed proxy uri, a correct example: https://example.com:8443/basePath" "Malformed proxy uri, a correct example: https://example.com:8443/basePath"
-- Checks that the provided jspath is valid -- Checks that the provided jspath is valid
when (isLeft roleClaimKey) $ whenLeft roleClaimKey $
panic $ show roleClaimKey panic $ show roleClaimKey
-- --
@@ -250,7 +256,7 @@ main = do
runSettings appSettings postgrestApplication runSettings appSettings postgrestApplication
Just socketAddr -> do Just socketAddr -> do
-- run postgrest application with user defined socket -- run postgrest application with user defined socket
sock <- createAndBindSocket (unpack socketAddr) sock <- createAndBindSocket (unpack socketAddr) (rightToMaybe socketFileMode)
listen sock maxListenQueue listen sock maxListenQueue
putStrLn $ ("Listening on unix socket " :: Text) <> show socketAddr putStrLn $ ("Listening on unix socket " :: Text) <> show socketAddr
runSettingsSocket appSettings sock postgrestApplication runSettingsSocket appSettings sock postgrestApplication
@@ -324,11 +330,12 @@ loadDbUriFile conf = extractDbUri mDbUri
Just filename -> strip <$> readFile (toS filename) Just filename -> strip <$> readFile (toS filename)
setDbUri dbUri = conf {configDatabase = dbUri} setDbUri dbUri = conf {configDatabase = dbUri}
createAndBindSocket :: FilePath -> IO Socket createAndBindSocket :: FilePath -> Maybe FileMode -> IO Socket
createAndBindSocket filePath = do createAndBindSocket socketFilePath maybeSocketFileMode = do
deleteSocketFileIfExist filePath deleteSocketFileIfExist socketFilePath
sock <- socket AF_UNIX Stream defaultProtocol sock <- socket AF_UNIX Stream defaultProtocol
bind sock $ SockAddrUnix filePath bind sock $ SockAddrUnix socketFilePath
mapM_ (setFileMode socketFilePath) maybeSocketFileMode
return sock return sock
where where
deleteSocketFileIfExist path = removeFile path `catch` handleDoesNotExist deleteSocketFileIfExist path = removeFile path `catch` handleDoesNotExist
+1
View File
@@ -97,6 +97,7 @@ executable postgrest
, base64-bytestring >= 1 && < 1.1 , base64-bytestring >= 1 && < 1.1
, bytestring >= 0.10.8 && < 0.11 , bytestring >= 0.10.8 && < 0.11
, directory >= 1.2.6 && < 1.4 , directory >= 1.2.6 && < 1.4
, either >= 4.4.1 && < 5.1
, hasql >= 1.4 && < 1.5 , hasql >= 1.4 && < 1.5
, hasql-pool >= 0.5 && < 0.6 , hasql-pool >= 0.5 && < 0.6
, hasql-transaction >= 0.7.2 && < 0.8 , hasql-transaction >= 0.7.2 && < 0.8
+21
View File
@@ -46,8 +46,10 @@ import Data.Text.IO (hPutStrLn)
import Data.Version (versionBranch) import Data.Version (versionBranch)
import Development.GitRev (gitHash) import Development.GitRev (gitHash)
import Network.Wai.Middleware.Cors (CorsResourcePolicy (..)) import Network.Wai.Middleware.Cors (CorsResourcePolicy (..))
import Numeric (readOct)
import Paths_postgrest (version) import Paths_postgrest (version)
import System.IO.Error (IOError) import System.IO.Error (IOError)
import System.Posix.Types (FileMode)
import Control.Applicative import Control.Applicative
import Data.Monoid import Data.Monoid
@@ -63,6 +65,7 @@ import Protolude hiding (concat, hPutStrLn, intercalate, null,
take, (<>)) take, (<>))
-- | Config file settings for the server -- | Config file settings for the server
data AppConfig = AppConfig { data AppConfig = AppConfig {
configDatabase :: Text configDatabase :: Text
@@ -72,6 +75,7 @@ data AppConfig = AppConfig {
, configHost :: Text , configHost :: Text
, configPort :: Int , configPort :: Int
, configSocket :: Maybe Text , configSocket :: Maybe Text
, configSocketMode :: Either Text FileMode
, configJwtSecret :: Maybe B.ByteString , configJwtSecret :: Maybe B.ByteString
, configJwtSecretIsBase64 :: Bool , configJwtSecretIsBase64 :: Bool
@@ -155,6 +159,7 @@ readOptions = do
<*> (fromMaybe "!4" <$> optString "server-host") <*> (fromMaybe "!4" <$> optString "server-host")
<*> (fromMaybe 3000 <$> optInt "server-port") <*> (fromMaybe 3000 <$> optInt "server-port")
<*> optString "server-unix-socket" <*> optString "server-unix-socket"
<*> parseSocketFileMode "server-unix-socket-mode"
<*> (fmap encodeUtf8 <$> optString "jwt-secret") <*> (fmap encodeUtf8 <$> optString "jwt-secret")
<*> (fromMaybe False <$> optBool "secret-is-base64") <*> (fromMaybe False <$> optBool "secret-is-base64")
<*> parseJwtAudience "jwt-aud" <*> parseJwtAudience "jwt-aud"
@@ -169,6 +174,19 @@ readOptions = do
<*> optString "root-spec" <*> optString "root-spec"
<*> (maybe [] (fmap encodeUtf8 . splitOnCommas) <$> optValue "raw-media-types") <*> (maybe [] (fmap encodeUtf8 . splitOnCommas) <$> optValue "raw-media-types")
parseSocketFileMode :: C.Key -> C.Parser C.Config (Either Text FileMode)
parseSocketFileMode k =
C.optional k C.string >>= \case
Nothing -> pure $ Right 493 -- return default 755 mode if no value was provided
Just fileModeText ->
case (readOct . unpack) fileModeText of
[] ->
pure $ Left "Invalid server-unix-socket-mode: not an octal"
(fileMode, _):_ ->
if fileMode < 384 || fileMode > 511
then pure $ Left "Invalid server-unix-socket-mode: needs to be between 600 and 777"
else pure $ Right fileMode
parseJwtAudience :: C.Key -> C.Parser C.Config (Maybe StringOrURI) parseJwtAudience :: C.Key -> C.Parser C.Config (Maybe StringOrURI)
parseJwtAudience k = parseJwtAudience k =
C.optional k C.string >>= \case C.optional k C.string >>= \case
@@ -248,6 +266,9 @@ readOptions = do
|## unix socket location |## unix socket location
|## if specified it takes precedence over server-port |## if specified it takes precedence over server-port
|# server-unix-socket = "/tmp/pgrst.sock" |# server-unix-socket = "/tmp/pgrst.sock"
|## unix socket file mode
|## when none is provided, 755 is applied by default
|# server-unix-socket-mode = "755"
| |
|## base url for swagger output |## base url for swagger output
|# server-proxy-uri = "" |# server-proxy-uri = ""
+2
View File
@@ -66,6 +66,8 @@ _baseCfg = -- Connection Settings
AppConfig mempty "postgrest_test_anonymous" Nothing "test" "localhost" 3000 AppConfig mempty "postgrest_test_anonymous" Nothing "test" "localhost" 3000
-- No user configured Unix Socket -- No user configured Unix Socket
Nothing Nothing
-- No user configured Unix Socket file mode (defaults to 755)
(Right 493)
-- Jwt settings -- Jwt settings
(Just $ encodeUtf8 "reallyreallyreallyreallyverysafe") False Nothing (Just $ encodeUtf8 "reallyreallyreallyreallyverysafe") False Nothing
-- Connection Modifiers -- Connection Modifiers