Skip to content

Commit

Permalink
Merge #383
Browse files Browse the repository at this point in the history
383: Assume role from profile via instance metadata r=mattBrzezinski a=christopher-dG

Closes #287 

```ini
[default]
region = us-east-2

[profile role-to-assume]
region = us-east-2
role_arn = arn:aws:iam::account:role/role-to-assume
credential_source = Ec2InstanceMetadata
```

```julia
julia> using AWS

julia> global_aws_config(; profile="default")
AWSConfig(arn:aws:iam::account:instance-profile/role-from-instance-profile (ASIASWQI5NDNRIZLJ3WJ, pAk..., IQo..., 2021-06-18T21:11:05), "us-east-2", "json")

julia> global_aws_config(; profile="role-to-assume")
AWSConfig(arn:aws:sts::account:assumed-role/role-to-assume/AWS.jl-role-role-to-assume-20210618T152950Z (ASIASWQI5NDNRFEK2HJS, AYR..., IQo..., 2021-06-18T15:44:53), "us-east-2", "json")
```

Needs some tests of course.

Co-authored-by: Chris de Graaf <me@cdg.dev>
Co-authored-by: mattBrzezinski <matt.brzezinski@invenia.ca>
  • Loading branch information
3 people authored Jun 18, 2021
2 parents c555321 + 0524f22 commit f33bb32
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 15 deletions.
65 changes: 51 additions & 14 deletions src/AWSCredentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ function AWSCredentials(; profile=nothing, throw_cred_error=true)
() -> dot_aws_config(profile),
credentials_from_webtoken,
ecs_instance_credentials,
ec2_instance_credentials
() -> ec2_instance_credentials(profile),
]

# Loop through our search locations until we get credentials back
Expand Down Expand Up @@ -235,32 +235,69 @@ ec2_instance_region() = ec2_instance_metadata("/latest/meta-data/placement/regio


"""
ec2_instance_credentials() -> AWSCredentials
ec2_instance_credentials(profile::AbstractString) -> AWSCredentials
Parse the EC2 metadata to retrieve AWSCredentials.
"""
function ec2_instance_credentials()
info = ec2_instance_metadata("/latest/meta-data/iam/info")
function ec2_instance_credentials(profile::AbstractString)
path = dot_aws_config_file()
ini = Inifile()
if isfile(path)
ini = read(ini, path)
end

if info === nothing
return nothing
# Any profile except default must specify the credential_source as Ec2InstanceMetadata.
if profile != "default"
source = _get_ini_value(ini, profile, "credential_source")
source == "Ec2InstanceMetadata" || return nothing
end

info = ec2_instance_metadata("/latest/meta-data/iam/info")
info === nothing && return nothing
info = JSON.parse(info)

# Get credentials for the role associated to the instance via instance profile.
name = ec2_instance_metadata("/latest/meta-data/iam/security-credentials/")
creds = ec2_instance_metadata("/latest/meta-data/iam/security-credentials/$name")
new_creds = JSON.parse(creds)
parsed = JSON.parse(creds)
instance_profile_creds = AWSCredentials(
parsed["AccessKeyId"],
parsed["SecretAccessKey"],
parsed["Token"],
info["InstanceProfileArn"];
expiry=DateTime(rstrip(parsed["Expiration"], 'Z')),
renew=() -> ec2_instance_credentials(profile),
)

expiry = DateTime(rstrip(new_creds["Expiration"], 'Z'))
# Look for a role to assume and return instance profile credentials if there is none.
role_arn = _get_ini_value(ini, profile, "role_arn")
role_arn === nothing && return instance_profile_creds

# Assume the role.
role_session = _role_session_name(
"AWS.jl-role-",
basename(role_arn),
"-" * Dates.format(@mock(now(UTC)), dateformat"yyyymmdd\THHMMSS\Z"),
)
params = Dict{String, Any}("RoleArn" => role_arn, "RoleSessionName" => role_session)
duration = _get_ini_value(ini, profile, "duration_seconds")
if duration !== nothing
params["DurationSeconds"] = parse(Int, duration)
end
resp = AWSServices.sts(
"AssumeRole",
params;
aws_config=AWSConfig(creds=instance_profile_creds),
)
role_creds = resp["AssumeRoleResult"]["Credentials"]
role_user = resp["AssumeRoleResult"]["AssumedRoleUser"]
return AWSCredentials(
new_creds["AccessKeyId"],
new_creds["SecretAccessKey"],
new_creds["Token"],
info["InstanceProfileArn"];
expiry=expiry,
renew=ec2_instance_credentials
role_creds["AccessKeyId"],
role_creds["SecretAccessKey"],
role_creds["SessionToken"],
role_user["Arn"],
expiry=DateTime(rstrip(role_creds["Expiration"], 'Z')),
renew=() -> ec2_instance_credentials(profile),
)
end

Expand Down
2 changes: 1 addition & 1 deletion test/AWSCredentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ end

@testset "Instance - EC2" begin
apply(_http_request_patch) do
result = ec2_instance_credentials()
result = ec2_instance_credentials("default")
@test result.access_key_id == test_values["AccessKeyId"]
@test result.secret_key == test_values["SecretAccessKey"]
@test result.token == test_values["Token"]
Expand Down

0 comments on commit f33bb32

Please sign in to comment.