From d28d2cac2831e9fe1ba5122b817ee663855679c7 Mon Sep 17 00:00:00 2001 From: Ben Coverston Date: Mon, 26 Feb 2018 13:54:13 -0700 Subject: [PATCH] Add FileAccesses to FIM Configuration (#1717) - Close #1708 - Fix FIM interval not being stored --- server/datastore/mysql/app_configs.go | 12 +++++++--- ...31234303_AddColumnFimFileAccessToConfig.go | 24 +++++++++++++++++++ server/kolide/app.go | 2 ++ server/kolide/file_integrity_monitoring.go | 2 ++ server/service/service_fim.go | 20 ++++++++++++++++ server/service/service_fim_test.go | 20 ++++++++++++---- 6 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 server/datastore/mysql/migrations/tables/20170831234303_AddColumnFimFileAccessToConfig.go diff --git a/server/datastore/mysql/app_configs.go b/server/datastore/mysql/app_configs.go index fbc170b0f1..1e159f5aed 100644 --- a/server/datastore/mysql/app_configs.go +++ b/server/datastore/mysql/app_configs.go @@ -52,9 +52,11 @@ func (d *Datastore) SaveAppConfig(info *kolide.AppConfig) error { metadata, metadata_url, idp_name, - enable_sso + enable_sso, + fim_interval, + fim_file_accesses ) - VALUES( 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) + VALUES( 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) ON DUPLICATE KEY UPDATE org_name = VALUES(org_name), org_logo_url = VALUES(org_logo_url), @@ -78,7 +80,9 @@ func (d *Datastore) SaveAppConfig(info *kolide.AppConfig) error { metadata = VALUES(metadata), metadata_url = VALUES(metadata_url), idp_name = VALUES(idp_name), - enable_sso = VALUES(enable_sso) + enable_sso = VALUES(enable_sso), + fim_interval = VALUES(fim_interval), + fim_file_accesses = VALUES(fim_file_accesses) ` _, err := d.db.Exec(insertStatement, @@ -105,6 +109,8 @@ func (d *Datastore) SaveAppConfig(info *kolide.AppConfig) error { info.MetadataURL, info.IDPName, info.EnableSSO, + info.FIMInterval, + info.FIMFileAccesses, ) return err diff --git a/server/datastore/mysql/migrations/tables/20170831234303_AddColumnFimFileAccessToConfig.go b/server/datastore/mysql/migrations/tables/20170831234303_AddColumnFimFileAccessToConfig.go new file mode 100644 index 0000000000..6e7e89c426 --- /dev/null +++ b/server/datastore/mysql/migrations/tables/20170831234303_AddColumnFimFileAccessToConfig.go @@ -0,0 +1,24 @@ +package tables + +import ( + "database/sql" +) + +func init() { + MigrationClient.AddMigration(Up20170831234303, Down20170831234303) +} + +func Up20170831234303(tx *sql.Tx) error { + _, err := tx.Exec( + "ALTER TABLE `app_configs` " + + "ADD COLUMN `fim_file_accesses` VARCHAR(255) NOT NULL DEFAULT '';", + ) + return err +} + +func Down20170831234303(tx *sql.Tx) error { + _, err := tx.Exec( + "ALTER TABLE `app_configs` DROP COLUMN `fim_file_accesses` ;", + ) + return err +} diff --git a/server/kolide/app.go b/server/kolide/app.go index 808fa7bf15..82776096a3 100644 --- a/server/kolide/app.go +++ b/server/kolide/app.go @@ -129,6 +129,8 @@ type AppConfig struct { EnableSSO bool `db:"enable_sso"` // FIMInterval defines the interval when file integrity checks will occur FIMInterval int `db:"fim_interval"` + // FIMFileAccess defines the FIMSections which will be monitored for file access events as a JSON formatted array + FIMFileAccesses string `db:"fim_file_accesses"` } // ModifyAppConfigRequest contains application configuration information diff --git a/server/kolide/file_integrity_monitoring.go b/server/kolide/file_integrity_monitoring.go index 29356a3ae1..e910fdcb35 100644 --- a/server/kolide/file_integrity_monitoring.go +++ b/server/kolide/file_integrity_monitoring.go @@ -40,4 +40,6 @@ type FIMConfig struct { // name, the array of strings contains paths to be monitored. // See https://osquery.readthedocs.io/en/stable/deployment/file-integrity-monitoring/ FilePaths FIMSections `json:"file_paths,omitempty"` + // FileAccesses defines those name groups of FIMSections which will be monitored for file accesses + FileAccesses []string `json:"file_accesses,omitempty"` } diff --git a/server/service/service_fim.go b/server/service/service_fim.go index 4c764ee22e..1e5b357ec8 100644 --- a/server/service/service_fim.go +++ b/server/service/service_fim.go @@ -5,6 +5,7 @@ import ( "github.com/kolide/fleet/server/kolide" "github.com/pkg/errors" + "encoding/json" ) func (svc service) GetFIM(ctx context.Context) (*kolide.FIMConfig, error) { @@ -16,9 +17,18 @@ func (svc service) GetFIM(ctx context.Context) (*kolide.FIMConfig, error) { if err != nil { return nil, errors.Wrap(err, "getting fim paths") } + + var arr []string + if len(config.FIMFileAccesses) > 0 { + if err = json.Unmarshal([]byte(config.FIMFileAccesses), &arr); err != nil { + return nil, errors.Wrap(err, "Error reading fim section, fileaccesses must be formatted as an array [\"cassandra\",\"etc\",\"homes\"]") + } + } + result := &kolide.FIMConfig{ Interval: uint(config.FIMInterval), FilePaths: paths, + FileAccesses: arr, } return result, nil } @@ -32,7 +42,17 @@ func (svc service) ModifyFIM(ctx context.Context, fim kolide.FIMConfig) error { if err != nil { return errors.Wrap(err, "updating fim") } + config.FIMInterval = int(fim.Interval) + + if len(fim.FileAccesses) > 0 { + fileAccesses, err := json.Marshal(fim.FileAccesses) + if err != nil { + return errors.Wrap(err, "Error creating fim section, fileaccesses must be formatted as an array [\"cassandra\",\"etc\",\"homes\"]") + } + config.FIMFileAccesses = string(fileAccesses) + } + for sectionName, paths := range fim.FilePaths { section := kolide.FIMSection{ SectionName: sectionName, diff --git a/server/service/service_fim_test.go b/server/service/service_fim_test.go index a2d2d97958..5cb3e530cb 100644 --- a/server/service/service_fim_test.go +++ b/server/service/service_fim_test.go @@ -11,11 +11,16 @@ import ( ) func TestGetFIMService(t *testing.T) { + fileAccessesString := "[\"etc\", \"home\", \"cassandra\"]" + fileAccessStringValue := []string{"etc", "home", "cassandra"} + fimIntervalTestValue := 500 //300 is the default value + ds := &mock.Store{ AppConfigStore: mock.AppConfigStore{ AppConfigFunc: func() (*kolide.AppConfig, error) { config := &kolide.AppConfig{ - FIMInterval: 300, + FIMInterval: fimIntervalTestValue, + FIMFileAccesses: fileAccessesString, } return config, nil }, @@ -38,18 +43,24 @@ func TestGetFIMService(t *testing.T) { resp, err := svc.GetFIM(context.Background()) require.Nil(t, err) require.NotNil(t, resp) - assert.Equal(t, resp.Interval, uint(300)) + assert.Equal(t, resp.Interval, uint(fimIntervalTestValue)) + assert.Equal(t, resp.FileAccesses, fileAccessStringValue) paths, ok := resp.FilePaths["etc"] require.True(t, ok) assert.Len(t, paths, 2) } func TestUpdateFIM(t *testing.T) { + fileAccessesString := "[\"etc\", \"home\", \"cassandra\"]" + fileAccessStringValue := []string{"etc", "home", "cassandra"} + fimIntervalTestValue := 500 //300 is the default value + ds := &mock.Store{ AppConfigStore: mock.AppConfigStore{ AppConfigFunc: func() (*kolide.AppConfig, error) { config := &kolide.AppConfig{ - FIMInterval: 300, + FIMInterval: fimIntervalTestValue, + FIMFileAccesses: fileAccessesString, } return config, nil }, @@ -71,7 +82,8 @@ func TestUpdateFIM(t *testing.T) { ds: ds, } fim := kolide.FIMConfig{ - Interval: uint(300), + Interval: uint(fimIntervalTestValue), + FileAccesses: fileAccessStringValue, FilePaths: kolide.FIMSections{ "etc": []string{ "/etc/config/%%",