Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

S3 - Using Profile with role_arn from config over credential file #190

Merged
merged 4 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ To use configurations other than the `default` profile set the `$AWS_PROFILE`
environment variable to your desired profile.

Since version `0.21.0.58` Rome also supports privilege escalation via [Amazon STS](https://docs.aws.amazon.com/STS/latest/APIReference/Welcome.html)
by specifying `role_arn` and `source_profile` in `~/.aws/credentials`
by specifying `role_arn` and `source_profile` in `~/.aws/config`

### Selecting the AWS Region

Expand Down
26 changes: 14 additions & 12 deletions src/Lib.hs
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,17 @@ s3EndpointOverride (URL (Absolute h) _ _) =
s3EndpointOverride _ = S3.s3

-- | Tries to get authentication details and region to perform
-- | requests to AWS.
-- | requests to AWS.
-- | The `AWS_PROFILE` is read from the environment
-- | or falls back to `default`.
-- | or falls back to `default`.
-- | The `AWS_REGION` is first read from the environment, if not found
-- | it is read from `~/.aws/config` based on the profile discovered in the previous step.
-- | The `AWS_ACCESS_KEY_ID` & `AWS_SECRET_ACCESS_KEY` are first
-- | read from the environment. If not found, then the `~/.aws/crendetilas`
-- | read from the environment. If not found, then the `~/.aws/credentials`
-- | file is read. If `source_profile` key is present the reading of the
-- | authentication details happens from this profile rather then the `AWS_PROFILE`.
-- | Finally, if `role_arn` is specified, the crendials gathered up to now are used
-- | to obtain new credentials with STS esclated to `role_arn`.
-- | Finally, if `role_arn` is specified, the credentials gathered up to now are used
-- | to obtain new credentials with STS escalated to `role_arn`.
getAWSEnv :: (MonadIO m, MonadCatch m) => ExceptT String m AWS.Env
getAWSEnv = do
region <- discoverRegion
Expand All @@ -94,13 +94,15 @@ getAWSEnv = do
(lookupEnv (T.unpack "AWS_PROFILE"))
credentials <-
runExceptT $ (AWS.credentialsFromFile =<< getAWSCredentialsFilePath) `catch` \(e :: IOError) -> ExceptT . return . Left . show $ e
config <-
runExceptT $ (AWS.configFromFile =<< getAWSConfigFilePath) `catch` \(e :: IOError) -> ExceptT . return . Left . show $ e
(auth, _) <-
AWS.catching AWS._MissingEnvError AWS.fromEnv $ \envError -> either
throwError
(\cred -> do
let finalProfile = fromMaybe
profile
(eitherToMaybe $ AWS.sourceProfileOf profile =<< credentials)
(eitherToMaybe $ AWS.sourceProfileOf profile =<< config)
let
authAndRegion =
(,)
Expand All @@ -109,7 +111,7 @@ getAWSEnv = do
T.unpack envError
++ ". "
++ e
++ " in file ~/.aws/credentilas"
++ " in file ~/.aws/credentials"
)
(AWS.authFromCredentilas finalProfile =<< credentials)
<*> pure (pure region)
Expand All @@ -118,7 +120,7 @@ getAWSEnv = do
credentials
manager <- liftIO (Conduit.newManager Conduit.tlsManagerSettings)
ref <- liftIO (newIORef Nothing)
let roleARN = eitherToMaybe $ AWS.roleARNOf profile =<< credentials
let roleARN = eitherToMaybe $ AWS.roleARNOf profile =<< config
let curerntEnv = AWS.Env region
(\_ _ -> pure ())
(AWS.retryConnectionFailure 3)
Expand Down Expand Up @@ -195,7 +197,7 @@ runUtilsCommand command absoluteRomefilePath _ _ =
lift $ encodeFile absoluteRomefilePath romeFileEntries
_ -> throwError "Error: Programming Error. Only Utils command supported."

-- | Runs a command containing a `UDCPayload`
-- | Runs a command containing a `UDCPayload`
runUDCCommand :: RomeCommand -> FilePath -> Bool -> RomeVersion -> RomeMonad ()
runUDCCommand command absoluteRomefilePath verbose romeVersion = do
cartfileEntries <- getCartfileEntries
Expand Down Expand Up @@ -618,7 +620,7 @@ downloadArtifacts mS3BucketName mlCacheDir mEnginePath reverseRepositoryMap fram
)
readerEnv
-- Use engine
(Nothing, lCacheDir, Just ePath) -> do
(Nothing, lCacheDir, Just ePath) -> do
let engineEnv = (cachePrefix, skipLocalCacheFlag, concurrentlyFlag, verbose)
let action1 = runReaderT
(downloadFrameworksAndArtifactsWithEngine ePath
Expand Down Expand Up @@ -713,7 +715,7 @@ uploadArtifacts mS3BucketName mlCacheDir mEnginePath reverseRepositoryMap framew
>> runReaderT
(saveVersionFilesToLocalCache lCacheDir gitRepoNamesAndVersions)
readerEnv
-- Engine, maybe Cache
-- Engine, maybe Cache
(Nothing, lCacheDir, Just enginePath) -> do
let engineEnv =
( cachePrefix
Expand Down Expand Up @@ -1538,7 +1540,7 @@ downloadFrameworkAndArtifactsWithEngine enginePath (Just lCacheDir) reverseRomeM
readerEnv
let sayFunc :: MonadIO m => String -> m ()
sayFunc = if verbose then sayLnWithTime else sayLn

case eitherFrameworkSuccess of
Right _ -> return ()
Left e -> liftIO $ do
Expand Down
46 changes: 37 additions & 9 deletions src/Network/AWS/Utils.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module Network.AWS.Utils
( ConfigFile
, credentialsFromFile
, configFromFile
, authFromCredentilas
, parseConfigFile
, regionOf
Expand All @@ -22,7 +23,7 @@ import Control.Monad ((<=<))
import Data.Either.Utils (maybeToEither)
import Data.Either.Extra (mapLeft)
import Data.Ini (Ini, lookupValue, parseIni)
import qualified Data.Text as T (Text, null, unpack)
import qualified Data.Text as T (Text, null, pack, unpack)
import qualified Data.Text.Encoding as T (encodeUtf8)
import qualified Data.Text.IO as T (readFile)
import qualified Network.AWS as AWS
Expand Down Expand Up @@ -54,6 +55,16 @@ credentialsFromFile filePath = do
withExceptT (("Could not parse " <> filePath <> ": ") <>) (action file)
where action a = ExceptT . return $ parseCredentialsFile a

-- | Reads `ConfigFile` from a file at a given path
configFromFile
:: MonadIO m
=> FilePath -- ^ The path to the file containing the config. Usually `~/.aws/config`
-> ExceptT String m ConfigFile
configFromFile filePath = do
file <- liftIO (T.readFile filePath)
withExceptT (("Could not parse " <> filePath <> ": ") <>) (action file)
where action a = ExceptT . return $ parseConfigFile a

authFromCredentilas :: T.Text -> CredentialsFile -> Either String AWS.Auth
authFromCredentilas profile credentials = AWS.Auth <$> authEnv
where
Expand Down Expand Up @@ -90,16 +101,33 @@ getPropertyFromCredentials
getPropertyFromCredentials profile property =
lookupValue profile property . asIni

sourceProfileOf :: T.Text -> CredentialsFile -> Either String T.Text
sourceProfileOf profile credFile =
getPropertyFromCredentials profile "source_profile" credFile
`withError` const (missingKeyError key profile)
where key = "source_profile"
getPropertyFromConfig
:: T.Text -> T.Text -> ConfigFile -> Either String T.Text
getPropertyFromConfig profile property =
lookupValue profile property . asIni

roleARNOf :: T.Text -> CredentialsFile -> Either String T.Text
roleARNOf profile credFile = getPropertyFromCredentials profile key credFile
sourceProfileOf :: T.Text -> ConfigFile -> Either String T.Text
sourceProfileOf profile configFile =
getPropertyFromConfig finalProfile key configFile
`withError` const (missingKeyError key profile)
where
key = "source_profile"
finalProfile =
if profile == "default" then
profile
else
T.pack "profile " <> profile

roleARNOf :: T.Text -> ConfigFile -> Either String T.Text
roleARNOf profile configFile = getPropertyFromConfig finalProfile key configFile
`withError` const (missingKeyError key profile)
where key = "role_arn"
where
key = "role_arn"
finalProfile =
if profile == "default" then
profile
else
T.pack "profile " <> profile

accessKeyIdOf :: T.Text -> CredentialsFile -> Either String T.Text
accessKeyIdOf profile credFile =
Expand Down