Skip to content

Commit

Permalink
Merge pull request #1048 from rjenkins2/patch-1
Browse files Browse the repository at this point in the history
sso_session support in .aws/config
  • Loading branch information
bernardd authored Jun 4, 2024
2 parents 1eb6bac + cf04003 commit 8f08678
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 8 deletions.
36 changes: 28 additions & 8 deletions lib/ex_aws/credentials_ini/file.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ if Code.ensure_loaded?(ConfigParser) do
@valid_config_keys ~w(
aws_access_key_id aws_secret_access_key aws_session_token region
role_arn source_profile credential_source external_id mfa_serial role_session_name credential_process
sso_start_url sso_region sso_account_id sso_role_name
sso_start_url sso_region sso_account_id sso_role_name sso_session
)

@special_merge_keys ~w(sso_session)

def security_credentials(profile_name) do
config_credentials = profile_from_config(profile_name)
shared_credentials = profile_from_shared_credentials(profile_name)
Expand All @@ -19,9 +21,10 @@ if Code.ensure_loaded?(ConfigParser) do
sso_account_id: sso_account_id,
sso_role_name: sso_role_name
} ->
sso_cache_key = Map.get(config_credentials, :sso_session, sso_start_url)
config = ExAws.Config.http_config(:sso)

case get_sso_role_credentials(sso_start_url, sso_account_id, sso_role_name, config) do
case get_sso_role_credentials(sso_cache_key, sso_account_id, sso_role_name, config) do
{:ok, sso_creds} -> {:ok, Map.merge(sso_creds, shared_credentials)}
{:error, _} = err -> err
end
Expand All @@ -39,9 +42,9 @@ if Code.ensure_loaded?(ConfigParser) do
end
end

defp get_sso_role_credentials(sso_start_url, sso_account_id, sso_role_name, config) do
defp get_sso_role_credentials(sso_cache_key, sso_account_id, sso_role_name, config) do
with {_, {:ok, sso_cache_content}} <-
{:read, File.read(get_sso_cache_file(sso_start_url))},
{:read, File.read(get_sso_cache_file(sso_cache_key))},
{_,
{:ok, %{"expiresAt" => expires_at, "accessToken" => access_token, "region" => region}}} <-
{:decode, config[:json_codec].decode(sso_cache_content)},
Expand All @@ -68,8 +71,8 @@ if Code.ensure_loaded?(ConfigParser) do
end
end

defp get_sso_cache_file(sso_start_url) do
hash = :crypto.hash(:sha, sso_start_url) |> Base.encode16() |> String.downcase()
defp get_sso_cache_file(sso_cache_key) do
hash = :crypto.hash(:sha, sso_cache_key) |> Base.encode16() |> String.downcase()

System.user_home()
|> Path.join(".aws/sso/cache/#{hash}.json")
Expand Down Expand Up @@ -227,8 +230,9 @@ if Code.ensure_loaded?(ConfigParser) do
contents
|> ConfigParser.parse_string()
|> case do
{:ok, %{^profile_name => config}} ->
strip_key_prefix(config)
{:ok, %{^profile_name => config} = full} ->
merge_special_keys(full, config)
|> strip_key_prefix()

{:ok, %{}} ->
%{}
Expand All @@ -240,6 +244,22 @@ if Code.ensure_loaded?(ConfigParser) do

def parse_ini_file(_, _), do: %{}

def merge_special_keys(full_config, credentials) do
credentials
|> Map.take(@special_merge_keys)
|> Enum.reduce(credentials, fn {key, val}, acc ->
merge_section = "#{String.replace(key, "_", "-")} #{val}"

case full_config do
%{^merge_section => config} ->
Map.merge(config, acc)

_ ->
acc
end
end)
end

def strip_key_prefix(credentials) do
credentials
|> Map.take(@valid_config_keys)
Expand Down
23 changes: 23 additions & 0 deletions test/ex_aws/credentials_ini/file_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,29 @@ defmodule ExAws.CredentialsIni.File.FileTest do
assert config.sso_role_name == "SomeRole"
end

test "config file is parsed with sso config that uses sso_session" do
example_config = """
[sso-session somecompany]
sso_start_url = https://start.us-gov-home.awsapps.com/directory/somecompany
sso_region = us-gov-west-1
[default]
sso_session = somecompany
sso_account_id = 123456789101
sso_role_name = SomeRole
region = us-gov-west-1
output = json
"""

config = ExAws.CredentialsIni.File.parse_ini_file({:ok, example_config}, "default")

assert config.sso_session == "somecompany"
assert config.sso_start_url == "https://start.us-gov-home.awsapps.com/directory/somecompany"
assert config.sso_region == "us-gov-west-1"
assert config.sso_account_id == "123456789101"
assert config.sso_role_name == "SomeRole"
end

test "{:system} in profile name gets dynamic profile name" do
System.put_env("AWS_PROFILE", "custom-profile")

Expand Down

0 comments on commit 8f08678

Please sign in to comment.