From 347c02a38e120c973445195b86339ca358a0b50a Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 11 Nov 2014 12:32:17 -0400 Subject: split out gpg keyring related stuff --- src/Propellor/CmdLine.hs | 43 +------------------------------------------ src/Propellor/Keyring.hs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 42 deletions(-) create mode 100644 src/Propellor/Keyring.hs (limited to 'src') diff --git a/src/Propellor/CmdLine.hs b/src/Propellor/CmdLine.hs index 415b8576..51ff2095 100644 --- a/src/Propellor/CmdLine.hs +++ b/src/Propellor/CmdLine.hs @@ -13,6 +13,7 @@ import System.Posix.IO import Data.Time.Clock.POSIX import Propellor +import Propellor.Keyring import qualified Propellor.Property.Docker as Docker import qualified Propellor.Property.Docker.Shim as DockerShim import Utility.FileMode @@ -303,48 +304,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 diff --git a/src/Propellor/Keyring.hs b/src/Propellor/Keyring.hs new file mode 100644 index 00000000..8a9c833c --- /dev/null +++ b/src/Propellor/Keyring.hs @@ -0,0 +1,46 @@ +module Propellor.Keyring where + +import Propellor +import Utility.SafeCommand + +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] -- cgit v1.2.3 From f559ccaf738535ad4b0ebb0b520542055d8ae305 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 11 Nov 2014 12:33:04 -0400 Subject: reorg --- src/Propellor/Keyring.hs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/Propellor/Keyring.hs b/src/Propellor/Keyring.hs index 8a9c833c..c3018eb9 100644 --- a/src/Propellor/Keyring.hs +++ b/src/Propellor/Keyring.hs @@ -3,6 +3,9 @@ module Propellor.Keyring where import Propellor import Utility.SafeCommand +keyring :: FilePath +keyring = privDataDir "keyring.gpg" + addKey :: String -> IO () addKey keyid = exitBool =<< allM id [ gpg, gitadd, gitconfig, gitcommit ] where @@ -30,6 +33,13 @@ addKey keyid = exitBool =<< allM id [ gpg, gitadd, gitconfig, gitcommit ] , Param "propellor addkey" ] + gpgopts = + [ "--options" + , "/dev/null" + , "--no-default-keyring" + , "--keyring", keyring + ] + {- Automatically sign the commit if there'a a keyring. -} gitCommit :: [CommandParam] -> IO Bool gitCommit ps = do @@ -38,9 +48,3 @@ gitCommit ps = do [ 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] -- cgit v1.2.3 From 84304821bebf9b794fae56f616b50ae1d06014d2 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 11 Nov 2014 12:58:53 -0400 Subject: propellor spin --- propellor.cabal | 3 +- src/Propellor/CmdLine.hs | 3 +- src/Propellor/Gpg.hs | 101 ++++++++++++++++++++++++++++++++++++++++ src/Propellor/Keyring.hs | 50 -------------------- src/Propellor/PrivData.hs | 31 +----------- src/Propellor/PrivData/Paths.hs | 12 +++++ 6 files changed, 119 insertions(+), 81 deletions(-) create mode 100644 src/Propellor/Gpg.hs delete mode 100644 src/Propellor/Keyring.hs create mode 100644 src/Propellor/PrivData/Paths.hs (limited to 'src') diff --git a/propellor.cabal b/propellor.cabal index b24381f1..4da14192 100644 --- a/propellor.cabal +++ b/propellor.cabal @@ -113,8 +113,9 @@ Library Other-Modules: Propellor.Types.Info Propellor.CmdLine - Propellor.Keyring + Propellor.Gpg Propellor.SimpleSh + Propellor.PrivData.Paths Propellor.Property.Docker.Shim Utility.Applicative Utility.Data diff --git a/src/Propellor/CmdLine.hs b/src/Propellor/CmdLine.hs index 51ff2095..c3b792d1 100644 --- a/src/Propellor/CmdLine.hs +++ b/src/Propellor/CmdLine.hs @@ -13,7 +13,8 @@ import System.Posix.IO import Data.Time.Clock.POSIX import Propellor -import Propellor.Keyring +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 diff --git a/src/Propellor/Gpg.hs b/src/Propellor/Gpg.hs new file mode 100644 index 00000000..c65d06ec --- /dev/null +++ b/src/Propellor/Gpg.hs @@ -0,0 +1,101 @@ +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 Utility.SafeCommand +import Utility.Process +import Utility.Monad +import Utility.Misc +import Utility.Tmp + +type KeyId = String + +keyring :: FilePath +keyring = privDataDir "keyring.gpg" + +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 id + [ gpg, gitadd keyring, reencryptprivdata, gitconfig, gitcommit ] + where + gpg = 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 = 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 + +gpgDecrypt :: FilePath -> IO String +gpgDecrypt f = ifM (doesFileExist f) + ( readProcess "gpg" ["--decrypt", f] + , return "" + ) + +gpgEncrypt :: FilePath -> String -> IO () +gpgEncrypt f s = do + keyids <- listPubKeys + let opts = + [ "--default-recipient-self" + , "--armor" + , "--encrypt" + ] ++ concatMap (\k -> ["--recipient", k]) keyids + encrypted <- writeReadProcessEnv "gpg" opts + Nothing + (Just $ flip hPutStr s) + Nothing + viaTmp writeFile f encrypted diff --git a/src/Propellor/Keyring.hs b/src/Propellor/Keyring.hs deleted file mode 100644 index c3018eb9..00000000 --- a/src/Propellor/Keyring.hs +++ /dev/null @@ -1,50 +0,0 @@ -module Propellor.Keyring where - -import Propellor -import Utility.SafeCommand - -keyring :: FilePath -keyring = privDataDir "keyring.gpg" - -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" - ] - - gpgopts = - [ "--options" - , "/dev/null" - , "--no-default-keyring" - , "--keyring", keyring - ] - -{- 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 diff --git a/src/Propellor/PrivData.hs b/src/Propellor/PrivData.hs index f55ab74c..a5150432 100644 --- a/src/Propellor/PrivData.hs +++ b/src/Propellor/PrivData.hs @@ -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 diff --git a/src/Propellor/PrivData/Paths.hs b/src/Propellor/PrivData/Paths.hs new file mode 100644 index 00000000..7c29f1bf --- /dev/null +++ b/src/Propellor/PrivData/Paths.hs @@ -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" -- cgit v1.2.3 From 7ea0f460e6e3cd82e0ec3d4b1c2d6006b7c24619 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 11 Nov 2014 13:26:31 -0400 Subject: use --trust-model always to avoid prompt from gpg gpg prompts when encrypting to an untrusted key, but if propellor has been told to add a key, we implicitly trust it. --- src/Propellor/Gpg.hs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/Propellor/Gpg.hs b/src/Propellor/Gpg.hs index c65d06ec..e478f610 100644 --- a/src/Propellor/Gpg.hs +++ b/src/Propellor/Gpg.hs @@ -93,6 +93,7 @@ gpgEncrypt f s = do [ "--default-recipient-self" , "--armor" , "--encrypt" + , "--trust-model", "always" ] ++ concatMap (\k -> ["--recipient", k]) keyids encrypted <- writeReadProcessEnv "gpg" opts Nothing -- cgit v1.2.3 From e4f9df8404b8a7a2358e920dc2a231a3df823d6d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 11 Nov 2014 13:41:25 -0400 Subject: avoid configuring git signing key when there's no secret key Also, nice display for --add-key steps --- doc/todo/multi_gpg_key_privdata.mdwn | 3 ++- src/Propellor/Gpg.hs | 31 ++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/doc/todo/multi_gpg_key_privdata.mdwn b/doc/todo/multi_gpg_key_privdata.mdwn index 1d9b05a4..f7475c13 100644 --- a/doc/todo/multi_gpg_key_privdata.mdwn +++ b/doc/todo/multi_gpg_key_privdata.mdwn @@ -8,4 +8,5 @@ To support multiple gpg keys added with --add-key, propellor should 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`. + `--set-signing-key`, or adding another command `--add-foreign-key`, + or perhaps determining if the key being added has a known secret key. diff --git a/src/Propellor/Gpg.hs b/src/Propellor/Gpg.hs index e478f610..572be190 100644 --- a/src/Propellor/Gpg.hs +++ b/src/Propellor/Gpg.hs @@ -8,6 +8,7 @@ import Data.Maybe import Data.List.Utils import Propellor.PrivData.Paths +import Propellor.Message import Utility.SafeCommand import Utility.Process import Utility.Monad @@ -19,6 +20,7 @@ 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 @@ -36,10 +38,15 @@ useKeyringOpts = ] addKey :: KeyId -> IO () -addKey keyid = exitBool =<< allM id - [ gpg, gitadd keyring, reencryptprivdata, gitconfig, gitcommit ] +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 - gpg = do + addkeyring = do createDirectoryIfMissing True privDataDir boolSystem "sh" [ Param "-c" @@ -59,11 +66,16 @@ addKey keyid = exitBool =<< allM id , File f ] - gitconfig = boolSystem "git" - [ Param "config" - , Param "user.signingkey" - , Param keyid - ] + 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 @@ -71,7 +83,7 @@ addKey keyid = exitBool =<< allM id , Param "propellor addkey" ] -{- Automatically sign the commit if there'a a keyring. -} +-- Automatically sign the commit if there'a a keyring. gitCommit :: [CommandParam] -> IO Bool gitCommit ps = do k <- doesFileExist keyring @@ -86,6 +98,7 @@ gpgDecrypt f = ifM (doesFileExist f) , return "" ) +-- Encrypt file to all keys in propellor's keyring. gpgEncrypt :: FilePath -> String -> IO () gpgEncrypt f s = do keyids <- listPubKeys -- cgit v1.2.3