Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
(let [invoke (delay @(requiring-resolve 'cs.aws-api/invoke))]
(defn fetch-assume-role-creds
[sts-client {:keys [role-arn
external-id
role-session-name]}]
(let [role-session-name (or role-session-name "computesoftware")
resp (@invoke
sts-client {:op :AssumeRole
:request (cond-> {:RoleArn role-arn
:RoleSessionName role-session-name}
external-id
(assoc :ExternalId external-id))})]
(when (anom/anomaly? resp)
(log/info {:tag ::assume-role-anomaly
:role-arn role-arn
:external-id external-id
:anomaly resp}))
(if (anom/anomaly? resp)
resp
(when-let [creds (:Credentials resp)]
{:aws/access-key-id (:AccessKeyId creds)
:aws/secret-access-key (:SecretAccessKey creds)
:aws/session-token (:SessionToken creds)
::credentials/ttl (credentials/calculate-ttl creds)})))))
(defn get-source-profile-order
[config profile-name {:keys [max-iterations]
:or {max-iterations 10}}]
(loop [profile-name profile-name
sources (list)
iter 0]
(when (>= iter max-iterations)
(throw (ex-info (format "Cannot nest more than %s profiles." max-iterations)
{:max-iterations max-iterations})))
(let [profile (get config profile-name)
source-profile-name (get profile "source_profile")]
(if (nil? source-profile-name)
(cons profile sources)
(recur source-profile-name (cons profile sources) (inc iter))))))
(let [client (delay @(requiring-resolve 'cs.aws-api/client))]
(defn fetch-nested-profiles-creds-map
[profiles]
(reduce
(fn [creds-map [start-profile target-profile]]
(let [sts-client (@client
(cond-> {:api :sts}
(:region start-profile)
(assoc :region (:region start-profile))
creds-map
(assoc
:credentials-provider
(reify
credentials/CredentialsProvider
(fetch [_] creds-map)))))
next-creds (fetch-assume-role-creds sts-client
{:role-arn (get target-profile "role_arn")
:external-id (get target-profile "external_id")
:role-session-name (get target-profile "role_session_name")})]
next-creds))
nil (partition 2 1 profiles))))
(defn get-credentials-from-profile
[f profile-name]
(when (.exists f)
(try
(let [profile (get (config/parse f) profile-name)]
(credentials/valid-credentials
{:aws/access-key-id (get profile "aws_access_key_id")
:aws/secret-access-key (get profile "aws_secret_access_key")
:aws/session-token (get profile "aws_session_token")}
"aws profiles file"))
(catch Throwable _ nil
#_(log/error t "Error fetching credentials from aws profiles file")))))
(defn get-credentials-from-assume-role-profile
[f profile-name]
(when (.exists f)
(try
(let [config (config/parse f)]
(when (get-in config [profile-name "role_arn"])
(let [profiles (get-source-profile-order config profile-name {})
creds (fetch-nested-profiles-creds-map profiles)]
(credentials/valid-credentials
creds
"aws config file"))))
(catch Throwable _ nil))))
(defn profile-credentials-provider
"Return credentials in an AWS configuration profile.
Arguments:
profile-name string The name of the profile in the file. (default: default)
f File The profile configuration file. (default: ~/.aws/credentials)
https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html
Parsed properties:
aws_access_key required
aws_secret_access_key required
aws_session_token optional
Alpha. Subject to change."
([]
(profile-credentials-provider (or (u/getenv "AWS_PROFILE")
(u/getProperty "aws.profile")
"default")))
([profile-name]
(profile-credentials-provider profile-name
{:config-file (or (io/file (u/getenv "AWS_CONFIG_FILE"))
(io/file (u/getProperty "user.home") ".aws" "config"))
:creds-file (or (io/file (u/getenv "AWS_CREDENTIAL_PROFILES_FILE"))
(io/file (u/getProperty "user.home") ".aws" "credentials"))}))
([profile-name {:keys [config-file creds-file]}]
(credentials/cached-credentials-with-auto-refresh
(reify credentials/CredentialsProvider
(fetch [_]
(or
(get-credentials-from-profile creds-file profile-name)
(get-credentials-from-assume-role-profile config-file profile-name)))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment