Преглед изворни кода

Merge pull request #14102 from zmstone/241029-support-file-secret-for-ssl-private-key-passphrase

feat: support file:///path/to/secret/file as SSL private key passphrase
zmstone пре 1 година
родитељ
комит
781e4e531e

+ 2 - 4
apps/emqx/src/emqx_schema.erl

@@ -2241,16 +2241,14 @@ common_ssl_opts_schema(Defaults, Type) ->
                 }
             )},
         {"password",
-            sc(
-                string(),
+            emqx_schema_secret:mk(
                 #{
                     sensitive => true,
                     required => false,
                     example => <<"">>,
                     format => <<"password">>,
                     desc => ?DESC(common_ssl_opts_schema_password),
-                    importance => ?IMPORTANCE_LOW,
-                    converter => fun password_converter/2
+                    importance => ?IMPORTANCE_LOW
                 }
             )},
         {"versions", tls_versions_schema(Collection)},

+ 12 - 2
apps/emqx/src/emqx_tls_lib.erl

@@ -532,13 +532,15 @@ to_server_opts(Type, Opts) ->
     Versions = integral_versions(Type, maps:get(versions, Opts, undefined)),
     Ciphers = integral_ciphers(Versions, maps:get(ciphers, Opts, undefined)),
     Path = fun(Key) -> resolve_cert_path_for_read_strict(maps:get(Key, Opts, undefined)) end,
+    Password = ensure_password(maps:get(password, Opts, undefined)),
     ensure_valid_options(
         maps:to_list(Opts#{
             keyfile => Path(keyfile),
             certfile => Path(certfile),
             cacertfile => Path(cacertfile),
             ciphers => Ciphers,
-            versions => Versions
+            versions => Versions,
+            password => Password
         }),
         Versions
     ).
@@ -576,7 +578,7 @@ to_client_opts(Type, Opts) ->
                     {ciphers, Ciphers},
                     {reuse_sessions, Get(reuse_sessions)},
                     {depth, Get(depth)},
-                    {password, ensure_str(Get(password))},
+                    {password, ensure_password(Get(password))},
                     {secure_renegotiate, Get(secure_renegotiate)}
                 ] ++ hostname_check(Verify),
                 Versions
@@ -709,6 +711,14 @@ ensure_sni(undefined) -> undefined;
 ensure_sni(L) when is_list(L) -> L;
 ensure_sni(B) when is_binary(B) -> unicode:characters_to_list(B, utf8).
 
+ensure_password(Password) ->
+    case emqx_secret:unwrap(Password) of
+        undefined ->
+            undefined;
+        S ->
+            ensure_str(S)
+    end.
+
 ensure_str(undefined) -> undefined;
 ensure_str(L) when is_list(L) -> L;
 ensure_str(B) when is_binary(B) -> unicode:characters_to_list(B, utf8).

+ 13 - 0
apps/emqx/test/emqx_tls_lib_tests.erl

@@ -334,6 +334,19 @@ to_client_opts_test() ->
     ),
     ok.
 
+password_file_test() ->
+    T = integer_to_list(erlang:system_time(microsecond)),
+    TmpFile = filename:join("/tmp", "secret-" ++ T ++ ".txt"),
+    ok = file:write_file(TmpFile, T),
+    ConfigValue = emqx_schema_secret:convert_secret("file://" ++ TmpFile, #{}),
+    Options = #{enable => true, password => ConfigValue},
+    ClientOpts = emqx_tls_lib:to_client_opts(tls, Options),
+    ServerOpts = emqx_tls_lib:to_server_opts(tls, Options),
+    {password, PasswordResolved} = lists:keyfind(password, 1, ClientOpts),
+    ?assertEqual({password, PasswordResolved}, lists:keyfind(password, 1, ServerOpts)),
+    ?assertEqual(T, PasswordResolved),
+    ok.
+
 to_server_opts_test() ->
     VersionsAll = [tlsv1, 'tlsv1.1', 'tlsv1.2', 'tlsv1.3'],
     Versions13Only = ['tlsv1.3'],

+ 3 - 0
changes/ce/feat-14102.en.md

@@ -0,0 +1,3 @@
+Support secret file for SSL private key passphrase.
+
+EMQX now can read passphrase from a secret file if `password` is configured as `...ssl.password = "file://{path-to-secret-file}"`