Open gws opened 3 years ago
This is a working (but rough; code review left as exercise for reader) solution, mostly copied from the v1 version in the lib:
(ns some-ns
(:require
[clojure.core.async :as a]
[clojure.data.json :as json]
[clojure.string :as str]
[cognitect.aws.client.shared :as client-shared]
[cognitect.aws.credentials :as credentials]
[cognitect.aws.http :as http]
[cognitect.aws.retry :as retry]
[cognitect.aws.util :as u])
(:import
[java.net URI]))
(def token-timeout
"Declares the lifetime of the AWS token before it should be refreshed."
21600)
(defn- request-map
([address]
(request-map address nil))
([address more]
(let [uri (URI. address)]
(merge-with (fn merge-if-map
[x y]
(if (and (map? x) (map? y))
(merge x y)
y))
{:scheme (.getScheme uri)
:server-name (.getHost uri)
:server-port (cond
(pos? (.getPort uri)) (.getPort uri)
(= :https (.getScheme uri)) 443
:else 80)
:uri (.getPath uri)
:request-method :get
:headers {:accept "*/*"}}
more))))
(defn- http-request
[http-client request-map]
(let [response (a/<!! (retry/with-retry
#(http/submit http-client request-map)
(a/promise-chan)
retry/default-retriable?
retry/default-backoff))]
;; TODO: handle unhappy paths -JS
(when (= 200 (:status response))
(u/bbuf->str (:body response)))))
(defn- get-token
[http-client]
(http-request http-client
(request-map "http://169.254.169.254/latest/api/token"
{:headers {"X-aws-ec2-metadata-token-ttl-seconds" (str token-timeout)}
:request-method :put})))
(defn- get-credential-names
[http-client token]
(some-> (http-request http-client
(request-map "http://169.254.169.254/latest/meta-data/iam/security-credentials"
{:headers {"X-aws-ec2-metadata-token" token}}))
(str/split-lines)))
(defn- get-credentials-string
[http-client token credentials-name]
(http-request http-client
(request-map (str "http://169.254.169.254/latest/meta-data/iam/security-credentials/" credentials-name)
{:headers {"X-aws-ec2-metadata-token" token}})))
(defn- get-imds-v2-credentials
[http-client]
(when-let [token (get-token http-client)]
(first
(eduction
(map (partial get-credentials-string http-client token))
(filter string?)
(map #(json/read-str % :key-fn keyword))
(take 1)
(get-credential-names http-client token)))))
(defn imds-v2-credentials-provider
"Attempt to retrieve credentials from Amazon Metadata Service v2."
[http-client]
(credentials/cached-credentials-with-auto-refresh
(reify credentials/CredentialsProvider
(fetch
[_]
(when-let [creds (get-imds-v2-credentials http-client)]
(credentials/valid-credentials
{:aws/access-key-id (:AccessKeyId creds)
:aws/secret-access-key (:SecretAccessKey creds)
:aws/session-token (:Token creds)
:cognitect.aws.credentials/ttl (credentials/calculate-ttl creds)}
"ec2 instance"))))))
(defn default-credentials-provider
"Returns a chain-credentials-provider with (in order):
environment-credentials-provider
system-property-credentials-provider
profile-credentials-provider
container-credentials-provider
instance-profile-credentials-provider
imds-v2-credentials-provider
Alpha. Subject to change."
[]
(let [http-client (client-shared/http-client)]
(credentials/chain-credentials-provider
[(credentials/environment-credentials-provider)
(credentials/system-property-credentials-provider)
(credentials/profile-credentials-provider)
(credentials/container-credentials-provider http-client)
(credentials/instance-profile-credentials-provider http-client)
(imds-v2-credentials-provider http-client)])))
For example;
(def s3
(aws/client
{:api :s3
:credentials-provider (some-ns/default-credentials-provider)}))
Are there any plans to implement this? We were just bitten hard by this one and took us quite a bit to discover why the calls where failing :smile:
Hi all,
Kindly reference this AWS blog post (Nov '23) https://aws.amazon.com/blogs/aws/amazon-ec2-instance-metadata-service-imdsv2-by-default/
[Mid 2024] Newly released Amazon EC2 instance types will use IMDSv2 only by default...
It seems as if AWS is moving away from IMDSv1, making it harder and harder to remain on v1. For example: In mid-July 2024 the public ubuntu AMIs are now defaulting to IMSDv2.
The instance metadata service v2 (IMDSv2), released in November 2019, offers some defense in depth protections over the previous version. EC2 provides control over the version of the metadata service used, and some security-conscious environments are disabling IMDSv1.
All current AWS SDKs support interacting with the IMDSv2 with a fallback to IMDSv1, and this request is for aws-api to behave similarly.