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 #1

Closed
wants to merge 1 commit into from

Conversation

dw-kihara
Copy link
Owner

Like in the issue aws-beam#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.


-spec get_role_arn(aws_credentials_provider:options()) -> {error, any()} | {ok, role_arn()}.
get_role_arn(Options) ->
case {os:getenv("AWS_ROLE_ARN"), maps:get(role_arn, Options, undefined)} of
Copy link
Owner 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: aws-beam#70

@onno-vos-dev
Copy link

@dw-kihara Can you open the DRAFT PR towards aws-beam. That makes it easier for me to follow it and comment on it without losing track of this work 👍

Thank you for the contribution in advance. I think it'd be great to add this so feel free to add a (DRAFT) PR and we can take it from there 👍

@dw-kihara
Copy link
Owner Author

@onno-vos-dev Thank you! I will re-create the PR.

@dw-kihara
Copy link
Owner Author

Created: aws-beam#73

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.

2 participants