Carry over more config items to client configs. (#4906)

These are uncommon but sometimes used in client configs.

Fixes: #4905
This commit is contained in:
Mike Cohen
2026-06-24 14:20:00 +10:00
committed by GitHub
parent ffee0f3cda
commit bbe2a5883c
12 changed files with 163 additions and 75 deletions
+1 -1
View File
@@ -347,7 +347,7 @@ func doDumpClientConfig() error {
return err
}
client_config := config.GetClientConfig(config_obj)
client_config := config.StripClientConfig(config_obj)
res, err := yaml.Marshal(client_config)
if err != nil {
return fmt.Errorf("Unable to encode config: %w", err)
+1 -1
View File
@@ -137,7 +137,7 @@ func generateGUIConfig(datastore_directory, server_config_path, client_config_pa
fd.Close()
// Now also write a client config
client_config := config.GetClientConfig(config_obj)
client_config := config.StripClientConfig(config_obj)
client_config.Logging = config_obj.Logging
serialized, err = yaml.Marshal(client_config)
+38 -2
View File
@@ -7,9 +7,45 @@ import config_proto "www.velocidex.com/golang/velociraptor/config/proto"
func GetClientConfig(config_obj *config_proto.Config) *config_proto.Config {
// Copy only settings relevant to the client from the main config.
client_config := &config_proto.Config{
Version: config_obj.Version,
Client: config_obj.Client,
Version: config_obj.Version,
Client: config_obj.Client,
Autoexec: config_obj.Autoexec,
// The below are added at runtime..
Remappings: config_obj.Remappings, // --remap flag.
Verbose: config_obj.Verbose, // -v flag
DebugMode: config_obj.DebugMode, // --debug flag
// Logging is populated from the client specific section.
Logging: config_obj.Client.Logging,
}
return client_config
}
// Produce a minima configuration for the client. This function is
// used to prepare a client config from the server config file
// (e.g. for packaging).
func StripClientConfig(config_obj *config_proto.Config) *config_proto.Config {
// Copy only settings relevant to the client from the main config.
client_config := &config_proto.Config{
Version: config_obj.Version,
Client: config_obj.Client,
Autoexec: config_obj.Autoexec,
}
return client_config
}
// Determine if the binary is running as a frontend. At a minimum we
// need a valid Frontend and Datastore sections.
func IsFrontend(config_obj *config_proto.Config) bool {
return config_obj.Datastore != nil &&
config_obj.Frontend != nil
}
// Determine if the binary is running as a client. At a minimum we
// need a valid Client section.
func IsClient(config_obj *config_proto.Config) bool {
return config_obj.Client != nil
}
+2 -2
View File
@@ -106,7 +106,7 @@ func (self *Loader) WithRequiredFrontend() *Loader {
self.validators = append(self.validators, validatorFunction{
name: "WithRequiredFrontend",
validator: func(self *Loader, config_obj *config_proto.Config) error { //
if config_obj.Frontend == nil {
if !IsFrontend(config_obj) {
return errors.New("Frontend config is required")
}
return nil
@@ -119,7 +119,7 @@ func (self *Loader) WithRequiredClient() *Loader {
self.validators = append(self.validators, validatorFunction{
name: "WithRequiredClient",
validator: func(self *Loader, config_obj *config_proto.Config) error {
if config_obj.Client == nil {
if !IsClient(config_obj) {
return errors.New("Client config is required")
}
return nil
+64 -50
View File
@@ -686,8 +686,12 @@ type ClientConfig struct {
// system has less than 2 cores. This allows to increase the
// threadhold. Set to a large number to disable.
LowResourceCpuCount uint64 `protobuf:"varint,53,opt,name=low_resource_cpu_count,json=lowResourceCpuCount,proto3" json:"low_resource_cpu_count,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
// Client specific logging configuration - this can be different
// from the server configuration. Usually the client does not log
// anything but you can enable this for debugging.
Logging *LoggingConfig `protobuf:"bytes,55,opt,name=Logging,proto3" json:"Logging,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ClientConfig) Reset() {
@@ -1035,6 +1039,13 @@ func (x *ClientConfig) GetLowResourceCpuCount() uint64 {
return 0
}
func (x *ClientConfig) GetLogging() *LoggingConfig {
if x != nil {
return x.Logging
}
return nil
}
type APIConfig struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Publicly accessible hostname.
@@ -4864,7 +4875,8 @@ type Config struct {
// Deprecated: Marked as deprecated in config.proto.
Writeback *Writeback `protobuf:"bytes,9,opt,name=Writeback,proto3" json:"Writeback,omitempty"`
// Deprecated - Mail plugin setting are now provided by args.
Mail *MailConfig `protobuf:"bytes,11,opt,name=Mail,proto3" json:"Mail,omitempty"`
Mail *MailConfig `protobuf:"bytes,11,opt,name=Mail,proto3" json:"Mail,omitempty"`
// Server specific logging configuration
Logging *LoggingConfig `protobuf:"bytes,23,opt,name=Logging,proto3" json:"Logging,omitempty"`
// Minion specific overrides
Minion *MinionConfig `protobuf:"bytes,40,opt,name=Minion,proto3" json:"Minion,omitempty"`
@@ -5186,7 +5198,7 @@ const file_config_proto_rawDesc = "" +
"\tdisk_size\x18\x02 \x01(\x04BQ\xe2\xfc\xe3\xc4\x01K\x12IHow many bytes to store in the ring buffer on disk (0 mean no disk file).R\bdiskSize\x12x\n" +
"\x0efilename_linux\x18\x04 \x01(\tBQ\xe2\xfc\xe3\xc4\x01K\x12IName of file to store the ring buffer in (if empty we do not use a file).R\rfilenameLinux\x12|\n" +
"\x10filename_windows\x18\x05 \x01(\tBQ\xe2\xfc\xe3\xc4\x01K\x12IName of file to store the ring buffer in (if empty we do not use a file).R\x0ffilenameWindows\x12z\n" +
"\x0ffilename_darwin\x18\x06 \x01(\tBQ\xe2\xfc\xe3\xc4\x01K\x12IName of file to store the ring buffer in (if empty we do not use a file).R\x0efilenameDarwin\"\xc1\x1c\n" +
"\x0ffilename_darwin\x18\x06 \x01(\tBQ\xe2\xfc\xe3\xc4\x01K\x12IName of file to store the ring buffer in (if empty we do not use a file).R\x0efilenameDarwin\"\xf1\x1c\n" +
"\fClientConfig\x12\x80\x01\n" +
"\x06labels\x18\x06 \x03(\tBh\xe2\xfc\xe3\xc4\x01b\x12`A list of labels the client has. This allows selected groups of clients to be targeted in hunts.R\x06labels\x12a\n" +
"\vserver_urls\x18\b \x03(\tB@\xe2\xfc\xe3\xc4\x01:\x128A list of server URLs the client will try to connect to.R\n" +
@@ -5236,7 +5248,8 @@ const file_config_proto_rawDesc = "" +
"panic_file\x181 \x01(\tR\tpanicFile\x12=\n" +
"\x1binsecure_network_trace_file\x183 \x01(\tR\x18insecureNetworkTraceFile\x12/\n" +
"\x14low_resource_max_cpu\x184 \x01(\x04R\x11lowResourceMaxCpu\x123\n" +
"\x16low_resource_cpu_count\x185 \x01(\x04R\x13lowResourceCpuCount\x1aD\n" +
"\x16low_resource_cpu_count\x185 \x01(\x04R\x13lowResourceCpuCount\x12.\n" +
"\aLogging\x187 \x01(\v2\x14.proto.LoggingConfigR\aLogging\x1aD\n" +
"\x16FallbackAddressesEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xad\x04\n" +
@@ -5718,51 +5731,52 @@ var file_config_proto_depIdxs = []int32{
6, // 7: proto.ClientConfig.local_buffer:type_name -> proto.RingBufferConfig
31, // 8: proto.ClientConfig.Crypto:type_name -> proto.CryptoConfig
36, // 9: proto.ClientConfig.fallback_addresses:type_name -> proto.ClientConfig.FallbackAddressesEntry
37, // 10: proto.ProxyConfig.proxy_url_regexp:type_name -> proto.ProxyConfig.ProxyUrlRegexpEntry
38, // 11: proto.OIDCClaims.role_map:type_name -> proto.OIDCClaims.RoleMapEntry
39, // 12: proto.Authenticator.oidc_auth_url_params:type_name -> proto.Authenticator.OidcAuthUrlParamsEntry
13, // 13: proto.Authenticator.claims:type_name -> proto.OIDCClaims
14, // 14: proto.Authenticator.sub_authenticators:type_name -> proto.Authenticator
18, // 15: proto.GUIConfig.reverse_proxy:type_name -> proto.ReverseProxyConfig
11, // 16: proto.GUIConfig.links:type_name -> proto.GUILink
16, // 17: proto.GUIConfig.initial_users:type_name -> proto.GUIUser
3, // 18: proto.GUIConfig.initial_orgs:type_name -> proto.InitialOrgRecord
14, // 19: proto.GUIConfig.authenticator:type_name -> proto.Authenticator
10, // 20: proto.FrontendConfig.proxy_config:type_name -> proto.ProxyConfig
19, // 21: proto.FrontendConfig.dyn_dns:type_name -> proto.DynDNSConfig
20, // 22: proto.FrontendConfig.resources:type_name -> proto.FrontendResourceControl
25, // 23: proto.LoggingConfig.debug:type_name -> proto.LoggingRetentionConfig
25, // 24: proto.LoggingConfig.info:type_name -> proto.LoggingRetentionConfig
25, // 25: proto.LoggingConfig.error:type_name -> proto.LoggingRetentionConfig
41, // 26: proto.AutoExecConfig.artifact_definitions:type_name -> proto.Artifact
32, // 27: proto.RemappingConfig.from:type_name -> proto.MountPoint
32, // 28: proto.RemappingConfig.on:type_name -> proto.MountPoint
42, // 29: proto.RemappingConfig.env:type_name -> proto.VQLEnv
0, // 30: proto.Config.version:type_name -> proto.Version
7, // 31: proto.Config.Client:type_name -> proto.ClientConfig
8, // 32: proto.Config.API:type_name -> proto.APIConfig
15, // 33: proto.Config.GUI:type_name -> proto.GUIConfig
17, // 34: proto.Config.CA:type_name -> proto.CAConfig
21, // 35: proto.Config.Frontend:type_name -> proto.FrontendConfig
21, // 36: proto.Config.ExtraFrontends:type_name -> proto.FrontendConfig
22, // 37: proto.Config.Datastore:type_name -> proto.DatastoreConfig
2, // 38: proto.Config.Writeback:type_name -> proto.Writeback
24, // 39: proto.Config.Mail:type_name -> proto.MailConfig
26, // 40: proto.Config.Logging:type_name -> proto.LoggingConfig
23, // 41: proto.Config.Minion:type_name -> proto.MinionConfig
27, // 42: proto.Config.Monitoring:type_name -> proto.MonitoringConfig
9, // 43: proto.Config.api_config:type_name -> proto.ApiClientConfig
28, // 44: proto.Config.autoexec:type_name -> proto.AutoExecConfig
30, // 45: proto.Config.defaults:type_name -> proto.Defaults
33, // 46: proto.Config.remappings:type_name -> proto.RemappingConfig
29, // 47: proto.Config.services:type_name -> proto.ServerServicesConfig
34, // 48: proto.Config.security:type_name -> proto.Security
12, // 49: proto.OIDCClaims.RoleMapEntry.value:type_name -> proto.OIDCACL
50, // [50:50] is the sub-list for method output_type
50, // [50:50] is the sub-list for method input_type
50, // [50:50] is the sub-list for extension type_name
50, // [50:50] is the sub-list for extension extendee
0, // [0:50] is the sub-list for field type_name
26, // 10: proto.ClientConfig.Logging:type_name -> proto.LoggingConfig
37, // 11: proto.ProxyConfig.proxy_url_regexp:type_name -> proto.ProxyConfig.ProxyUrlRegexpEntry
38, // 12: proto.OIDCClaims.role_map:type_name -> proto.OIDCClaims.RoleMapEntry
39, // 13: proto.Authenticator.oidc_auth_url_params:type_name -> proto.Authenticator.OidcAuthUrlParamsEntry
13, // 14: proto.Authenticator.claims:type_name -> proto.OIDCClaims
14, // 15: proto.Authenticator.sub_authenticators:type_name -> proto.Authenticator
18, // 16: proto.GUIConfig.reverse_proxy:type_name -> proto.ReverseProxyConfig
11, // 17: proto.GUIConfig.links:type_name -> proto.GUILink
16, // 18: proto.GUIConfig.initial_users:type_name -> proto.GUIUser
3, // 19: proto.GUIConfig.initial_orgs:type_name -> proto.InitialOrgRecord
14, // 20: proto.GUIConfig.authenticator:type_name -> proto.Authenticator
10, // 21: proto.FrontendConfig.proxy_config:type_name -> proto.ProxyConfig
19, // 22: proto.FrontendConfig.dyn_dns:type_name -> proto.DynDNSConfig
20, // 23: proto.FrontendConfig.resources:type_name -> proto.FrontendResourceControl
25, // 24: proto.LoggingConfig.debug:type_name -> proto.LoggingRetentionConfig
25, // 25: proto.LoggingConfig.info:type_name -> proto.LoggingRetentionConfig
25, // 26: proto.LoggingConfig.error:type_name -> proto.LoggingRetentionConfig
41, // 27: proto.AutoExecConfig.artifact_definitions:type_name -> proto.Artifact
32, // 28: proto.RemappingConfig.from:type_name -> proto.MountPoint
32, // 29: proto.RemappingConfig.on:type_name -> proto.MountPoint
42, // 30: proto.RemappingConfig.env:type_name -> proto.VQLEnv
0, // 31: proto.Config.version:type_name -> proto.Version
7, // 32: proto.Config.Client:type_name -> proto.ClientConfig
8, // 33: proto.Config.API:type_name -> proto.APIConfig
15, // 34: proto.Config.GUI:type_name -> proto.GUIConfig
17, // 35: proto.Config.CA:type_name -> proto.CAConfig
21, // 36: proto.Config.Frontend:type_name -> proto.FrontendConfig
21, // 37: proto.Config.ExtraFrontends:type_name -> proto.FrontendConfig
22, // 38: proto.Config.Datastore:type_name -> proto.DatastoreConfig
2, // 39: proto.Config.Writeback:type_name -> proto.Writeback
24, // 40: proto.Config.Mail:type_name -> proto.MailConfig
26, // 41: proto.Config.Logging:type_name -> proto.LoggingConfig
23, // 42: proto.Config.Minion:type_name -> proto.MinionConfig
27, // 43: proto.Config.Monitoring:type_name -> proto.MonitoringConfig
9, // 44: proto.Config.api_config:type_name -> proto.ApiClientConfig
28, // 45: proto.Config.autoexec:type_name -> proto.AutoExecConfig
30, // 46: proto.Config.defaults:type_name -> proto.Defaults
33, // 47: proto.Config.remappings:type_name -> proto.RemappingConfig
29, // 48: proto.Config.services:type_name -> proto.ServerServicesConfig
34, // 49: proto.Config.security:type_name -> proto.Security
12, // 50: proto.OIDCClaims.RoleMapEntry.value:type_name -> proto.OIDCACL
51, // [51:51] is the sub-list for method output_type
51, // [51:51] is the sub-list for method input_type
51, // [51:51] is the sub-list for extension type_name
51, // [51:51] is the sub-list for extension extendee
0, // [0:51] is the sub-list for field type_name
}
func init() { file_config_proto_init() }
+7
View File
@@ -353,6 +353,12 @@ message ClientConfig {
// system has less than 2 cores. This allows to increase the
// threadhold. Set to a large number to disable.
uint64 low_resource_cpu_count = 53;
// Client specific logging configuration - this can be different
// from the server configuration. Usually the client does not log
// anything but you can enable this for debugging.
LoggingConfig Logging = 55;
}
message APIConfig {
@@ -1549,6 +1555,7 @@ message Config {
// Deprecated - Mail plugin setting are now provided by args.
MailConfig Mail = 11;
// Server specific logging configuration
LoggingConfig Logging = 23;
// Minion specific overrides
+27 -12
View File
@@ -102,9 +102,11 @@ func InitLogging(config_obj *config_proto.Config) error {
&GenericComponent, &FrontendComponent, &ClientComponent,
&GUIComponent, &ToolComponent, &APICmponent, &Audit}
logging_config := getLoggingConfig(config_obj)
// User asked for all components to go in the same log.
if config_obj.Logging != nil &&
!config_obj.Logging.SeparateLogsPerComponent {
if logging_config != nil &&
!logging_config.SeparateLogsPerComponent {
components = []*string{&GenericComponent}
}
@@ -303,8 +305,9 @@ func (self *LogManager) GetLogger(
self.mu.Lock()
defer self.mu.Unlock()
if config_obj.Logging != nil &&
!config_obj.Logging.SeparateLogsPerComponent {
logging_config := getLoggingConfig(config_obj)
if logging_config != nil &&
!logging_config.SeparateLogsPerComponent {
component = &GenericComponent
}
@@ -345,10 +348,12 @@ func getRotator(
rotator_config *config_proto.LoggingRetentionConfig,
base_path string) (io.Writer, error, bool) {
logging_config := getLoggingConfig(config_obj)
if rotator_config == nil {
rotator_config = &config_proto.LoggingRetentionConfig{
RotationTime: config_obj.Logging.RotationTime,
MaxAge: config_obj.Logging.MaxAge,
RotationTime: logging_config.RotationTime,
MaxAge: logging_config.MaxAge,
}
}
@@ -399,12 +404,14 @@ func (self *LogManager) makeNewComponent(
DisableHTMLEscape: true,
}
logging_config := getLoggingConfig(config_obj)
if !disable_log_to_files &&
config_obj != nil &&
config_obj.Logging != nil &&
config_obj.Logging.OutputDirectory != "" {
logging_config != nil &&
logging_config.OutputDirectory != "" {
output_directory := utils.ExpandEnv(config_obj.Logging.OutputDirectory)
output_directory := utils.ExpandEnv(logging_config.OutputDirectory)
base_directory := utils.Join(output_directory, node_name)
err := os.MkdirAll(base_directory, 0700)
if err != nil {
@@ -417,7 +424,7 @@ func (self *LogManager) makeNewComponent(
Prelog("Initializing logging for %v\n", base_filename)
rotator, err, enable := getRotator(
config_obj, config_obj.Logging.Debug,
config_obj, logging_config.Debug,
base_filename+"_debug.log")
if err != nil {
return nil, err
@@ -426,7 +433,7 @@ func (self *LogManager) makeNewComponent(
enabled[DEBUG] = enable
rotator, err, enable = getRotator(
config_obj, config_obj.Logging.Info,
config_obj, logging_config.Info,
base_filename+"_info.log")
if err != nil {
return nil, err
@@ -435,7 +442,7 @@ func (self *LogManager) makeNewComponent(
enabled[INFO] = enable
rotator, err, enable = getRotator(
config_obj, config_obj.Logging.Error,
config_obj, logging_config.Error,
base_filename+"_error.log")
if err != nil {
return nil, err
@@ -584,3 +591,11 @@ func (self inMemoryLogWriter) Write(p []byte) (n int, err error) {
func newInMemoryLogWriter() *inMemoryLogWriter {
return &inMemoryLogWriter{}
}
func getLoggingConfig(config_obj *config_proto.Config) *config_proto.LoggingConfig {
logging_config := config_obj.Logging
if logging_config == nil && config_obj.Client != nil {
logging_config = config_obj.Client.Logging
}
return logging_config
}
+7 -5
View File
@@ -14,24 +14,26 @@ func maybeAddRemoteSyslog(
ctx context.Context,
config_obj *config_proto.Config, manager *LogManager) error {
if config_obj.Logging == nil ||
config_obj.Logging.RemoteSyslogServer == "" {
logging_config := getLoggingConfig(config_obj)
if logging_config == nil ||
logging_config.RemoteSyslogServer == "" {
return nil
}
protocol := config_obj.Logging.RemoteSyslogProtocol
protocol := logging_config.RemoteSyslogProtocol
if protocol == "" {
protocol = "udp"
}
server := config_obj.Logging.RemoteSyslogServer
server := logging_config.RemoteSyslogServer
if !strings.Contains(server, ":") {
server += ":514"
}
components := make(map[*string]bool)
for _, c := range config_obj.Logging.RemoteSyslogComponents {
for _, c := range logging_config.RemoteSyslogComponents {
switch c {
case GenericComponent:
components[&GenericComponent] = true
+4
View File
@@ -65,6 +65,10 @@ type DEBBuilder struct {
state *ordereddict.Dict
}
func (self *DEBBuilder) Close() error {
return self.DebPkg.Close()
}
func (self *DEBBuilder) AddFileString(data, path string) error {
switch path {
+4
View File
@@ -20,6 +20,7 @@ func (self *PackagingTestSuite) TestDEBClient() {
builder, err := BuildDeb(spec)
assert.NoError(self.T(), err)
defer builder.Close()
goldie.Assert(self.T(), "TestDEBClient",
[]byte(builder.Debug()))
@@ -36,6 +37,7 @@ func (self *PackagingTestSuite) TestDEBServer() {
builder, err := BuildDeb(spec)
assert.NoError(self.T(), err)
defer builder.Close()
goldie.Assert(self.T(), "TestDEBServer",
[]byte(builder.Debug()))
@@ -57,6 +59,7 @@ func (self *PackagingTestSuite) TestDEBServerMaster() {
builder, err := BuildDeb(spec)
assert.NoError(self.T(), err)
defer builder.Close()
goldie.Assert(self.T(), "TestDEBServerMaster",
[]byte(builder.Debug()))
@@ -79,6 +82,7 @@ func (self *PackagingTestSuite) TestDEBServerMinion() {
builder, err := BuildDeb(spec)
assert.NoError(self.T(), err)
defer builder.Close()
goldie.Assert(self.T(), "TestDEBServerMinion",
[]byte(builder.Debug()))
+3 -2
View File
@@ -243,6 +243,7 @@ func (self CreatePackagePlugin) Call(ctx context.Context,
scope.Log("ERROR:%v:Unable to create RPM: %w", self.name, err)
return
}
defer builder.Close()
filename := utils.Join(arg.DirName, package_spec.OutputFilename())
scope.Log("DEBUG:%v: writing file %v", self.name, filename)
@@ -336,7 +337,7 @@ func validateClientConfig(
// Derive client config from server config
if config_yaml == "" {
return config.GetClientConfig(config_obj), nil
return config.StripClientConfig(config_obj), nil
}
// Load and validate the client config file.
@@ -350,7 +351,7 @@ func validateClientConfig(
// Strip any unrelated fields for the client config (in case the
// user passed a server config accidentally).
return config.GetClientConfig(client_config), nil
return config.StripClientConfig(client_config), nil
}
func (self CreatePackagePlugin) Info(scope vfilter.Scope, type_map *vfilter.TypeMap) *vfilter.PluginInfo {
+5
View File
@@ -62,6 +62,10 @@ type RPMBuilder struct {
pack *rpmpack.RPM
}
func (self *RPMBuilder) Close() error {
return nil
}
func (self *RPMBuilder) AddFile(f rpmpack.RPMFile) {
switch f.Name {
case "Preun":
@@ -203,4 +207,5 @@ func BuildRPM(spec *PackageSpec) (Builder, error) {
type Builder interface {
Bytes(scope vfilter.Scope) ([]byte, error)
Debug() string
Close() error
}