Skip to content

Conversation

BeichenZhang-BCZ
Copy link

In collaboration with Sunfinite - thanks for kicking off first commit

Proposed Changes

Please describe the big picture of your changes here to communicate to the RabbitMQ team why we should accept this pull request.
If it fixes a bug or resolves a feature request, be sure to link to that issue.

When rabbitmq user configures or operates rabbitmq, user may want to configure rabbitmq to access information such as private CA certs/credentials etc, in AWS service rather than passing those information as local file or plain-text configuration to improve security and usability. For example, if user intends to configure LDAP for authentication and authorization, user as of today needs to define a local certs file and inform rabbitmq with config or environment variable .

With this AWS Resource Fetcher feature, user can pass in Amazon Resource Name(ARN) of the certs through new configuration schema eg: aws.arns.auth_ldap.ssl_options.cacertfile. The fetcher will fetch the relevant cert files from AWS S3 from user's account and assign it to the appropriate LDAP plugin application environment.

For corner case handling:

  1. Change is backward compatible if user doesn't configure any new ARN based attributes.
  2. If the user configurates both arn attribute and normal attribute for the same content, the value fetched according to arn attribute will prevail.
  3. If the fetcher failed to fetch from user resource, an unique error message will be thrown and rabbitmq start-up will fail.

This PR is working in progress to solicit early feedbacks. We are working on to add more functionalities such as allowing customer to configure Secret Manager arn for rabbitmq to retrieve credentials.

Types of Changes

What types of changes does your code introduce to this project?
Put an x in the boxes that apply

  • Bug fix (non-breaking change which fixes issue #NNNN)
  • [ x ] New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause an observable behavior change in existing systems)
  • Documentation improvements (corrections, new content, etc)
  • Cosmetic change (whitespace, formatting, etc)
  • Build system and/or CI

Checklist

Put an x in the boxes that apply.
You can also fill these out after creating the PR.
This is simply a reminder of what we are going to look for before merging your code.

  • [ x ] Mandatory: I (or my employer/client) have have signed the CA (see https://github.com/rabbitmq/cla)
  • [ x ] I have read the CONTRIBUTING.md document
  • I have added tests that prove my fix is effective or that my feature works
  • All tests pass locally with my changes
  • If relevant, I have added necessary documentation to https://github.com/rabbitmq/rabbitmq-website
  • If relevant, I have added this change to the first version(s) in release-notes that I expect to introduce it

Further Comments

If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution
you did and what alternatives you considered, etc.

@lukebakken lukebakken self-requested a review September 19, 2025 18:57
@lukebakken lukebakken self-assigned this Sep 19, 2025
Copy link
Collaborator

@lukebakken lukebakken left a comment

Choose a reason for hiding this comment

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

Let's chat about cacerts.

lists:foreach(fun({_Key, Arn, Handler}) ->
case resolve_arn(Arn) of
{ok, Content} ->
FilePath = write_to_file(Arn, Content),
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is no need to write these files to the filesystem if we use the cacerts configuration option. Please see this discussion for more information:

#14426


%% Export all for unit tests
-ifdef(TEST).
-compile(export_all).
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be better to be specific about which functions are exported for tests.


-spec resolve_arn(string()) -> {ok, binary()} | {error, term()}.
resolve_arn(Arn) ->
?LOG_INFO("Attempting to resolve ARN: ~p", [Arn]),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
?LOG_INFO("Attempting to resolve ARN: ~p", [Arn]),
?LOG_DEBUG("aws arn: resolving: ~p", [Arn]),

end,
?LOG_INFO("Fetched ARN ~p and stored to ~p", [Arn, FilePath]);
{error, Reason} ->
?LOG_ERROR("Failed to resolve ARN ~p: ~p", [Arn, Reason])
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
?LOG_ERROR("Failed to resolve ARN ~p: ~p", [Arn, Reason])
?LOG_ERROR("aws arn: failed to resolve ~p: ~p", [Arn, Reason])

ldap_ssl_options_cacertfile ->
update_env(rabbitmq_auth_backend_ldap, ssl_options, cacertfile, FilePath)
end,
?LOG_INFO("Fetched ARN ~p and stored to ~p", [Arn, FilePath]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
?LOG_INFO("Fetched ARN ~p and stored to ~p", [Arn, FilePath]);
?LOG_INFO("aws arn: fetched ~p and stored to ~p", [Arn, FilePath]);

{ok, #{service := "s3"}} ->
fetch_s3_object(Arn);
{ok, #{service := Service}} ->
?LOG_ERROR("Unsupported service: ~p", [Service]),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
?LOG_ERROR("Unsupported service: ~p", [Service]),
?LOG_ERROR("aws arn: unsupported service: ~p", [Service]),

?LOG_ERROR("Unsupported service: ~p", [Service]),
{error, {unsupported_service, Service}};
{error, _} = Error ->
?LOG_ERROR("Failed to parse ARN ~p: ~p", [Arn, Error]),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
?LOG_ERROR("Failed to parse ARN ~p: ~p", [Arn, Error]),
?LOG_ERROR("aws arn: failed to parse ~p: ~p", [Arn, Error]),

end.

-spec parse_arn(string()) -> {ok, map()} | {error, term()}.
parse_arn(Arn) ->
Copy link
Collaborator

Choose a reason for hiding this comment

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

If Arn can be a string(), then it shouldn't be necessary to convert it to a binary and then use binary:split. I recommend string:tokens.

case binary:split(ArnBin, <<":">>, [global]) of
[<<"arn">>, Partition, Service, Region, Account, Resource] ->
{ok, #{
partition => binary_to_list(Partition),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are we doing conversions to lists here?

Copy link
Author

Choose a reason for hiding this comment

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

+1 I also noted the conversion here. The input from {mapping, "aws.arns.auth_ldap.ssl_options.cacertfile", "rabbit.aws_arns", [{datatype, string}]}. is a binary.Can we just use binary:split ? @sunfinite

Copy link
Author

Choose a reason for hiding this comment

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

If the reason of using list is because you need to use string:tokens against the output, considering using string:lexemes which takes in either list or binary

@lukebakken
Copy link
Collaborator

An alternative to using aws arn: to differentiate log messages would be to have an AWS-plugin specific logging domain - https://www.erlang.org/doc/apps/kernel/logger.html#t:metadata/0 cc @SimonUnge @the-mikedavis

@BeichenZhang-BCZ BeichenZhang-BCZ changed the title Add support to fetch cacertfiles from Amazon S3 [DO NOT MERGE, WIP]Add support to fetch cacertfiles from Amazon S3 Sep 19, 2025
@lukebakken lukebakken marked this pull request as draft September 23, 2025 15:49
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.

4 participants