Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[experimental] Added a provider with web identity token #73

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

dw-kihara
Copy link
Contributor

(Moved from my fork repository dw-kihara#1)

Like in the issue #55, I also need support for web identity token in my (company's) project.
Therefore, I am writing a provider that calls the AssumeRoleWithWebIdentity API to fetch credentials.

This module is not well-tested for merging, so I am making this pull request as a draft only for reference.

Usage (by rebar3 shell):

$ rebar3 shell
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling aws_credentials
Erlang/OTP 26 [erts-14.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit:ns]

Eshell V14.1 (press Ctrl+G to abort, type help(). for help)
1> application:set_env(aws_credentials, credential_providers, [aws_credentials_web_identity]).
ok
2> application:set_env(aws_credentials, provider_options, #{region => <<"ap-northeast-1">>, role_arn => <<"arn:aws:iam::XXXXXXXXXXXX">>, web_identity_token_file => <<"/path/to/token">>}).
ok
3> application:ensure_all_started(aws_credentials).
{ok,[jsx,eini,iso8601,aws_credentials]}
4> aws_credentials:get_credentials().
#{region => <<"ap-northeast-1">>,
  access_key_id => <<"XXXXXXXXXX">>,
  credential_provider => aws_credentials_web_identity,
  secret_access_key =>
      <<"XXXXXXXXXX">>,
  token =>
      <<"XXXXXXXXXX">>}

By default, this module uses the aws CLI command to call AssumeRoleWithWebIdentity because using aws-erlang introduces too many dependencies.
Instead, the provider user can change the module that calls AssumeRoleWithWebIdentity by setting the web_identity_token_module option.
Example module:

-module(aws_credentials_web_identity_aws).
-behaviour(aws_credentials_web_identity).

-export([assume_role_with_web_identity/5]).

-spec assume_role_with_web_identity(
    aws_credentials_web_identity:region(),
    aws_credentials_web_identity:role_arn(),
    aws_credentials_web_identity:role_session_name(),
    aws_credentials_web_identity:web_identity_token(), map()) ->
    {ok, aws_credentials:credentials(), aws_credentials_provider:expiration()} | {error, any()}.
assume_role_with_web_identity(Region, RoleArn, RoleSessionName, WebIdentityToken, Options) ->
    Client = aws_client:make_temporary_client(<<"">>, <<"">>, <<"">>, Region),
    Input = #{
        <<"RoleArn">> => RoleArn,
        <<"RoleSessionName">> => RoleSessionName,
        <<"WebIdentityToken">> => WebIdentityToken
    },
    RetryOptions = maps:get(retry_options, Options, {exponential_with_jitter, {10, 100, 2000}}),
    RequestOptions = [{retry_options, RetryOptions}],
    case aws_sts:assume_role_with_web_identity(Client, Input, RequestOptions) of
        {ok, Response, _HttpDetail} ->
            #{<<"AssumeRoleWithWebIdentityResponse">> := #{
                <<"AssumeRoleWithWebIdentityResult">> := #{
                    <<"Credentials">> := #{
                        <<"AccessKeyId">> := AccessKeyId,
                        <<"SecretAccessKey">> := SecretAccessKey,
                        <<"SessionToken">> := SessionToken,
                        <<"Expiration">> := Expiration
                        }
                    }
                }
            } = Response,
            Credentials = aws_credentials:make_map(aws_credentials_web_identity,
                                                   AccessKeyId, SecretAccessKey, SessionToken, Region),
            {ok, Credentials, Expiration};
        {error, Reason} ->
            {error, Reason};
        {error, ErrorResponse, _HttpDetail} ->
            {error, {error_in_request, ErrorResponse}}
    end.

Comment on lines +63 to +66
-spec get_region(aws_credentials_provider:options()) -> {error, any()} | {ok, region()}.
get_region(Options) ->
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I followed the Options usage in aws_credentials_file, but I'm not certain if this is correct.
See: #70

@dw-kihara
Copy link
Contributor Author

rebased to resolve conflict with the aws_credentials_provider:provider() type which is caused by #74

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant