-
Notifications
You must be signed in to change notification settings - Fork 3.9k
[improvement](fe) add fe_meta_auth_token for FE meta-service internal HTTP auth #65551
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,6 +52,10 @@ public class ConfigBase { | |
|
|
||
| boolean masterOnly() default false; | ||
|
|
||
| // If true, the value is a secret (e.g. a token or password) and is masked in every | ||
| // config dump API (Config.dump / getConfigInfo), so it is never returned in plaintext. | ||
| boolean sensitive() default false; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because this new masking is opt-in, marking only |
||
|
|
||
| String comment() default ""; | ||
|
|
||
| VariableAnnotation varType() default VariableAnnotation.NONE; | ||
|
|
@@ -191,13 +195,26 @@ private void warnUnknownConfigKeys(String confFile, Properties props) { | |
| } | ||
| } | ||
|
|
||
| // Placeholder returned instead of a sensitive config's real value in any dump API. | ||
| public static final String SENSITIVE_CONF_MASK = "********"; | ||
|
|
||
| // Mask the value of a sensitive config (a non-empty secret) so it is never dumped in plaintext. | ||
| // An empty value is left as-is: it reveals nothing and keeps "unset" visible. | ||
| private static String maskIfSensitive(Field field, String value) { | ||
| ConfField anno = field.getAnnotation(ConfField.class); | ||
| if (anno != null && anno.sensitive() && !Strings.isNullOrEmpty(value)) { | ||
| return SENSITIVE_CONF_MASK; | ||
| } | ||
| return value; | ||
| } | ||
|
|
||
| public static HashMap<String, String> dump() { | ||
| HashMap<String, String> map = new HashMap<>(); | ||
| Field[] fields = confClass.getFields(); | ||
| for (Field f : fields) { | ||
| ConfField anno = f.getAnnotation(ConfField.class); | ||
| if (anno != null) { | ||
| map.put(f.getName(), getConfValue(f)); | ||
| map.put(f.getName(), maskIfSensitive(f, getConfValue(f))); | ||
| } | ||
| } | ||
| return map; | ||
|
|
@@ -441,6 +458,7 @@ public static synchronized List<List<String>> getConfigInfo(PatternMatcher match | |
| if (confKey.equals("sys_log_dir") && Strings.isNullOrEmpty(value)) { | ||
| value = System.getenv("DORIS_HOME") + "/log"; | ||
| } | ||
| value = maskIfSensitive(f, value); | ||
| config.add(value); | ||
| config.add(f.getType().getSimpleName()); | ||
| config.add(String.valueOf(confField.mutable())); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,8 +20,10 @@ | |
| import org.apache.doris.catalog.Env; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I remember there is another util like httpurlutil, InternalHttpsUtils.java
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. InternalHttpsUtils only provides the shared SSLContext/truststore for TLS; HttpURLUtil builds the JDK HttpURLConnection and adds the node-ident + token headers, delegating TLS to InternalHttpsUtils. They're layered, not duplicated. The token is an auth header on the checkFromValidFe-protected meta endpoints, all of which go through HttpURLUtil, and it is sent unconditionally so it rides over HTTPS as well — so InternalHttpsUtils is orthogonal to this change and HTTPS works. |
||
| import org.apache.doris.cloud.security.SecurityChecker; | ||
| import org.apache.doris.common.Config; | ||
| import org.apache.doris.httpv2.meta.MetaBaseAction; | ||
| import org.apache.doris.system.SystemInfoService.HostInfo; | ||
|
|
||
| import com.google.common.base.Strings; | ||
| import com.google.common.collect.Maps; | ||
| import org.apache.http.conn.ssl.NoopHostnameVerifier; | ||
|
|
||
|
|
@@ -50,6 +52,10 @@ public static HttpURLConnection getConnectionWithNodeIdent(String request) throw | |
| HostInfo selfNode = Env.getServingEnv().getSelfNode(); | ||
| conn.setRequestProperty(Env.CLIENT_NODE_HOST_KEY, selfNode.getHost()); | ||
| conn.setRequestProperty(Env.CLIENT_NODE_PORT_KEY, selfNode.getPort() + ""); | ||
| String token = Config.fe_meta_auth_token; | ||
| if (!Strings.isNullOrEmpty(token)) { | ||
| conn.setRequestProperty(MetaBaseAction.TOKEN, token); | ||
| } | ||
| return conn; | ||
| } catch (Exception e) { | ||
| throw new IOException(e); | ||
|
|
@@ -65,6 +71,10 @@ public static Map<String, String> getNodeIdentHeaders() throws IOException { | |
| HostInfo selfNode = Env.getServingEnv().getSelfNode(); | ||
| headers.put(Env.CLIENT_NODE_HOST_KEY, selfNode.getHost()); | ||
| headers.put(Env.CLIENT_NODE_PORT_KEY, selfNode.getPort() + ""); | ||
| String token = Config.fe_meta_auth_token; | ||
| if (!Strings.isNullOrEmpty(token)) { | ||
| headers.put(MetaBaseAction.TOKEN, token); | ||
| } | ||
| return headers; | ||
| } | ||
|
|
||
|
|
||
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 token is added as a regular
@ConfField, so it is also returned by the legacy config API.Config.dump()includes every annotated field with the raw value, and/rest/v1/config/fe?conf_item=fe_meta_auth_tokenserves that map. Although/rest/v1/**goes throughAuthInterceptor, the BasicAuthorizationpath only checks the password and skipsADMIN_OR_NODEunlessConfig.isCloudMode()is true, so a normal authenticated on-prem user can read the meta-service token. Please either gate this config reader with the same unconditional ADMIN check asSHOW FRONTEND CONFIG, or add a sensitive/masked config mechanism and mark this token so every config dump API masks or omits it.