Skip to content

Commit

Permalink
/vsis3/ / AWS: implement support for AWS Single-Sign On (AWS IAM Iden…
Browse files Browse the repository at this point in the history
…tity Center)

Fixes #11203
  • Loading branch information
rouault committed Nov 4, 2024
1 parent f5eedd2 commit 4d3722f
Show file tree
Hide file tree
Showing 6 changed files with 486 additions and 39 deletions.
115 changes: 115 additions & 0 deletions autotest/gcore/vsis3.py
Original file line number Diff line number Diff line change
Expand Up @@ -6093,6 +6093,121 @@ def test_vsis3_read_credentials_sts_assume_role_with_web_identity_from_config_fi
assert data == "foo"


###############################################################################
# Read credentials from cached SSO file


def test_vsis3_read_credentials_sso(tmp_vsimem, aws_test_config, webserver_port):

if webserver_port != 8080:
pytest.skip("only works for webserver on port 8080")

options = {
"AWS_SECRET_ACCESS_KEY": "",
"AWS_ACCESS_KEY_ID": "",
"AWS_PROFILE": "my_profile",
"CPL_AWS_SSO_ENDPOINT": "localhost:%d" % webserver_port,
"CPL_AWS_ROOT_DIR": str(tmp_vsimem),
}

gdal.VSICurlClearCache()

gdal.FileFromMemBuffer(
tmp_vsimem / "config",
"""
[sso-session my-sso]
sso_start_url = https://example.com
sso_region = eu-central-1
sso_registration_scopes = sso:account:access
[profile my_profile]
sso_session = my-sso
sso_account_id = my_sso_account_id
sso_role_name = my_sso_role_name
region = eu-east-1
""",
)

gdal.FileFromMemBuffer(
tmp_vsimem / "sso" / "cache" / "327c3fda87ce286848a574982ddd0b7c7487f816.json",
'{"startUrl": "https://example.com", "region": "us-east-1", "accessToken": "sso-accessToken", "expiresAt": "9999-01-01T00:00:00Z"}',
)

gdal.VSICurlClearCache()

handler = webserver.SequentialHandler()

handler.add(
"GET",
"/federation/credentials?role_name=my_sso_role_name&account_id=my_sso_account_id",
200,
{},
"""{
"roleCredentials": {
"accessKeyId": "accessKeyId",
"secretAccessKey": "secretAccessKey",
"sessionToken": "sessionToken",
"expiration": 9999999999000
}
}""",
expected_headers={
"x-amz-sso_bearer_token": "sso-accessToken",
},
)

handler.add(
"GET",
"/s3_fake_bucket/resource",
200,
{},
"""foo""",
expected_headers={
"x-amz-date": "20150101T000000Z",
"x-amz-content-sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"X-Amz-Security-Token": "sessionToken",
"Authorization": "AWS4-HMAC-SHA256 Credential=accessKeyId/20150101/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token,Signature=bfa9fb8c88286e3ef6537303784efe45721ede5e5bf51091565a66cf1ad8084a",
},
)

with webserver.install_http_handler(handler):
with gdaltest.config_options(options, thread_local=False):
f = open_for_read("/vsis3/s3_fake_bucket/resource")
assert f is not None
try:
data = gdal.VSIFReadL(1, 4, f).decode("ascii")
finally:
gdal.VSIFCloseL(f)

assert data == "foo"

handler = webserver.SequentialHandler()

handler.add(
"GET",
"/s3_fake_bucket/resource2",
200,
{},
"""bar""",
expected_headers={
"x-amz-date": "20150101T000000Z",
"x-amz-content-sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"X-Amz-Security-Token": "sessionToken",
"Authorization": "AWS4-HMAC-SHA256 Credential=accessKeyId/20150101/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token,Signature=b081c4f3195807de3fc934626f7ef7f3fd8e1143226bcbf2afce478c4bb7d4ff",
},
)

with webserver.install_http_handler(handler):
with gdaltest.config_options(options, thread_local=False):
f = open_for_read("/vsis3/s3_fake_bucket/resource2")
assert f is not None
try:
data = gdal.VSIFReadL(1, 4, f).decode("ascii")
finally:
gdal.VSIFCloseL(f)

assert data == "bar"


###############################################################################


Expand Down
3 changes: 2 additions & 1 deletion doc/source/user/virtual_file_systems.rst
Original file line number Diff line number Diff line change
Expand Up @@ -629,9 +629,10 @@ Since GDAL 3.1, the :cpp:func:`VSIRmdirRecursive` operation is supported (using

The :config:`CPL_VSIS3_CREATE_DIR_OBJECT` configuration option can be set to NO to prevent the :cpp:func:`VSIMkdir` operation from creating an empty object with the name of the directory terminated with a slash directory. By default GDAL creates such object, so that empty directories can be modeled, but this may cause compatibility problems with applications that do not expect such empty objects.


Starting with GDAL 3.5, profiles that use IAM role assumption (see https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html) are handled. The ``role_arn`` and ``source_profile`` keywords are required in such profiles. The optional ``external_id``, ``mfa_serial`` and ``role_session_name`` can be specified. ``credential_source`` is not supported currently.

Support for AWS Single-Sign On (AWS IAM Identity Center) parameters in ``~/.aws/config`` and cached SSO files in ``~/.aws/sso/cache`` is implemented since GDAL 3.10.1.

.. _vsis3_imds:

/vsis3/ and AWS Instance Metadata Service (IMDS)
Expand Down
Loading

0 comments on commit 4d3722f

Please sign in to comment.