-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
feat(mqttbridge): support file-sourced secrets as passwords #11809
feat(mqttbridge): support file-sourced secrets as passwords #11809
Conversation
8596163
to
ce0f64b
Compare
These secrets follow the same `emqx_secret` convention of 0-arity functions. Also provide a simple HOCON schema module for use in application schemas.
ce0f64b
to
52f4519
Compare
apps/emqx/src/emqx_schema_secret.erl
Outdated
{ok, Secret} -> | ||
string:trim(Secret, trailing, [$\n]); | ||
{error, Reason} -> | ||
error({inaccessible_secret_file, Reason}, [Filename]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe no need for stacktrace here
thorw(#{msg => failed_to_read_secret_file,
path => Filename,
reason => emqx_utils:explain_posix(Reason)})
apps/emqx/src/emqx_schema_secret.erl
Outdated
-spec wrap(source()) -> emqx_secret:t(t()). | ||
wrap(Source) -> | ||
try | ||
_Secret = load(Source), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can probably leave the exception to runtime.
i.e. allow the file to be missing when emqx boots up or when new config is added.
integrations usually has a retry loop, so sysadmin can crate the file after seeing error messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. On the other hand, should this be configurable? I.e. are there potential situations when we want to crash during configuration loading?
They are intended to be used mostly in the context of resources, which have their own feedback mechanism: statuses, retries, etc. Also turn the error into a throw exception, so that it can be interpreted as a regular error condition, for example by the resource manager.
|
||
%% @doc Inspect the term wrapped in a secret closure. | ||
-spec term(t(_)) -> _Term. | ||
term(Wrap) when is_function(Wrap, 0) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit unclear why we need quite a tricky way to extract an "intermediate value for unwrap"...
Maybe I am missing something, but could we be more explicit:
wrap(Fun, Arg) ->
fun(arg) -> Arg;
(value) -> Fun(Arg)
end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This somewhat hacky approach is motivated by the fact that we want to keep emqx_secret
following the convention (followed in turn by quite a few libraries) that says that wrapped secrets are 0-arity functions.
apps/emqx/src/emqx_secret.erl
Outdated
-spec wrap(atom(), _Term) -> t(_). | ||
wrap(Function, Term) -> | ||
fun() -> | ||
apply(?LOADER, Function, [Term]) | ||
end. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe:
-spec wrap(atom(), _Term) -> t(_). | |
wrap(Function, Term) -> | |
fun() -> | |
apply(?LOADER, Function, [Term]) | |
end. | |
-spec wrap(atom(), _Term) -> t(_). | |
wrap_dynamic(Term) -> | |
fun() -> | |
apply(?LOADER, load, [Term]) | |
end. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean if Term
is already a contract between the caller and emqx_secret_loader:Function
, maybe just keep it to one place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in d278486.
To make code employing `emqx_secret` easier to follow.
28c00b5
to
d278486
Compare
May be test it in higher level tests as well? |
Basically no objections, but this PR currently affects only handling of secrets in the MQTT bridge app, so it's kinda unclear how to test this feature there. Should be more apparent how to do that in some of the followup PRs? |
}). | ||
|
||
mk_client_opt_password(Options = #{password := Secret}) -> | ||
%% TODO: Teach `emqtt` to accept 0-arity closures as passwords. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also needed I think.
emqx/emqtt#223
Part of EMQX-10808.
How it works
Assuming we have the password for it stored in
/var/lib/secrets/mqtt1/password
, to source the password from this file, one need to either set an environment variable:Or a HOCON config entry:
In general, any string starting with file:// prefix is always considered a file-based secret, where the rest of the string interpreted as a file name.
Important implementation details
\r\n
s but not at the very end.Summary
🤖 Generated by Copilot at 7b109e7
This pull request introduces a new feature to handle secret values, such as passwords, in the configuration of EMQ X. It adds a new
secret()
type to the HOCON schema and a newemqx_secret
module to wrap and unwrap secret values using closures. It also updates the MQTT bridge connector and its test suite to use the new feature, and adds Swagger API documentation for it.PR Checklist
Please convert it to a draft if any of the following conditions are not met. Reviewers may skip over until all the items are checked:
changes/(ce|ee)/(feat|perf|fix)-<PR-id>.en.md
files