store S3 creds in a 600 mode file inside the local git repo

This commit is contained in:
Joey Hess 2012-09-26 12:06:44 -04:00
parent 926ffaf3f3
commit e4bf74a965
5 changed files with 63 additions and 28 deletions

View file

@ -20,6 +20,7 @@ module Locations (
gitAnnexUnusedLog, gitAnnexUnusedLog,
gitAnnexFsckState, gitAnnexFsckState,
gitAnnexTransferDir, gitAnnexTransferDir,
gitAnnexCredsDir,
gitAnnexJournalDir, gitAnnexJournalDir,
gitAnnexJournalLock, gitAnnexJournalLock,
gitAnnexIndex, gitAnnexIndex,
@ -135,7 +136,12 @@ gitAnnexUnusedLog prefix r = gitAnnexDir r </> (prefix ++ "unused")
gitAnnexFsckState :: Git.Repo -> FilePath gitAnnexFsckState :: Git.Repo -> FilePath
gitAnnexFsckState r = gitAnnexDir r </> "fsckstate" gitAnnexFsckState r = gitAnnexDir r </> "fsckstate"
{- .git/annex/transfer/ is used is used to record keys currently {- .git/annex/creds/ is used to store credentials to access some special
- remotes. -}
gitAnnexCredsDir :: Git.Repo -> FilePath
gitAnnexCredsDir r = addTrailingPathSeparator $ gitAnnexDir r </> "creds"
{- .git/annex/transfer/ is used to record keys currently
- being transferred, and other transfer bookkeeping info. -} - being transferred, and other transfer bookkeeping info. -}
gitAnnexTransferDir :: Git.Repo -> FilePath gitAnnexTransferDir :: Git.Repo -> FilePath
gitAnnexTransferDir r = addTrailingPathSeparator $ gitAnnexDir r </> "transfer" gitAnnexTransferDir r = addTrailingPathSeparator $ gitAnnexDir r </> "transfer"

View file

@ -88,6 +88,11 @@ remoteCipher c = go $ extractCipher c
Annex.changeState (\s -> s { Annex.ciphers = M.insert encipher cipher cache }) Annex.changeState (\s -> s { Annex.ciphers = M.insert encipher cipher cache })
return $ Just cipher return $ Just cipher
{- Checks if there is a trusted (non-shared) cipher. -}
isTrustedCipher :: RemoteConfig -> Bool
isTrustedCipher c =
isJust (M.lookup "cipherkeys" c) && isJust (M.lookup "cipher" c)
{- Gets encryption Cipher, and encrypted version of Key. -} {- Gets encryption Cipher, and encrypted version of Key. -}
cipherKey :: Maybe RemoteConfig -> Key -> Annex (Maybe (Cipher, Key)) cipherKey :: Maybe RemoteConfig -> Key -> Annex (Maybe (Cipher, Key))
cipherKey Nothing _ = return Nothing cipherKey Nothing _ = return Nothing

View file

@ -27,6 +27,8 @@ import Remote.Helper.Encryptable
import Crypto import Crypto
import Annex.Content import Annex.Content
import Utility.Base64 import Utility.Base64
import Annex.Perms
import Utility.FileMode
remote :: RemoteType remote :: RemoteType
remote = RemoteType { remote = RemoteType {
@ -85,12 +87,12 @@ s3Setup u c = handlehost $ M.lookup "host" c
use fullconfig = do use fullconfig = do
gitConfigSpecialRemote u fullconfig "s3" "true" gitConfigSpecialRemote u fullconfig "s3" "true"
s3SetCreds fullconfig s3SetCreds fullconfig u
defaulthost = do defaulthost = do
c' <- encryptionSetup c c' <- encryptionSetup c
let fullconfig = c' `M.union` defaults let fullconfig = c' `M.union` defaults
genBucket fullconfig genBucket fullconfig u
use fullconfig use fullconfig
archiveorg = do archiveorg = do
@ -206,7 +208,7 @@ s3Action r noconn action = do
when (isNothing $ config r) $ when (isNothing $ config r) $
error $ "Missing configuration for special remote " ++ name r error $ "Missing configuration for special remote " ++ name r
let bucket = M.lookup "bucket" $ fromJust $ config r let bucket = M.lookup "bucket" $ fromJust $ config r
conn <- s3Connection $ fromJust $ config r conn <- s3Connection (fromJust $ config r) (uuid r)
case (bucket, conn) of case (bucket, conn) of
(Just b, Just c) -> action (c, b) (Just b, Just c) -> action (c, b)
_ -> return noconn _ -> return noconn
@ -235,9 +237,9 @@ iaMunge = (>>= munge)
| isSpace c = [] | isSpace c = []
| otherwise = "&" ++ show (ord c) ++ ";" | otherwise = "&" ++ show (ord c) ++ ";"
genBucket :: RemoteConfig -> Annex () genBucket :: RemoteConfig -> UUID -> Annex ()
genBucket c = do genBucket c u = do
conn <- s3ConnectionRequired c conn <- s3ConnectionRequired c u
showAction "checking bucket" showAction "checking bucket"
loc <- liftIO $ getBucketLocation conn bucket loc <- liftIO $ getBucketLocation conn bucket
case loc of case loc of
@ -253,13 +255,13 @@ genBucket c = do
bucket = fromJust $ M.lookup "bucket" c bucket = fromJust $ M.lookup "bucket" c
datacenter = fromJust $ M.lookup "datacenter" c datacenter = fromJust $ M.lookup "datacenter" c
s3ConnectionRequired :: RemoteConfig -> Annex AWSConnection s3ConnectionRequired :: RemoteConfig -> UUID -> Annex AWSConnection
s3ConnectionRequired c = s3ConnectionRequired c u =
maybe (error "Cannot connect to S3") return =<< s3Connection c maybe (error "Cannot connect to S3") return =<< s3Connection c u
s3Connection :: RemoteConfig -> Annex (Maybe AWSConnection) s3Connection :: RemoteConfig -> UUID -> Annex (Maybe AWSConnection)
s3Connection c = do s3Connection c u = do
creds <- s3GetCreds c creds <- s3GetCreds c u
case creds of case creds of
Just (ak, sk) -> return $ Just $ AWSConnection host port ak sk Just (ak, sk) -> return $ Just $ AWSConnection host port ak sk
_ -> do _ -> do
@ -273,23 +275,32 @@ s3Connection c = do
_ -> error $ "bad S3 port value: " ++ s _ -> error $ "bad S3 port value: " ++ s
{- S3 creds come from the environment if set. {- S3 creds come from the environment if set.
- Otherwise, might be stored encrypted in the remote's config. -} - Otherwise, might be stored encrypted in the remote's config, or
s3GetCreds :: RemoteConfig -> Annex (Maybe (String, String)) - locally in gitAnnexCredsDir. -}
s3GetCreds c = maybe fromconfig (return . Just) =<< liftIO getenv s3GetCreds :: RemoteConfig -> UUID -> Annex (Maybe (String, String))
s3GetCreds c u = maybe fromconfig (return . Just) =<< liftIO getenv
where where
getenv = liftM2 (,) getenv = liftM2 (,)
<$> get s3AccessKey <$> get s3AccessKey
<*> get s3SecretKey <*> get s3SecretKey
where where
get = catchMaybeIO . getEnv get = catchMaybeIO . getEnv
setenv (ak, sk) = do cache (ak, sk) = do
setEnv s3AccessKey ak True setEnv s3AccessKey ak True
setEnv s3SecretKey sk True setEnv s3SecretKey sk True
return $ Just (ak, sk)
fromconfig = do fromconfig = do
mcipher <- remoteCipher c mcipher <- remoteCipher c
case (M.lookup "s3creds" c, mcipher) of case (M.lookup "s3creds" c, mcipher) of
(Just s3creds, Just cipher) -> (Just s3creds, Just cipher) ->
liftIO $ decrypt s3creds cipher liftIO $ decrypt s3creds cipher
_ -> fromcredsfile
fromcredsfile = do
d <- fromRepo gitAnnexCredsDir
let f = d </> fromUUID u
v <- liftIO $ catchMaybeIO $ readFile f
case lines <$> v of
Just (ak:sk:[]) -> liftIO $ cache (ak, sk)
_ -> return Nothing _ -> return Nothing
decrypt s3creds cipher = do decrypt s3creds cipher = do
creds <- lines <$> creds <- lines <$>
@ -297,25 +308,33 @@ s3GetCreds c = maybe fromconfig (return . Just) =<< liftIO getenv
(return $ L.pack $ fromB64 s3creds) (return $ L.pack $ fromB64 s3creds)
(return . L.unpack) (return . L.unpack)
case creds of case creds of
[ak, sk] -> do [ak, sk] -> cache (ak, sk)
setenv (ak, sk)
return $ Just (ak, sk)
_ -> do error "bad s3creds" _ -> do error "bad s3creds"
{- Stores S3 creds encrypted in the remote's config if possible. -} {- Stores S3 creds encrypted in the remote's config if possible to do so
s3SetCreds :: RemoteConfig -> Annex RemoteConfig - securely, and otherwise locally in gitAnnexCredsDir. -}
s3SetCreds c = do s3SetCreds :: RemoteConfig -> UUID -> Annex RemoteConfig
creds <- s3GetCreds c s3SetCreds c u = do
creds <- s3GetCreds c u
case creds of case creds of
Just (ak, sk) -> do Just (ak, sk) -> do
mcipher <- remoteCipher c mcipher <- remoteCipher c
case mcipher of case mcipher of
Just cipher -> do Just cipher | isTrustedCipher c -> do
s <- liftIO $ withEncryptedContent cipher s <- liftIO $ withEncryptedContent cipher
(return $ L.pack $ unlines [ak, sk]) (return $ L.pack $ unlines [ak, sk])
(return . L.unpack) (return . L.unpack)
return $ M.insert "s3creds" (toB64 s) c return $ M.insert "s3creds" (toB64 s) c
Nothing -> return c _ -> do
d <- fromRepo gitAnnexCredsDir
createAnnexDirectory d
let f = d </> fromUUID u
h <- liftIO $ openFile f WriteMode
liftIO $ modifyFileMode f $ removeModes
[groupReadMode, otherReadMode]
liftIO $ hPutStr h $ unlines [ak, sk]
liftIO $ hClose h
return c
_ -> return c _ -> return c
s3AccessKey :: String s3AccessKey :: String

3
debian/changelog vendored
View file

@ -12,6 +12,9 @@ git-annex (3.20120925) UNRELEASED; urgency=low
eg, monthly incremental fsck runs in cron jobs. eg, monthly incremental fsck runs in cron jobs.
* Fix fallback to ~/Desktop when xdg-user-dir is not available. * Fix fallback to ~/Desktop when xdg-user-dir is not available.
Closes: #688833 Closes: #688833
* S3: When using a shared cipher, S3 credentials are not stored encrypted
in the git repository, as that would allow anyone with access to
the repository access to the S3 account.
-- Joey Hess <joeyh@debian.org> Mon, 24 Sep 2012 19:58:07 -0400 -- Joey Hess <joeyh@debian.org> Mon, 24 Sep 2012 19:58:07 -0400

View file

@ -9,8 +9,10 @@ See [[tips/using_Amazon_S3]] and
The standard environment variables `AWS_ACCESS_KEY_ID` and The standard environment variables `AWS_ACCESS_KEY_ID` and
`AWS_SECRET_ACCESS_KEY` are used to supply login credentials `AWS_SECRET_ACCESS_KEY` are used to supply login credentials
for Amazon. When encryption is enabled, they are stored in encrypted form for Amazon. When encryption is enabled, they are stored in encrypted form
by `git annex initremote`, so you do not need to keep the environment by `git annex initremote`. Without encryption, they are stored in a
variables set after the initial initalization of the remote. file only you can read inside the local git repository. So you do not
need to keep the environment variables set after the initial
initalization of the remote.
A number of parameters can be passed to `git annex initremote` to configure A number of parameters can be passed to `git annex initremote` to configure
the S3 remote. the S3 remote.