Skip to content

Commit

Permalink
Support IMDSv2 credential fetch with AWS IAM provider
Browse files Browse the repository at this point in the history
  • Loading branch information
setu4993 committed Aug 20, 2024
1 parent c9b4c49 commit d971153
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 11 deletions.
27 changes: 18 additions & 9 deletions minio/credentials/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,10 +402,9 @@ def __init__(
self._full_uri = os.environ.get("AWS_CONTAINER_CREDENTIALS_FULL_URI")
self._credentials: Credentials | None = None

def fetch(self, url: str) -> Credentials:
"""Fetch credentials from EC2/ECS. """

res = _urlopen(self._http_client, "GET", url)
def fetch(self, url: str, headers: dict) -> Credentials:
"""Fetch credentials from EC2/ECS."""
res = _urlopen(self._http_client, "GET", url, headers=headers)
data = json.loads(res.data)
if data.get("Code", "Success") != "Success":
raise ValueError(
Expand Down Expand Up @@ -457,17 +456,27 @@ def retrieve(self) -> Credentials:
"http://169.254.169.254" +
"/latest/meta-data/iam/security-credentials/"
)

res = _urlopen(self._http_client, "GET", url)
# Step 1 of the IMDSv2 protocol: get a token from the metadata
# service with a 6-hour TTL.
response = _urlopen(
self._http_client, "PUT",
"http://169.254.169.254/latest/api/token",
headers={"X-aws-ec2-metadata-token-ttl-seconds": "21600"}
)
# Step 2: get the role name from the metadata service, with the
# token as a header.
token_header: dict = {
"X-aws-ec2-metadata-token":
response.data.decode("utf-8").strip()
}
res = _urlopen(self._http_client, "GET", url, headers=token_header)
role_names = res.data.decode("utf-8").split("\n")
if not role_names:
raise ValueError(f"no IAM roles attached to EC2 service {url}")
url += "/" + role_names[0].strip("\r")

if not url:
raise ValueError("url is empty; this should not happen")

self._credentials = self.fetch(url)
self._credentials = self.fetch(url, headers=token_header)
return self._credentials


Expand Down
11 changes: 9 additions & 2 deletions tests/unit/credentials_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,16 @@ def test_credentials_get(self):
self.assertEqual(creds.session_token, None)


class CredListResponse(object):
class TokenResponse(object):
status = 200
data = b"test-s3-full-access-for-minio-ec2"


class CredListResponse(object):
status = 200
data = b"test-s3-token-for-minio"


class CredsResponse(object):
status = 200
data = json.dumps({
Expand All @@ -66,7 +71,9 @@ class CredsResponse(object):
class IamAwsProviderTest(TestCase):
@mock.patch("urllib3.PoolManager.urlopen")
def test_iam(self, mock_connection):
mock_connection.side_effect = [CredListResponse(), CredsResponse()]
mock_connection.side_effect = [
TokenResponse(), CredListResponse(), CredsResponse()
]
provider = IamAwsProvider()
creds = provider.retrieve()
self.assertEqual(creds.access_key, "accessKey")
Expand Down

0 comments on commit d971153

Please sign in to comment.