Merge branch 'joeyconfig'

This commit is contained in:
Joey Hess 2014-11-11 13:47:25 -04:00
commit 08ff95fbfa
7 changed files with 144 additions and 72 deletions

2
debian/changelog vendored
View File

@ -2,6 +2,8 @@ propellor (0.9.3) UNRELEASED; urgency=medium
* Added prosody module, contributed by 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

View File

@ -1,6 +1,14 @@
To support multiple gpg keys added with --add-key, propellor should
* 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,
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]]

View File

@ -113,7 +113,9 @@ Library
Other-Modules:
Propellor.Types.Info
Propellor.CmdLine
Propellor.Gpg
Propellor.SimpleSh
Propellor.PrivData.Paths
Propellor.Property.Docker.Shim
Utility.Applicative
Utility.Data

View File

@ -13,6 +13,8 @@ import System.Posix.IO
import Data.Time.Clock.POSIX
import Propellor
import Propellor.PrivData.Paths
import Propellor.Gpg
import qualified Propellor.Property.Docker as Docker
import qualified Propellor.Property.Docker.Shim as DockerShim
import Utility.FileMode
@ -303,48 +305,6 @@ boot h = do
fromMarked privDataMarker reply
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 = maybe nourl return =<< getM get urls
where

115
src/Propellor/Gpg.hs Normal file
View File

@ -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

View File

@ -3,7 +3,6 @@
module Propellor.PrivData where
import Control.Applicative
import System.FilePath
import System.IO
import System.Directory
import Data.Maybe
@ -19,10 +18,11 @@ import Propellor.Types
import Propellor.Types.Info
import Propellor.Message
import Propellor.Info
import Propellor.Gpg
import Propellor.PrivData.Paths
import Utility.Monad
import Utility.PartialPrelude
import Utility.Exception
import Utility.Process
import Utility.Tmp
import Utility.SafeCommand
import Utility.Misc
@ -146,30 +146,3 @@ decryptPrivData = fromMaybe M.empty . readish <$> gpgDecrypt privDataFile
makePrivDataDir :: IO ()
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

View File

@ -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"