diff options
| author | doufenghu <[email protected]> | 2024-01-30 19:54:02 +0800 |
|---|---|---|
| committer | doufenghu <[email protected]> | 2024-01-30 19:54:02 +0800 |
| commit | cfb60f30354f6ee1919b7606118b824b5b6ed0c5 (patch) | |
| tree | 68e0ea868688794c61912978fd34ba9014b98303 /groot-bootstrap | |
| parent | 4576db8dbff7754abdbbd88d592a6b8a48a921d7 (diff) | |
[Feature][bootstrap] Add ConfigShade interface and implement the AESConfigShade class for encrypting and decrypting sensitive configuration information, such as usename and password.
Diffstat (limited to 'groot-bootstrap')
13 files changed, 465 insertions, 5 deletions
diff --git a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/AESConfigShade.java b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/AESConfigShade.java new file mode 100644 index 0000000..2b5d0a4 --- /dev/null +++ b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/AESConfigShade.java @@ -0,0 +1,36 @@ +package com.geedgenetworks.bootstrap.command; + +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.symmetric.SymmetricAlgorithm; +import com.geedgenetworks.common.config.ConfigShade; +import java.nio.charset.StandardCharsets; + +public class AESConfigShade implements ConfigShade { + private static final String IDENTIFIER = "aes"; + + private static final byte[] SECURITY_KEY = + SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue(), ".geedgenetworks.".getBytes(StandardCharsets.UTF_8)).getEncoded() ; + + private static final String[] SENSITIVE_OPTIONS = + new String[] {"connection.user", "connection.password", "kafka.sasl.jaas.config"}; + + @Override + public String[] sensitiveOptions() { + return SENSITIVE_OPTIONS; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public String encrypt(String content) { + return SecureUtil.aes(SECURITY_KEY).encryptHex(content, StandardCharsets.UTF_8); + } + + @Override + public String decrypt(String content) { + return SecureUtil.aes(SECURITY_KEY).decryptStr(content, StandardCharsets.UTF_8); + } +} diff --git a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/Base64ConfigShade.java b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/Base64ConfigShade.java new file mode 100644 index 0000000..4ae2b5c --- /dev/null +++ b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/Base64ConfigShade.java @@ -0,0 +1,28 @@ +package com.geedgenetworks.bootstrap.command; + +import com.geedgenetworks.common.config.ConfigShade; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class Base64ConfigShade implements ConfigShade { + private static final Base64.Encoder ENCODER = Base64.getEncoder(); + + private static final Base64.Decoder DECODER = Base64.getDecoder(); + + private static final String IDENTIFIER = "base64"; + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public String encrypt(String content) { + return ENCODER.encodeToString(content.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public String decrypt(String content) { + return new String(DECODER.decode(content)); + } +} diff --git a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/CommandArgs.java b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/CommandArgs.java index 2a00474..f83183c 100644 --- a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/CommandArgs.java +++ b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/CommandArgs.java @@ -30,16 +30,26 @@ public abstract class CommandArgs { names = {"--check"}, description = "Whether check config") protected boolean checkConfig = false; + + @Parameter(names = {"-i", "--variable"}, - splitter = ParameterSplitter.class, - description = "user-defined parameters , such as -i data_center=bj " + - "We use ',' as separator, when inside \"\", ',' are treated as normal characters instead of delimiters.") + splitter = ParameterSplitter.class, + description = "user-defined parameters , such as -i data_center=bj " + + "We use ',' as separator, when inside \"\", ',' are treated as normal characters instead of delimiters.") protected List<String> variables = Collections.emptyList(); @Parameter(names = {"-n", "--name"}, - description = "job name") + description = "job name") protected String jobName = Constants.DEFAULT_JOB_NAME; + @Parameter(names = {"--encrypt"}, + description = "Encrypt config file, when both --decrypt and --encrypt are specified, only --encrypt will take effect") + protected boolean encrypt = false; + + @Parameter(names = {"--decrypt"}, + description = "Decrypt config file, When both --decrypt and --encrypt are specified, only --encrypt will take effect") + protected boolean decrypt = false; + protected List<String> originalParameters = Collections.emptyList(); public abstract Command buildCommand(); diff --git a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ConfDecryptCommand.java b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ConfDecryptCommand.java new file mode 100644 index 0000000..1476d2e --- /dev/null +++ b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ConfDecryptCommand.java @@ -0,0 +1,42 @@ +package com.geedgenetworks.bootstrap.command; + +import cn.hutool.setting.yaml.YamlUtil; +import com.geedgenetworks.bootstrap.exception.CommandExecuteException; +import com.geedgenetworks.bootstrap.exception.ConfigCheckException; +import com.geedgenetworks.bootstrap.utils.ConfigShadeUtils; +import com.typesafe.config.*; +import lombok.extern.slf4j.Slf4j; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; + + +import static com.geedgenetworks.bootstrap.utils.ConfigFileUtils.checkConfigExist; +@Slf4j +public class ConfDecryptCommand implements Command<ExecuteCommandArgs>{ + + private final ExecuteCommandArgs executeCommandArgs; + + public ConfDecryptCommand(ExecuteCommandArgs executeCommandArgs) { + this.executeCommandArgs = executeCommandArgs; + } + + @Override + public void execute() throws CommandExecuteException, ConfigCheckException { + String decryptConfigFile = executeCommandArgs.getConfigFile(); + Path configPath = Paths.get(decryptConfigFile); + checkConfigExist(configPath); + Map<String, Object> configMap = YamlUtil.loadByPath(configPath.toString()); + ConfigObject configObject = ConfigValueFactory.fromMap(configMap); + Config config = configObject.toConfig(); + Config decryptConfig = ConfigShadeUtils.decryptConfig(config); + log.info( + "Encrypt config: \n{}", + decryptConfig + .root() + .render(ConfigRenderOptions.defaults().setOriginComments(false))); + + + } +} diff --git a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ConfEncryptCommand.java b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ConfEncryptCommand.java new file mode 100644 index 0000000..dfefbca --- /dev/null +++ b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ConfEncryptCommand.java @@ -0,0 +1,42 @@ +package com.geedgenetworks.bootstrap.command; + +import cn.hutool.setting.yaml.YamlUtil; +import com.geedgenetworks.bootstrap.exception.CommandExecuteException; +import com.geedgenetworks.bootstrap.exception.ConfigCheckException; +import com.geedgenetworks.bootstrap.utils.ConfigShadeUtils; +import com.typesafe.config.*; +import lombok.extern.slf4j.Slf4j; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; + +import static com.geedgenetworks.bootstrap.utils.ConfigFileUtils.checkConfigExist; + +@Slf4j +public class ConfEncryptCommand implements Command<ExecuteCommandArgs>{ + private final ExecuteCommandArgs executeCommandArgs; + + public ConfEncryptCommand(ExecuteCommandArgs executeCommandArgs) { + this.executeCommandArgs = executeCommandArgs; + } + @Override + public void execute() throws CommandExecuteException, ConfigCheckException { + if (executeCommandArgs.isDecrypt()) { + log.warn( + "When both --decrypt and --encrypt are specified, only --encrypt will take effect"); + } + String encryptConfigFile = executeCommandArgs.getConfigFile(); + Path configPath = Paths.get(encryptConfigFile); + Map<String, Object> configMap = YamlUtil.loadByPath(configPath.toString()); + ConfigObject configObject = ConfigValueFactory.fromMap(configMap); + Config config = configObject.toConfig(); + Config encryptConfig = ConfigShadeUtils.encryptConfig(config); + log.info( + "Encrypt config: \n{}", + encryptConfig + .root() + .render(ConfigRenderOptions.defaults().setOriginComments(false))); + + } +} diff --git a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ConfValidateCommand.java b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ConfValidateCommand.java new file mode 100644 index 0000000..e6a9da4 --- /dev/null +++ b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ConfValidateCommand.java @@ -0,0 +1,24 @@ +package com.geedgenetworks.bootstrap.command; + +import com.geedgenetworks.bootstrap.exception.CommandExecuteException; +import com.geedgenetworks.bootstrap.exception.ConfigCheckException; +import com.geedgenetworks.bootstrap.utils.ConfigFileUtils; +import lombok.extern.slf4j.Slf4j; + +import java.nio.file.Path; + +@Slf4j +public class ConfValidateCommand implements Command<ExecuteCommandArgs> { + private final ExecuteCommandArgs executeCommandArgs; + + public ConfValidateCommand(ExecuteCommandArgs executeCommandArgs) { + this.executeCommandArgs = executeCommandArgs; + } + + + @Override + public void execute() throws CommandExecuteException, ConfigCheckException { + Path configFile = ConfigFileUtils.getConfigPath(executeCommandArgs); + // todo validate config file + } +} diff --git a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ExecuteCommand.java b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ExecuteCommand.java index dc73bd1..17bc278 100644 --- a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ExecuteCommand.java +++ b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ExecuteCommand.java @@ -7,6 +7,7 @@ import com.geedgenetworks.bootstrap.exception.JobExecuteException; import com.geedgenetworks.bootstrap.execution.ExecutionConfigKeyName; import com.geedgenetworks.bootstrap.execution.JobExecution; import com.geedgenetworks.bootstrap.utils.ConfigFileUtils; +import com.geedgenetworks.bootstrap.utils.ConfigShadeUtils; import com.geedgenetworks.common.Constants; import com.geedgenetworks.common.config.ConfigProvider; import com.geedgenetworks.common.config.GrootStreamConfig; @@ -35,6 +36,7 @@ public class ExecuteCommand implements Command<ExecuteCommandArgs> { Map<String, Object> configMap = YamlUtil.loadByPath(configFile.toString()); ConfigObject configObject = ConfigValueFactory.fromMap(configMap); Config config = configObject.toConfig(); + config = ConfigShadeUtils.decryptConfig(config); // if user specified job name using command line arguments, override config option if (!executeCommandArgs.getJobName().equals(Constants.DEFAULT_JOB_NAME)) { config = config.withValue( diff --git a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ExecuteCommandArgs.java b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ExecuteCommandArgs.java index a6b2dd6..a6ccadc 100644 --- a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ExecuteCommandArgs.java +++ b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/command/ExecuteCommandArgs.java @@ -35,8 +35,17 @@ public class ExecuteCommandArgs extends CommandArgs { StartBuilder.setDeployMode(getDeployMode()); userParamsToSysEnv(); if(checkConfig) { - // todo check job config + return new ConfValidateCommand(this); } + + if (encrypt) { + return new ConfEncryptCommand(this); + } + + if (decrypt) { + return new ConfDecryptCommand(this); + } + return new ExecuteCommand(this); } diff --git a/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/utils/ConfigShadeUtils.java b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/utils/ConfigShadeUtils.java new file mode 100644 index 0000000..3e6663e --- /dev/null +++ b/groot-bootstrap/src/main/java/com/geedgenetworks/bootstrap/utils/ConfigShadeUtils.java @@ -0,0 +1,137 @@ +package com.geedgenetworks.bootstrap.utils; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.geedgenetworks.common.Constants; +import com.geedgenetworks.common.config.ConfigShade; +import com.geedgenetworks.common.config.TypesafeConfigUtils; +import com.google.common.base.Preconditions; +import com.typesafe.config.*; +import lombok.extern.slf4j.Slf4j; +import java.util.*; +import java.util.function.BiFunction; + +/** Config shade utilities */ +@Slf4j +public final class ConfigShadeUtils { + + private static final String SHADE_IDENTIFIER_OPTION = "shade.identifier"; + + private static final String[] DEFAULT_SENSITIVE_OPTIONS = + new String[] {"password", "username", "auth"}; + + private static final Map<String, ConfigShade> CONFIG_SHADES = new HashMap<>(); + + private static final ConfigShade DEFAULT_SHADE = new DefaultConfigShade(); + + static { + ServiceLoader<ConfigShade> serviceLoader = ServiceLoader.load(ConfigShade.class); + Iterator<ConfigShade> it = serviceLoader.iterator(); + it.forEachRemaining( + configShade -> { + CONFIG_SHADES.put(configShade.getIdentifier(), configShade); + }); + log.info("Load config shade: {}", CONFIG_SHADES.keySet()); + } + + public static String encryptOption(String identifier, String content) { + ConfigShade configShade = CONFIG_SHADES.getOrDefault(identifier, DEFAULT_SHADE); + return configShade.encrypt(content); + } + + public static String decryptOption(String identifier, String content) { + ConfigShade configShade = CONFIG_SHADES.getOrDefault(identifier, DEFAULT_SHADE); + return configShade.decrypt(content); + } + + public static Config decryptConfig(Config config) { + String identifier = + TypesafeConfigUtils.getConfig( + config.hasPath(ConfigUtil.joinPath(Constants.APPLICATION, Constants.APPLICATION_ENV)) + ? config.getConfig(ConfigUtil.joinPath(Constants.APPLICATION, Constants.APPLICATION_ENV)) + : ConfigFactory.empty(), + ConfigUtil.joinPath(SHADE_IDENTIFIER_OPTION), + DEFAULT_SHADE.getIdentifier()); + return decryptConfig(identifier, config); + } + + public static Config encryptConfig(Config config) { + String identifier = + TypesafeConfigUtils.getConfig( + config.hasPath(ConfigUtil.joinPath(Constants.APPLICATION, Constants.APPLICATION_ENV)) + ? config.getConfig(ConfigUtil.joinPath(Constants.APPLICATION, Constants.APPLICATION_ENV)) + : ConfigFactory.empty(), + ConfigUtil.joinPath(SHADE_IDENTIFIER_OPTION), + DEFAULT_SHADE.getIdentifier()); + return encryptConfig(identifier, config); + } + + public static Config decryptConfig(String identifier, Config config) { + return processConfig(identifier, config, true); + } + + public static Config encryptConfig(String identifier, Config config) { + return processConfig(identifier, config, false); + } + + @SuppressWarnings("unchecked") + private static Config processConfig(String identifier, Config config, boolean isDecrypted) { + ConfigShade configShade = CONFIG_SHADES.getOrDefault(identifier, DEFAULT_SHADE); + List<String> sensitiveOptions = new ArrayList<>(Arrays.asList(DEFAULT_SENSITIVE_OPTIONS)); + sensitiveOptions.addAll(Arrays.asList(configShade.sensitiveOptions())); + BiFunction<String, Object, String> processFunction = + (key, value) -> { + if (isDecrypted) { + return configShade.decrypt(value.toString()); + } else { + return configShade.encrypt(value.toString()); + } + }; + String jsonString = config.root().render(ConfigRenderOptions.concise()); + JSONObject configMap = JSON.parseObject(jsonString); + JSONObject sources = configMap.getJSONObject(Constants.SOURCES); + JSONObject sinks = configMap.getJSONObject(Constants.SINKS); + Preconditions.checkArgument( + !sources.isEmpty(), "Miss <Source> config! Please check the config file."); + Preconditions.checkArgument( + !sinks.isEmpty(), "Miss <Sink> config! Please check the config file."); + + sources.values().forEach((value) -> { + JSONObject source = (JSONObject) value; + JSONObject propertiesObject = source.getJSONObject("properties"); + for (String sensitiveOption : sensitiveOptions) { + propertiesObject.computeIfPresent(sensitiveOption, processFunction); + } + }); + + sinks.values().forEach((value) -> { + JSONObject sink = (JSONObject) value; + JSONObject propertiesObject = sink.getJSONObject("properties"); + for (String sensitiveOption : sensitiveOptions) { + propertiesObject.computeIfPresent(sensitiveOption, processFunction); + } + }); + return ConfigValueFactory.fromMap(configMap).toConfig(); + } + + + private static class DefaultConfigShade implements ConfigShade { + private static final String IDENTIFIER = "default"; + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public String encrypt(String content) { + return content; + } + + @Override + public String decrypt(String content) { + return content; + } + } + +} diff --git a/groot-bootstrap/src/main/resources/META-INF/services/com.geedgenetworks.common.config.ConfigShade b/groot-bootstrap/src/main/resources/META-INF/services/com.geedgenetworks.common.config.ConfigShade new file mode 100644 index 0000000..6654db5 --- /dev/null +++ b/groot-bootstrap/src/main/resources/META-INF/services/com.geedgenetworks.common.config.ConfigShade @@ -0,0 +1,2 @@ +com.geedgenetworks.bootstrap.command.Base64ConfigShade +com.geedgenetworks.bootstrap.command.AESConfigShade
\ No newline at end of file diff --git a/groot-bootstrap/src/test/java/com/geedgenetworks/bootstrap/utils/ConfigShadeTest.java b/groot-bootstrap/src/test/java/com/geedgenetworks/bootstrap/utils/ConfigShadeTest.java new file mode 100644 index 0000000..ccdd224 --- /dev/null +++ b/groot-bootstrap/src/test/java/com/geedgenetworks/bootstrap/utils/ConfigShadeTest.java @@ -0,0 +1,71 @@ +package com.geedgenetworks.bootstrap.utils; + +import cn.hutool.setting.yaml.YamlUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.geedgenetworks.common.Constants; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigObject; +import com.typesafe.config.ConfigRenderOptions; +import com.typesafe.config.ConfigValueFactory; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Paths; +import java.util.Map; + +@Slf4j +public class ConfigShadeTest { + + private static final String USERNAME = "grootstream"; + + private static final String PASSWORD = "grootstream_password"; + + @Test + public void testParseConfig() throws URISyntaxException { + URL resource = ConfigShadeTest.class.getResource("/inline_to_clickhouse.yaml"); + Assertions.assertNotNull(resource); + Map<String, Object> configMap = YamlUtil.loadByPath(Paths.get(resource.toURI()).toString()); + ConfigObject configObject = ConfigValueFactory.fromMap(configMap); + Config decryptConfig = ConfigShadeUtils.decryptConfig(configObject.toConfig()); + String jsonString = decryptConfig.root().render(ConfigRenderOptions.concise()); + JSONObject jsonObject = JSON.parseObject(jsonString); + JSONObject sinkObject = jsonObject.getJSONObject(Constants.SINKS); + log.info("Decrypt config: {}", decryptConfig.root().render(ConfigRenderOptions.concise())); + Assertions.assertEquals(sinkObject.keySet().size(), 1); + Assertions.assertNotNull(sinkObject); + Assertions.assertNotNull(sinkObject.getJSONObject("clickhouse_sink")); + Assertions.assertNotNull(sinkObject.getJSONObject("clickhouse_sink") + .getJSONObject("properties")); + Assertions.assertEquals(sinkObject.getJSONObject("clickhouse_sink") + .getJSONObject("properties").isEmpty(), false); + Assertions.assertEquals(sinkObject.getJSONObject("clickhouse_sink") + .getJSONObject("properties").get("connection.user"),USERNAME); + Assertions.assertNotNull(sinkObject.getJSONObject("clickhouse_sink") + .getJSONObject("properties").get("connection.password"), PASSWORD); + } + + @Test + public void testDecryptAndEncrypt() { + String encryptUsername = ConfigShadeUtils.encryptOption("base64", USERNAME); + String decryptUsername = ConfigShadeUtils.decryptOption("base64", encryptUsername); + String encryptPassword = ConfigShadeUtils.encryptOption("base64", PASSWORD); + String decryptPassword = ConfigShadeUtils.decryptOption("base64", encryptPassword); + Assertions.assertEquals("Z3Jvb3RzdHJlYW0=", encryptUsername); + Assertions.assertEquals("Z3Jvb3RzdHJlYW1fcGFzc3dvcmQ=", encryptPassword); + Assertions.assertEquals(decryptUsername, USERNAME); + Assertions.assertEquals(decryptPassword, PASSWORD); + encryptUsername = ConfigShadeUtils.encryptOption("aes", USERNAME); + decryptUsername = ConfigShadeUtils.decryptOption("aes", encryptUsername); + encryptPassword = ConfigShadeUtils.encryptOption("aes", PASSWORD); + decryptPassword = ConfigShadeUtils.decryptOption("aes", encryptPassword); + Assertions.assertEquals("ed986337dfdbe341be1d29702e6ae619", encryptUsername); + Assertions.assertEquals("159c7da83d988a9ec041d10a6bfbe221bcbaed6b62d9cc1b04ff51e633ebd105", encryptPassword); + Assertions.assertEquals(decryptUsername, USERNAME); + Assertions.assertEquals(decryptPassword, PASSWORD); + System.out.println( ConfigShadeUtils.encryptOption("aes", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"admin\" password=\"galaxy2019\";")); + System.out.println( ConfigShadeUtils.decryptOption("aes", "454f65ea6eef1256e3067104f82730e737b68959560966b811e7ff364116b03124917eb2b0f3596f14733aa29ebad9352644ce1a5c85991c6f01ba8a5e8f177a7ff0b2d3889a424249967b3870b50993d9644f239f0de82cdb13bdb502959e16afadffa49ef1e1d2b9c9b5113e619817")); + } +} diff --git a/groot-bootstrap/src/test/resources/META-INF/services/com.geedgenetworks.common.config.ConfigShade b/groot-bootstrap/src/test/resources/META-INF/services/com.geedgenetworks.common.config.ConfigShade new file mode 100644 index 0000000..6654db5 --- /dev/null +++ b/groot-bootstrap/src/test/resources/META-INF/services/com.geedgenetworks.common.config.ConfigShade @@ -0,0 +1,2 @@ +com.geedgenetworks.bootstrap.command.Base64ConfigShade +com.geedgenetworks.bootstrap.command.AESConfigShade
\ No newline at end of file diff --git a/groot-bootstrap/src/test/resources/inline_to_clickhouse.yaml b/groot-bootstrap/src/test/resources/inline_to_clickhouse.yaml new file mode 100644 index 0000000..9038cc8 --- /dev/null +++ b/groot-bootstrap/src/test/resources/inline_to_clickhouse.yaml @@ -0,0 +1,55 @@ +sources: # [object] Define connector source + inline_source: + type: inline + fields: # [array of object] Schema field projection, support read data only from specified fields. + - name: log_id + type: bigint + - name: recv_time + type: bigint + - name: server_fqdn + type: string + - name: server_domain + type: string + - name: client_ip + type: string + - name: server_ip + type: string + - name: server_asn + type: string + - name: decoded_as + type: string + - name: device_group + type: string + - name: device_tag + type: string + properties: + # + # [string] Event Data, it will be parsed to Map<String, Object> by the specified format. + # + data: '{"recv_time": 1705565615, "log_id":206211012872372224, "tcp_rtt_ms":128,"decoded_as":"HTTP", "http_version":"http1","http_request_line":"GET / HTTP/1.1","http_host":"www.ct.cn","http_url":"www.ct.cn/","http_user_agent":"curl/8.0.1","http_status_code":200,"http_response_line":"HTTP/1.1 200 OK","http_response_content_type":"text/html; charset=UTF-8","http_response_latency_ms":31,"http_session_duration_ms":5451,"in_src_mac":"ba:bb:a7:3c:67:1c","in_dest_mac":"86:dd:7a:8f:ae:e2","out_src_mac":"86:dd:7a:8f:ae:e2","out_dest_mac":"ba:bb:a7:3c:67:1c","tcp_client_isn":678677906,"tcp_server_isn":1006700307,"address_type":4,"client_ip":"192.11.22.22","server_ip":"8.8.8.8","client_port":42751,"server_port":80,"in_link_id":65535,"out_link_id":65535,"start_timestamp_ms":1703646546127,"end_timestamp_ms":1703646551702,"duration_ms":5575,"sent_pkts":97,"sent_bytes":5892,"received_pkts":250,"received_bytes":333931,"tcp_c2s_ip_fragments":0,"tcp_s2c_ip_fragments":0,"tcp_c2s_rtx_pkts":0,"tcp_c2s_rtx_bytes":0,"tcp_s2c_rtx_pkts":0,"tcp_s2c_rtx_bytes":0,"tcp_c2s_o3_pkts":0,"tcp_s2c_o3_pkts":0,"tcp_c2s_lost_bytes":0,"tcp_s2c_lost_bytes":0,"flags":26418,"flags_identify_info":[100,1,100,60,150,100,1,2],"app_transition":"http.1111.test_1_1","decoded_as":"HTTP","server_fqdn":"www.ct.cn","app":"test_1_1","decoded_path":"ETHERNET.IPv4.TCP.http","fqdn_category_list":[1767],"t_vsys_id":1,"vsys_id":1,"session_id":290538039798223400,"tcp_handshake_latency_ms":41,"client_os_desc":"Windows","server_os_desc":"Linux","data_center":"center-xxg-tsgx","device_group":"group-xxg-tsgx","device_tag":"{\"tags\":[{\"tag\":\"data_center\",\"value\":\"center-xxg-tsgx\"},{\"tag\":\"device_group\",\"value\":\"group-xxg-tsgx\"}]}","device_id":"9800165603247024","sled_ip":"192.168.40.39","dup_traffic_flag":0}' + format: json + json.ignore.parse.errors: false + +sinks: + clickhouse_sink: + type: clickhouse + properties: + host: 192.168.44.12:9001 + table: tsg_galaxy_v3.inline_source_test_local + batch.size: 10 + batch.interval: 1s + connection.user: ed986337dfdbe341be1d29702e6ae619 + connection.password: 159c7da83d988a9ec041d10a6bfbe221bcbaed6b62d9cc1b04ff51e633ebd105 + +application: # [object] Define job configuration + env: + name: example-inline-to-clickhouse + parallelism: 3 + shade.identifier: aes + pipeline: + object-reuse: true + topology: + - name: inline_source + downstream: [clickhouse_sink] + - name: clickhouse_sink + downstream: []
\ No newline at end of file |
