Merge branch 'joeyconfig'
This commit is contained in:
commit
08ff95fbfa
|
@ -2,6 +2,8 @@ propellor (0.9.3) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
* Added prosody module, contributed by Félix Sipma.
|
* Added prosody module, contributed by Félix Sipma.
|
||||||
* Can be used to configure tor hidden services. Thanks, Félix Sipma.
|
* Can be used to configure tor hidden services. Thanks, Félix Sipma.
|
||||||
|
* When multiple gpg keys are added, ensure that the privdata file
|
||||||
|
can be decrypted by all of them.
|
||||||
|
|
||||||
-- Joey Hess <joeyh@debian.org> Mon, 10 Nov 2014 11:15:27 -0400
|
-- Joey Hess <joeyh@debian.org> Mon, 10 Nov 2014 11:15:27 -0400
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
To support multiple gpg keys added with --add-key, propellor should
|
To support multiple gpg keys added with --add-key, propellor should
|
||||||
|
|
||||||
* When it encrypts the privdata after a change, encrypt it to all keys
|
* When it encrypts the privdata after a change, encrypt it to all keys
|
||||||
listed in `privdata/keyring.gpg`
|
listed in `privdata/keyring.gpg`. See [this
|
||||||
|
post](http://laurent.bachelier.name/2013/03/gpg-encryption-to-multiple-recipients/)
|
||||||
|
explaining why and how encryption with multiple recipients work.
|
||||||
* When --add-key adds a new key, it should re-encrypt the privdata,
|
* When --add-key adds a new key, it should re-encrypt the privdata,
|
||||||
so that this new key can access it.
|
so that this new key can access it.
|
||||||
|
* When --add-key on behalf of another user, do not modify the signing key for
|
||||||
|
local git. This entails either splitting this command in two, `--add-key` and
|
||||||
|
`--set-signing-key`, or adding another command `--add-foreign-key`,
|
||||||
|
or perhaps determining if the key being added has a known secret key.
|
||||||
|
|
||||||
|
[[done]]
|
||||||
|
|
|
@ -113,7 +113,9 @@ Library
|
||||||
Other-Modules:
|
Other-Modules:
|
||||||
Propellor.Types.Info
|
Propellor.Types.Info
|
||||||
Propellor.CmdLine
|
Propellor.CmdLine
|
||||||
|
Propellor.Gpg
|
||||||
Propellor.SimpleSh
|
Propellor.SimpleSh
|
||||||
|
Propellor.PrivData.Paths
|
||||||
Propellor.Property.Docker.Shim
|
Propellor.Property.Docker.Shim
|
||||||
Utility.Applicative
|
Utility.Applicative
|
||||||
Utility.Data
|
Utility.Data
|
||||||
|
|
|
@ -13,6 +13,8 @@ import System.Posix.IO
|
||||||
import Data.Time.Clock.POSIX
|
import Data.Time.Clock.POSIX
|
||||||
|
|
||||||
import Propellor
|
import Propellor
|
||||||
|
import Propellor.PrivData.Paths
|
||||||
|
import Propellor.Gpg
|
||||||
import qualified Propellor.Property.Docker as Docker
|
import qualified Propellor.Property.Docker as Docker
|
||||||
import qualified Propellor.Property.Docker.Shim as DockerShim
|
import qualified Propellor.Property.Docker.Shim as DockerShim
|
||||||
import Utility.FileMode
|
import Utility.FileMode
|
||||||
|
@ -303,48 +305,6 @@ boot h = do
|
||||||
fromMarked privDataMarker reply
|
fromMarked privDataMarker reply
|
||||||
mainProperties h
|
mainProperties h
|
||||||
|
|
||||||
addKey :: String -> IO ()
|
|
||||||
addKey keyid = exitBool =<< allM id [ gpg, gitadd, gitconfig, gitcommit ]
|
|
||||||
where
|
|
||||||
gpg = do
|
|
||||||
createDirectoryIfMissing True privDataDir
|
|
||||||
boolSystem "sh"
|
|
||||||
[ Param "-c"
|
|
||||||
, Param $ "gpg --export " ++ keyid ++ " | gpg " ++
|
|
||||||
unwords (gpgopts ++ ["--import"])
|
|
||||||
]
|
|
||||||
gitadd = boolSystem "git"
|
|
||||||
[ Param "add"
|
|
||||||
, File keyring
|
|
||||||
]
|
|
||||||
|
|
||||||
gitconfig = boolSystem "git"
|
|
||||||
[ Param "config"
|
|
||||||
, Param "user.signingkey"
|
|
||||||
, Param keyid
|
|
||||||
]
|
|
||||||
|
|
||||||
gitcommit = gitCommit
|
|
||||||
[ File keyring
|
|
||||||
, Param "-m"
|
|
||||||
, Param "propellor addkey"
|
|
||||||
]
|
|
||||||
|
|
||||||
{- Automatically sign the commit if there'a a keyring. -}
|
|
||||||
gitCommit :: [CommandParam] -> IO Bool
|
|
||||||
gitCommit ps = do
|
|
||||||
k <- doesFileExist keyring
|
|
||||||
boolSystem "git" $ catMaybes $
|
|
||||||
[ Just (Param "commit")
|
|
||||||
, if k then Just (Param "--gpg-sign") else Nothing
|
|
||||||
] ++ map Just ps
|
|
||||||
|
|
||||||
keyring :: FilePath
|
|
||||||
keyring = privDataDir </> "keyring.gpg"
|
|
||||||
|
|
||||||
gpgopts :: [String]
|
|
||||||
gpgopts = ["--options", "/dev/null", "--no-default-keyring", "--keyring", keyring]
|
|
||||||
|
|
||||||
getUrl :: IO String
|
getUrl :: IO String
|
||||||
getUrl = maybe nourl return =<< getM get urls
|
getUrl = maybe nourl return =<< getM get urls
|
||||||
where
|
where
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
module Propellor.Gpg where
|
||||||
|
|
||||||
|
import Control.Applicative
|
||||||
|
import System.IO
|
||||||
|
import System.FilePath
|
||||||
|
import System.Directory
|
||||||
|
import Data.Maybe
|
||||||
|
import Data.List.Utils
|
||||||
|
|
||||||
|
import Propellor.PrivData.Paths
|
||||||
|
import Propellor.Message
|
||||||
|
import Utility.SafeCommand
|
||||||
|
import Utility.Process
|
||||||
|
import Utility.Monad
|
||||||
|
import Utility.Misc
|
||||||
|
import Utility.Tmp
|
||||||
|
|
||||||
|
type KeyId = String
|
||||||
|
|
||||||
|
keyring :: FilePath
|
||||||
|
keyring = privDataDir </> "keyring.gpg"
|
||||||
|
|
||||||
|
-- Lists the keys in propellor's keyring.
|
||||||
|
listPubKeys :: IO [KeyId]
|
||||||
|
listPubKeys = parse . lines <$> readProcess "gpg" listopts
|
||||||
|
where
|
||||||
|
listopts = useKeyringOpts ++ ["--with-colons", "--list-public-keys"]
|
||||||
|
parse = mapMaybe (keyIdField . split ":")
|
||||||
|
keyIdField ("pub":_:_:_:f:_) = Just f
|
||||||
|
keyIdField _ = Nothing
|
||||||
|
|
||||||
|
useKeyringOpts :: [String]
|
||||||
|
useKeyringOpts =
|
||||||
|
[ "--options"
|
||||||
|
, "/dev/null"
|
||||||
|
, "--no-default-keyring"
|
||||||
|
, "--keyring", keyring
|
||||||
|
]
|
||||||
|
|
||||||
|
addKey :: KeyId -> IO ()
|
||||||
|
addKey keyid = exitBool =<< allM (uncurry actionMessage)
|
||||||
|
[ ("adding key to propellor's keyring", addkeyring)
|
||||||
|
, ("staging propellor's keyring", gitadd keyring)
|
||||||
|
, ("updating encryption of any privdata", reencryptprivdata)
|
||||||
|
, ("configuring git signing to use key", gitconfig)
|
||||||
|
, ("committing changes", gitcommit)
|
||||||
|
]
|
||||||
|
where
|
||||||
|
addkeyring = do
|
||||||
|
createDirectoryIfMissing True privDataDir
|
||||||
|
boolSystem "sh"
|
||||||
|
[ Param "-c"
|
||||||
|
, Param $ "gpg --export " ++ keyid ++ " | gpg " ++
|
||||||
|
unwords (useKeyringOpts ++ ["--import"])
|
||||||
|
]
|
||||||
|
|
||||||
|
reencryptprivdata = ifM (doesFileExist privDataFile)
|
||||||
|
( do
|
||||||
|
gpgEncrypt privDataFile =<< gpgDecrypt privDataFile
|
||||||
|
gitadd privDataFile
|
||||||
|
, return True
|
||||||
|
)
|
||||||
|
|
||||||
|
gitadd f = boolSystem "git"
|
||||||
|
[ Param "add"
|
||||||
|
, File f
|
||||||
|
]
|
||||||
|
|
||||||
|
gitconfig = ifM (snd <$> processTranscript "gpg" ["--list-secret-keys", keyid] Nothing)
|
||||||
|
( boolSystem "git"
|
||||||
|
[ Param "config"
|
||||||
|
, Param "user.signingkey"
|
||||||
|
, Param keyid
|
||||||
|
]
|
||||||
|
, do
|
||||||
|
warningMessage $ "Cannot find a secret key for key " ++ keyid ++ ", so not configuring git user.signingkey to use this key."
|
||||||
|
return True
|
||||||
|
)
|
||||||
|
|
||||||
|
gitcommit = gitCommit
|
||||||
|
[ File keyring
|
||||||
|
, Param "-m"
|
||||||
|
, Param "propellor addkey"
|
||||||
|
]
|
||||||
|
|
||||||
|
-- Automatically sign the commit if there'a a keyring.
|
||||||
|
gitCommit :: [CommandParam] -> IO Bool
|
||||||
|
gitCommit ps = do
|
||||||
|
k <- doesFileExist keyring
|
||||||
|
boolSystem "git" $ catMaybes $
|
||||||
|
[ Just (Param "commit")
|
||||||
|
, if k then Just (Param "--gpg-sign") else Nothing
|
||||||
|
] ++ map Just ps
|
||||||
|
|
||||||
|
gpgDecrypt :: FilePath -> IO String
|
||||||
|
gpgDecrypt f = ifM (doesFileExist f)
|
||||||
|
( readProcess "gpg" ["--decrypt", f]
|
||||||
|
, return ""
|
||||||
|
)
|
||||||
|
|
||||||
|
-- Encrypt file to all keys in propellor's keyring.
|
||||||
|
gpgEncrypt :: FilePath -> String -> IO ()
|
||||||
|
gpgEncrypt f s = do
|
||||||
|
keyids <- listPubKeys
|
||||||
|
let opts =
|
||||||
|
[ "--default-recipient-self"
|
||||||
|
, "--armor"
|
||||||
|
, "--encrypt"
|
||||||
|
, "--trust-model", "always"
|
||||||
|
] ++ concatMap (\k -> ["--recipient", k]) keyids
|
||||||
|
encrypted <- writeReadProcessEnv "gpg" opts
|
||||||
|
Nothing
|
||||||
|
(Just $ flip hPutStr s)
|
||||||
|
Nothing
|
||||||
|
viaTmp writeFile f encrypted
|
|
@ -3,7 +3,6 @@
|
||||||
module Propellor.PrivData where
|
module Propellor.PrivData where
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import System.FilePath
|
|
||||||
import System.IO
|
import System.IO
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
@ -19,10 +18,11 @@ import Propellor.Types
|
||||||
import Propellor.Types.Info
|
import Propellor.Types.Info
|
||||||
import Propellor.Message
|
import Propellor.Message
|
||||||
import Propellor.Info
|
import Propellor.Info
|
||||||
|
import Propellor.Gpg
|
||||||
|
import Propellor.PrivData.Paths
|
||||||
import Utility.Monad
|
import Utility.Monad
|
||||||
import Utility.PartialPrelude
|
import Utility.PartialPrelude
|
||||||
import Utility.Exception
|
import Utility.Exception
|
||||||
import Utility.Process
|
|
||||||
import Utility.Tmp
|
import Utility.Tmp
|
||||||
import Utility.SafeCommand
|
import Utility.SafeCommand
|
||||||
import Utility.Misc
|
import Utility.Misc
|
||||||
|
@ -146,30 +146,3 @@ decryptPrivData = fromMaybe M.empty . readish <$> gpgDecrypt privDataFile
|
||||||
|
|
||||||
makePrivDataDir :: IO ()
|
makePrivDataDir :: IO ()
|
||||||
makePrivDataDir = createDirectoryIfMissing False privDataDir
|
makePrivDataDir = createDirectoryIfMissing False privDataDir
|
||||||
|
|
||||||
privDataDir :: FilePath
|
|
||||||
privDataDir = "privdata"
|
|
||||||
|
|
||||||
privDataFile :: FilePath
|
|
||||||
privDataFile = privDataDir </> "privdata.gpg"
|
|
||||||
|
|
||||||
privDataLocal :: FilePath
|
|
||||||
privDataLocal = privDataDir </> "local"
|
|
||||||
|
|
||||||
gpgDecrypt :: FilePath -> IO String
|
|
||||||
gpgDecrypt f = ifM (doesFileExist f)
|
|
||||||
( readProcess "gpg" ["--decrypt", f]
|
|
||||||
, return ""
|
|
||||||
)
|
|
||||||
|
|
||||||
gpgEncrypt :: FilePath -> String -> IO ()
|
|
||||||
gpgEncrypt f s = do
|
|
||||||
encrypted <- writeReadProcessEnv "gpg"
|
|
||||||
[ "--default-recipient-self"
|
|
||||||
, "--armor"
|
|
||||||
, "--encrypt"
|
|
||||||
]
|
|
||||||
Nothing
|
|
||||||
(Just $ flip hPutStr s)
|
|
||||||
Nothing
|
|
||||||
viaTmp writeFile f encrypted
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
module Propellor.PrivData.Paths where
|
||||||
|
|
||||||
|
import System.FilePath
|
||||||
|
|
||||||
|
privDataDir :: FilePath
|
||||||
|
privDataDir = "privdata"
|
||||||
|
|
||||||
|
privDataFile :: FilePath
|
||||||
|
privDataFile = privDataDir </> "privdata.gpg"
|
||||||
|
|
||||||
|
privDataLocal :: FilePath
|
||||||
|
privDataLocal = privDataDir </> "local"
|
Loading…
Reference in New Issue