Add enable scheduled query stats to fleet config (#4066)

* Add enable scheduled query stats to fleet config as well

* Add documentation

* Revert "Allow disabling scheduled query stats via app config (#4049)"

This reverts commit f98fd4d331.

* Add changes file

* Update ref

* Add missing docs
This commit is contained in:
Tomas Touceda 2022-02-09 08:20:29 -03:00 committed by GitHub
parent f855e45089
commit 11887f87f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 47 additions and 37 deletions

View File

@ -0,0 +1 @@
* Allow to disable scheduled query stats through fleet serve config

View File

@ -1 +0,0 @@
* Allow disabling scheduled query stats via app config

View File

@ -398,7 +398,6 @@ spec:
host_expiry_window: 0
host_settings:
enable_host_users: true
enable_scheduled_query_stats: false
enable_software_inventory: false
org_info:
org_logo_url: ""
@ -450,7 +449,7 @@ spec:
enable_vulnerabilities_webhook: false
host_batch_size: 0
`
expectedJson := `{"kind":"config","apiVersion":"v1","spec":{"org_info":{"org_name":"","org_logo_url":""},"server_settings":{"server_url":"","live_query_disabled":false,"enable_analytics":false,"deferred_save_host":false},"smtp_settings":{"enable_smtp":false,"configured":false,"sender_address":"","server":"","port":0,"authentication_type":"","user_name":"","password":"","enable_ssl_tls":false,"authentication_method":"","domain":"","verify_ssl_certs":false,"enable_start_tls":false},"host_expiry_settings":{"host_expiry_enabled":false,"host_expiry_window":0},"host_settings":{"enable_host_users":true,"enable_software_inventory":false,"enable_scheduled_query_stats":false},"sso_settings":{"entity_id":"","issuer_uri":"","idp_image_url":"","metadata":"","metadata_url":"","idp_name":"","enable_sso":false,"enable_sso_idp_login":false},"vulnerability_settings":{"databases_path":"/some/path"},"webhook_settings":{"host_status_webhook":{"enable_host_status_webhook":false,"destination_url":"","host_percentage":0,"days_count":0},"failing_policies_webhook":{"enable_failing_policies_webhook":false,"destination_url":"","policy_ids":null,"host_batch_size":0},"vulnerabilities_webhook":{"enable_vulnerabilities_webhook":false,"destination_url":"","host_batch_size":0},"interval":"0s"}}}
expectedJson := `{"kind":"config","apiVersion":"v1","spec":{"org_info":{"org_name":"","org_logo_url":""},"server_settings":{"server_url":"","live_query_disabled":false,"enable_analytics":false,"deferred_save_host":false},"smtp_settings":{"enable_smtp":false,"configured":false,"sender_address":"","server":"","port":0,"authentication_type":"","user_name":"","password":"","enable_ssl_tls":false,"authentication_method":"","domain":"","verify_ssl_certs":false,"enable_start_tls":false},"host_expiry_settings":{"host_expiry_enabled":false,"host_expiry_window":0},"host_settings":{"enable_host_users":true,"enable_software_inventory":false},"sso_settings":{"entity_id":"","issuer_uri":"","idp_image_url":"","metadata":"","metadata_url":"","idp_name":"","enable_sso":false,"enable_sso_idp_login":false},"vulnerability_settings":{"databases_path":"/some/path"},"webhook_settings":{"host_status_webhook":{"enable_host_status_webhook":false,"destination_url":"","host_percentage":0,"days_count":0},"failing_policies_webhook":{"enable_failing_policies_webhook":false,"destination_url":"","policy_ids":null,"host_batch_size":0},"vulnerabilities_webhook":{"enable_vulnerabilities_webhook":false,"destination_url":"","host_batch_size":0},"interval":"0s"}}}
`
assert.Equal(t, expectedYaml, runAppForTest(t, []string{"get", "config"}))
@ -468,7 +467,6 @@ spec:
host_expiry_window: 0
host_settings:
enable_host_users: true
enable_scheduled_query_stats: false
enable_software_inventory: false
license:
expiration: "0001-01-01T00:00:00Z"
@ -550,7 +548,7 @@ spec:
enable_vulnerabilities_webhook: false
host_batch_size: 0
`
expectedJson := `{"kind":"config","apiVersion":"v1","spec":{"org_info":{"org_name":"","org_logo_url":""},"server_settings":{"server_url":"","live_query_disabled":false,"enable_analytics":false,"deferred_save_host":false},"smtp_settings":{"enable_smtp":false,"configured":false,"sender_address":"","server":"","port":0,"authentication_type":"","user_name":"","password":"","enable_ssl_tls":false,"authentication_method":"","domain":"","verify_ssl_certs":false,"enable_start_tls":false},"host_expiry_settings":{"host_expiry_enabled":false,"host_expiry_window":0},"host_settings":{"enable_host_users":true,"enable_software_inventory":false,"enable_scheduled_query_stats":false},"sso_settings":{"entity_id":"","issuer_uri":"","idp_image_url":"","metadata":"","metadata_url":"","idp_name":"","enable_sso":false,"enable_sso_idp_login":false},"vulnerability_settings":{"databases_path":"/some/path"},"webhook_settings":{"host_status_webhook":{"enable_host_status_webhook":false,"destination_url":"","host_percentage":0,"days_count":0},"failing_policies_webhook":{"enable_failing_policies_webhook":false,"destination_url":"","policy_ids":null,"host_batch_size":0},"vulnerabilities_webhook":{"enable_vulnerabilities_webhook":false,"destination_url":"","host_batch_size":0},"interval":"0s"},"update_interval":{"osquery_detail":3600000000000,"osquery_policy":3600000000000},"vulnerabilities":{"databases_path":"","periodicity":0,"cpe_database_url":"","cve_feed_prefix_url":"","current_instance_checks":"","disable_data_sync":false},"license":{"tier":"free","expiration":"0001-01-01T00:00:00Z"},"logging":{"debug":true,"json":false,"result":{"plugin":"filesystem","config":{"enable_log_compression":false,"enable_log_rotation":false,"result_log_file":"/dev/null","status_log_file":"/dev/null"}},"status":{"plugin":"filesystem","config":{"enable_log_compression":false,"enable_log_rotation":false,"result_log_file":"/dev/null","status_log_file":"/dev/null"}}}}}
expectedJson := `{"kind":"config","apiVersion":"v1","spec":{"org_info":{"org_name":"","org_logo_url":""},"server_settings":{"server_url":"","live_query_disabled":false,"enable_analytics":false,"deferred_save_host":false},"smtp_settings":{"enable_smtp":false,"configured":false,"sender_address":"","server":"","port":0,"authentication_type":"","user_name":"","password":"","enable_ssl_tls":false,"authentication_method":"","domain":"","verify_ssl_certs":false,"enable_start_tls":false},"host_expiry_settings":{"host_expiry_enabled":false,"host_expiry_window":0},"host_settings":{"enable_host_users":true,"enable_software_inventory":false},"sso_settings":{"entity_id":"","issuer_uri":"","idp_image_url":"","metadata":"","metadata_url":"","idp_name":"","enable_sso":false,"enable_sso_idp_login":false},"vulnerability_settings":{"databases_path":"/some/path"},"webhook_settings":{"host_status_webhook":{"enable_host_status_webhook":false,"destination_url":"","host_percentage":0,"days_count":0},"failing_policies_webhook":{"enable_failing_policies_webhook":false,"destination_url":"","policy_ids":null,"host_batch_size":0},"vulnerabilities_webhook":{"enable_vulnerabilities_webhook":false,"destination_url":"","host_batch_size":0},"interval":"0s"},"update_interval":{"osquery_detail":3600000000000,"osquery_policy":3600000000000},"vulnerabilities":{"databases_path":"","periodicity":0,"cpe_database_url":"","cve_feed_prefix_url":"","current_instance_checks":"","disable_data_sync":false},"license":{"tier":"free","expiration":"0001-01-01T00:00:00Z"},"logging":{"debug":true,"json":false,"result":{"plugin":"filesystem","config":{"enable_log_compression":false,"enable_log_rotation":false,"result_log_file":"/dev/null","status_log_file":"/dev/null"}},"status":{"plugin":"filesystem","config":{"enable_log_compression":false,"enable_log_rotation":false,"result_log_file":"/dev/null","status_log_file":"/dev/null"}}}}}
`
assert.Equal(t, expectedYaml, runAppForTest(t, []string{"get", "config", "--include-server-config"}))

View File

@ -6,7 +6,6 @@
- [Enroll secrets](#enroll-secrets)
- [Teams](#teams)
- [Organization settings](#organization-settings)
- [Host settings](#host-settings)
Entities in Fleet, such as queries, packs, labels, agent options, and enroll secrets, can be managed with configuration files in yaml syntax.
@ -500,4 +499,3 @@ later on processed by Fleet for different functionalities.
- `host_settings.enable_host_users`: boolean value that when enabled Fleet will send the query needed to gather user data
- `host_settings.enable_software_inventory`: boolean value that when enabled Fleet will send the query needed to gather the list of software installed along with other metadata
- `host_settings.enable_scheduled_query_stats`: boolean value that when enabled Fleet will send the query needed to gather statistics about query executions in a host

View File

@ -769,6 +769,19 @@ How long invite tokens should be valid for.
invite_token_validity_period: 1d
```
##### app_enable_scheduled_query_stats
Determines whether Fleet gets scheduled query statistics from hosts or not.
- Default value: `true`
- Environment variable: `FLEET_APP_ENABLE_SCHEDULED_QUERY_STATS`
- Config file format:
```
app:
enable_scheduled_query_stats: true
```
#### License
##### license_key

View File

@ -93,6 +93,7 @@ type AuthConfig struct {
type AppConfig struct {
TokenKeySize int `yaml:"token_key_size"`
InviteTokenValidityPeriod time.Duration `yaml:"invite_token_validity_period"`
EnableScheduledQueryStats bool `yaml:"enable_scheduled_query_stats"`
}
// SessionConfig defines configs related to user sessions
@ -385,6 +386,8 @@ func (man Manager) addConfigs() {
"Duration invite tokens remain valid (i.e. 1h)")
man.addConfigInt("app.token_key_size", 24,
"Size of generated tokens")
man.addConfigBool("app.enable_scheduled_query_stats", true,
"If true (default) it gets scheduled query stats from hosts")
// Session
man.addConfigInt("session.key_size", 64,
@ -610,6 +613,7 @@ func (man Manager) LoadConfig() FleetConfig {
App: AppConfig{
TokenKeySize: man.getConfigInt("app.token_key_size"),
InviteTokenValidityPeriod: man.getConfigDuration("app.invite_token_validity_period"),
EnableScheduledQueryStats: man.getConfigBool("app.enable_scheduled_query_stats"),
},
Session: SessionConfig{
KeySize: man.getConfigInt("session.key_size"),

View File

@ -280,7 +280,6 @@ func testAppConfigDefaults(t *testing.T, ds *Datastore) {
require.Equal(t, 24*time.Hour, ac.WebhookSettings.Interval.Duration)
require.False(t, ac.WebhookSettings.HostStatusWebhook.Enable)
require.True(t, ac.HostSettings.EnableHostUsers)
require.True(t, ac.HostSettings.EnableScheduledQueryStats)
require.False(t, ac.HostSettings.EnableSoftwareInventory)
_, err = ds.writer.Exec(
@ -294,6 +293,5 @@ func testAppConfigDefaults(t *testing.T, ds *Datastore) {
require.Equal(t, 12*time.Hour, ac.WebhookSettings.Interval.Duration)
require.False(t, ac.HostSettings.EnableHostUsers)
require.True(t, ac.HostSettings.EnableScheduledQueryStats)
require.False(t, ac.HostSettings.EnableSoftwareInventory)
}

View File

@ -230,7 +230,6 @@ func (c *AppConfig) ApplyDefaultsForNewInstalls() {
func (c *AppConfig) ApplyDefaults() {
c.HostSettings.EnableHostUsers = true
c.HostSettings.EnableScheduledQueryStats = true
c.WebhookSettings.Interval.Duration = 24 * time.Hour
}
@ -256,10 +255,9 @@ type HostExpirySettings struct {
}
type HostSettings struct {
EnableHostUsers bool `json:"enable_host_users"`
EnableSoftwareInventory bool `json:"enable_software_inventory"`
EnableScheduledQueryStats bool `json:"enable_scheduled_query_stats"`
AdditionalQueries *json.RawMessage `json:"additional_queries,omitempty"`
EnableHostUsers bool `json:"enable_host_users"`
EnableSoftwareInventory bool `json:"enable_software_inventory"`
AdditionalQueries *json.RawMessage `json:"additional_queries,omitempty"`
}
type OrderDirection int

View File

@ -8,6 +8,7 @@ import (
"strings"
"time"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/go-kit/kit/log"
@ -365,6 +366,14 @@ FROM homebrew_packages;
DirectIngestFunc: directIngestSoftware,
}
var scheduledQueryStats = DetailQuery{
Query: `
SELECT *,
(SELECT value from osquery_flags where name = 'pack_delimiter') AS delimiter
FROM osquery_schedule`,
DirectIngestFunc: directIngestScheduledQueryStats,
}
var softwareLinux = DetailQuery{
Query: `
WITH cached_users AS (SELECT * FROM users)
@ -491,14 +500,6 @@ FROM python_packages;
DirectIngestFunc: directIngestSoftware,
}
var scheduledQueryStats = DetailQuery{
Query: `
SELECT *,
(SELECT value from osquery_flags where name = 'pack_delimiter') AS delimiter
FROM osquery_schedule`,
DirectIngestFunc: directIngestScheduledQueryStats,
}
var usersQuery = DetailQuery{
// Note we use the cached_groups CTE (`WITH` clause) here to suggest to SQLite that it generate
// the `groups` table only once. Without doing this, on some Windows systems (Domain Controllers)
@ -738,7 +739,7 @@ func directIngestMunkiInfo(ctx context.Context, logger log.Logger, host *fleet.H
return ds.SetOrUpdateMunkiVersion(ctx, host.ID, rows[0]["version"])
}
func GetDetailQueries(ac *fleet.AppConfig) map[string]DetailQuery {
func GetDetailQueries(ac *fleet.AppConfig, fleetConfig config.FleetConfig) map[string]DetailQuery {
generatedMap := make(map[string]DetailQuery)
for key, query := range detailQueries {
generatedMap[key] = query
@ -754,7 +755,7 @@ func GetDetailQueries(ac *fleet.AppConfig) map[string]DetailQuery {
generatedMap["users"] = usersQuery
}
if ac != nil && ac.HostSettings.EnableScheduledQueryStats {
if fleetConfig.App.EnableScheduledQueryStats {
generatedMap["scheduled_query_stats"] = scheduledQueryStats
}

View File

@ -8,6 +8,7 @@ import (
"testing"
"time"
"github.com/fleetdm/fleet/v4/server/config"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mock"
"github.com/go-kit/kit/log"
@ -19,7 +20,7 @@ func TestDetailQueryNetworkInterfaces(t *testing.T) {
var initialHost fleet.Host
host := initialHost
ingest := GetDetailQueries(nil)["network_interface"].IngestFunc
ingest := GetDetailQueries(nil, config.FleetConfig{})["network_interface"].IngestFunc
assert.NoError(t, ingest(log.NewNopLogger(), &host, nil))
assert.Equal(t, initialHost, host)
@ -110,7 +111,7 @@ func TestDetailQueryScheduledQueryStats(t *testing.T) {
return nil
}
ingest := GetDetailQueries(&fleet.AppConfig{HostSettings: fleet.HostSettings{EnableScheduledQueryStats: true}})["scheduled_query_stats"].DirectIngestFunc
ingest := GetDetailQueries(nil, config.FleetConfig{App: config.AppConfig{EnableScheduledQueryStats: true}})["scheduled_query_stats"].DirectIngestFunc
ctx := context.Background()
assert.NoError(t, ingest(ctx, log.NewNopLogger(), &host, ds, nil, false))
@ -288,7 +289,7 @@ func sortedKeysCompare(t *testing.T, m map[string]DetailQuery, expectedKeys []st
}
func TestGetDetailQueries(t *testing.T) {
queriesNoConfig := GetDetailQueries(nil)
queriesNoConfig := GetDetailQueries(nil, config.FleetConfig{})
require.Len(t, queriesNoConfig, 11)
baseQueries := []string{
"network_interface",
@ -305,11 +306,11 @@ func TestGetDetailQueries(t *testing.T) {
}
sortedKeysCompare(t, queriesNoConfig, baseQueries)
queriesWithUsers := GetDetailQueries(&fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true, EnableScheduledQueryStats: true}})
queriesWithUsers := GetDetailQueries(&fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true}}, config.FleetConfig{App: config.AppConfig{EnableScheduledQueryStats: true}})
require.Len(t, queriesWithUsers, 13)
sortedKeysCompare(t, queriesWithUsers, append(baseQueries, "users", "scheduled_query_stats"))
queriesWithUsersAndSoftware := GetDetailQueries(&fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true, EnableSoftwareInventory: true, EnableScheduledQueryStats: true}})
queriesWithUsersAndSoftware := GetDetailQueries(&fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true, EnableSoftwareInventory: true}}, config.FleetConfig{App: config.AppConfig{EnableScheduledQueryStats: true}})
require.Len(t, queriesWithUsersAndSoftware, 16)
sortedKeysCompare(t, queriesWithUsersAndSoftware,
append(baseQueries, "users", "software_macos", "software_linux", "software_windows", "scheduled_query_stats"))

View File

@ -129,7 +129,7 @@ func (svc Service) EnrollAgent(ctx context.Context, enrollSecret, hostIdentifier
}
// Save enrollment details if provided
detailQueries := osquery_utils.GetDetailQueries(appConfig)
detailQueries := osquery_utils.GetDetailQueries(appConfig, svc.config)
save := false
if r, ok := hostDetails["os_version"]; ok {
err := detailQueries["os_version"].IngestFunc(svc.logger, host, []map[string]string{r})
@ -423,7 +423,7 @@ func (svc *Service) detailQueriesForHost(ctx context.Context, host *fleet.Host)
}
queries := make(map[string]string)
detailQueries := osquery_utils.GetDetailQueries(config)
detailQueries := osquery_utils.GetDetailQueries(config, svc.config)
for name, query := range detailQueries {
if query.RunsForPlatform(host.Platform) {
queries[hostDetailQueryPrefix+name] = query.Query
@ -628,7 +628,7 @@ func (svc *Service) ingestDetailQuery(ctx context.Context, host *fleet.Host, nam
return osqueryError{message: "ingest detail query: " + err.Error()}
}
detailQueries := osquery_utils.GetDetailQueries(config)
detailQueries := osquery_utils.GetDetailQueries(config, svc.config)
query, ok := detailQueries[name]
if !ok {
return osqueryError{message: "unknown detail query " + name}
@ -744,7 +744,7 @@ func (svc *Service) directIngestDetailQuery(ctx context.Context, host *fleet.Hos
return false, osqueryError{message: "ingest detail query: " + err.Error()}
}
detailQueries := osquery_utils.GetDetailQueries(config)
detailQueries := osquery_utils.GetDetailQueries(config, svc.config)
query, ok := detailQueries[name]
if !ok {
return false, osqueryError{message: "unknown detail query " + name}

View File

@ -40,8 +40,7 @@ import (
)
// One of these queries is the disk space, only one of the two works in a platform
var expectedDetailQueries = len(osquery_utils.GetDetailQueries(
&fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true}})) - 1
var expectedDetailQueries = len(osquery_utils.GetDetailQueries(&fleet.AppConfig{HostSettings: fleet.HostSettings{EnableHostUsers: true}}, config.FleetConfig{})) - 1
func TestEnrollAgent(t *testing.T) {
ds := new(mock.Store)