From af6e13a98af492b3ab1dabce0e2064bbce3ca201 Mon Sep 17 00:00:00 2001 From: Javier Marcos Date: Fri, 8 Jan 2021 07:00:44 +0100 Subject: [PATCH] Add query packs from osctrl-cli --- cli/environment.go | 197 ++++++++++++++++++++++++++++++++++-- cli/main.go | 171 ++++++++++++++++++++++++++++++- cli/utils.go | 8 -- environments/flags.go | 2 + environments/osqueryconf.go | 188 +++++++++++++++++++++++++++++++++- 5 files changed, 544 insertions(+), 22 deletions(-) diff --git a/cli/environment.go b/cli/environment.go index 0ab7f84d..001c193f 100644 --- a/cli/environment.go +++ b/cli/environment.go @@ -319,16 +319,12 @@ func addScheduledQuery(c *cli.Context) error { fmt.Println("Interval is required") os.Exit(1) } - // Get platform - platform := c.String("platform") - // Get version - version := c.String("version") // Add new scheduled query qData := environments.ScheduleQuery{ Query: query, Interval: interval, - Platform: platform, - Version: version, + Platform: c.String("platform"), + Version: c.String("version"), } if err := envs.AddScheduleConfQuery(envName, queryName, qData); err != nil { return err @@ -337,6 +333,27 @@ func addScheduledQuery(c *cli.Context) error { return nil } +func removeScheduledQuery(c *cli.Context) error { + // Get environment name + envName := c.String("name") + if envName == "" { + fmt.Println("Environment name is required") + os.Exit(1) + } + // Get query name + queryName := c.String("query-name") + if queryName == "" { + fmt.Println("Query name is required") + os.Exit(1) + } + // Remove query + if err := envs.RemoveScheduleConfQuery(envName, queryName); err != nil { + return err + } + fmt.Printf("Query %s was removed successfully\n", queryName) + return nil +} + func addOsqueryOption(c *cli.Context) error { // Get environment name envName := c.String("name") @@ -376,3 +393,171 @@ func addOsqueryOption(c *cli.Context) error { fmt.Printf("Option %s was added successfully\n", option) return nil } + +func removeOsqueryOption(c *cli.Context) error { + // Get environment name + envName := c.String("name") + if envName == "" { + fmt.Println("Environment name is required") + os.Exit(1) + } + // Get option + option := c.String("option") + if option == "" { + fmt.Println("Option is required") + os.Exit(1) + } + // Remove osquery option + if err := envs.RemoveOptionsConf(envName, option); err != nil { + return err + } + fmt.Printf("Option %s was added successfully\n", option) + return nil +} + +func addNewPack(c *cli.Context) error { + // Get environment name + envName := c.String("name") + if envName == "" { + fmt.Println("Environment name is required") + os.Exit(1) + } + // Get pack name + pName := c.String("pack") + if pName == "" { + fmt.Println("Pack name is required") + os.Exit(1) + } + // Compose query pack + pack := environments.PackEntry{ + Platform: c.String("platform"), + Version: c.String("version"), + Shard: c.Int("shard"), + } + // Add pack to configuration + if err := envs.AddQueryPackConf(envName, pName, pack); err != nil { + return err + } + fmt.Printf("Pack %s was added successfully\n", pName) + return nil +} + +func removePack(c *cli.Context) error { + // Get environment name + envName := c.String("name") + if envName == "" { + fmt.Println("Environment name is required") + os.Exit(1) + } + // Get pack name + pName := c.String("pack") + if pName == "" { + fmt.Println("Pack name is required") + os.Exit(1) + } + // Remove pack from configuration + if err := envs.RemoveQueryPackConf(envName, pName); err != nil { + return err + } + fmt.Printf("Pack %s was added successfully\n", pName) + return nil +} + +func addLocalPack(c *cli.Context) error { + // Get environment name + envName := c.String("name") + if envName == "" { + fmt.Println("Environment name is required") + os.Exit(1) + } + // Get pack name + pName := c.String("pack") + if pName == "" { + fmt.Println("Pack name is required") + os.Exit(1) + } + // Get pack local path + pPath := c.String("pack-path") + if pPath == "" { + fmt.Println("Pack path is required") + os.Exit(1) + } + // Add pack to configuration option + if err := envs.AddQueryPackConf(envName, pName, pPath); err != nil { + return err + } + fmt.Printf("Pack %s was added successfully\n", pName) + return nil +} + +func addPackQuery(c *cli.Context) error { + // Get environment name + envName := c.String("name") + if envName == "" { + fmt.Println("Environment name is required") + os.Exit(1) + } + // Get query name + packName := c.String("pack") + if packName == "" { + fmt.Println("Pack name is required") + os.Exit(1) + } + // Get query + query := c.String("query") + if query == "" { + fmt.Println("Query is required") + os.Exit(1) + } + // Get query name + queryName := c.String("query-name") + if queryName == "" { + fmt.Println("Query name is required") + os.Exit(1) + } + // Get interval + interval := c.Int("interval") + if interval == 0 { + fmt.Println("Interval is required") + os.Exit(1) + } + // Add new scheduled query + qData := environments.ScheduleQuery{ + Query: query, + Interval: interval, + Platform: c.String("platform"), + Version: c.String("version"), + } + if err := envs.AddQueryToPackConf(envName, packName, queryName, qData); err != nil { + return err + } + fmt.Printf("Query %s was added to pack %s successfully\n", queryName, packName) + return nil +} + +func removePackQuery(c *cli.Context) error { + // Get environment name + envName := c.String("name") + if envName == "" { + fmt.Println("Environment name is required") + os.Exit(1) + } + // Get query name + packName := c.String("pack") + if packName == "" { + fmt.Println("Pack name is required") + os.Exit(1) + } + // Get query name + queryName := c.String("query-name") + if queryName == "" { + fmt.Println("Query name is required") + os.Exit(1) + } + // Remove query + if err := envs.RemoveQueryFromPackConf(envName, packName, queryName); err != nil { + return err + } + fmt.Printf("Query %s was removed from pack %s successfully\n", queryName, packName) + return nil +} diff --git a/cli/main.go b/cli/main.go index caf0049e..32a2dcb9 100644 --- a/cli/main.go +++ b/cli/main.go @@ -240,19 +240,36 @@ func init() { cli.StringFlag{ Name: "platform, p", Value: "", - Usage: "Query to be added to the schedule", + Usage: "Restrict this query to a given platform", }, cli.StringFlag{ Name: "version, v", Value: "", - Usage: "Query to be added to the schedule", + Usage: "Only run on osquery versions greater than or equal-to this version", }, }, Action: cliWrapper(addScheduledQuery), }, + { + Name: "remove-scheduled-query", + Usage: "Remove query from the osquery schedule for an environment", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name, n", + Value: "", + Usage: "Environment to be updated", + }, + cli.StringFlag{ + Name: "query-name, q", + Value: "", + Usage: "Query to be removed from the schedule", + }, + }, + Action: cliWrapper(removeScheduledQuery), + }, { Name: "add-osquery-option", - Usage: "Add a new option for the osquery configuration", + Usage: "Add or change an osquery option to the configuration", Flags: []cli.Flag{ cli.StringFlag{ Name: "name, n", @@ -284,6 +301,154 @@ func init() { }, Action: cliWrapper(addOsqueryOption), }, + { + Name: "remove-osquery-option", + Usage: "Remove an option for the osquery configuration", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name, n", + Value: "", + Usage: "Environment to be updated", + }, + cli.StringFlag{ + Name: "option, o", + Value: "", + Usage: "Option name to be added", + }, + }, + Action: cliWrapper(removeOsqueryOption), + }, + { + Name: "add-new-pack", + Usage: "Add a new query pack to the osquery configuration", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name, n", + Value: "", + Usage: "Environment to be updated", + }, + cli.StringFlag{ + Name: "pack, p", + Value: "", + Usage: "Pack name to be added", + }, + cli.StringFlag{ + Name: "platform, P", + Usage: "Restrict this pack to a given platform", + }, + cli.StringFlag{ + Name: "version, v", + Usage: "Only run on osquery versions greater than or equal-to this version", + }, + cli.IntFlag{ + Name: "shard, s", + Usage: "Restrict this query to a percentage (1-100) of target hosts", + }, + }, + Action: cliWrapper(addNewPack), + }, + { + Name: "add-local-pack", + Usage: "Add a new local query pack to the osquery configuration", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name, n", + Value: "", + Usage: "Environment to be updated", + }, + cli.StringFlag{ + Name: "pack, p", + Value: "", + Usage: "Pack name to be added", + }, + cli.StringFlag{ + Name: "pack-path, P", + Usage: "Local full path to load the query pack within osquery", + }, + }, + Action: cliWrapper(addLocalPack), + }, + { + Name: "remove-pack", + Usage: "Remove query pack from the osquery configuration", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name, n", + Value: "", + Usage: "Environment to be updated", + }, + cli.StringFlag{ + Name: "pack, p", + Value: "", + Usage: "Pack name to be removed", + }, + }, + Action: cliWrapper(removePack), + }, + { + Name: "add-query-to-pack", + Usage: "Add a new query to the given query pack", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name, n", + Value: "", + Usage: "Environment to be updated", + }, + cli.StringFlag{ + Name: "pack, p", + Value: "", + Usage: "Environment to be updated", + }, + cli.StringFlag{ + Name: "query, q", + Value: "", + Usage: "Query to be added to the pack", + }, + cli.StringFlag{ + Name: "query-name, Q", + Value: "", + Usage: "Query name to be added to the pack", + }, + cli.IntFlag{ + Name: "interval, i", + Value: 0, + Usage: "Query interval in seconds", + }, + cli.StringFlag{ + Name: "platform, P", + Value: "", + Usage: "Restrict this query to a given platform", + }, + cli.StringFlag{ + Name: "version, v", + Value: "", + Usage: "Only run on osquery versions greater than or equal-to this version", + }, + }, + Action: cliWrapper(addPackQuery), + }, + { + Name: "remove-query-from-pack", + Usage: "Remove query from the given query pack", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name, n", + Value: "", + Usage: "Environment to be updated", + }, + cli.StringFlag{ + Name: "pack, p", + Value: "", + Usage: "Pack name to be updated", + }, + cli.StringFlag{ + Name: "query-name, q", + Value: "", + Usage: "Query name to be removed", + }, + }, + Action: cliWrapper(removePackQuery), + }, { Name: "delete", Aliases: []string{"d"}, diff --git a/cli/utils.go b/cli/utils.go index 49214e5d..31ac2c82 100644 --- a/cli/utils.go +++ b/cli/utils.go @@ -4,14 +4,6 @@ import ( "unicode/utf8" ) -// Constants for seconds -const ( - oneMinute = 60 - oneHour = 3600 - oneDay = 86400 - fifteenDays = 1296000 -) - // Helper to truncate a string func truncateString(s string, n int) string { if len(s) <= n { diff --git a/environments/flags.go b/environments/flags.go index 3d0d6080..690c3d7f 100644 --- a/environments/flags.go +++ b/environments/flags.go @@ -40,7 +40,9 @@ const ( ) const ( + // EmptyFlagSecret to use as placeholder for the secret file EmptyFlagSecret string = "__SECRET_FILE__" + // EmptyFlagCert to use as placeholder for the certificate file EmptyFlagCert string = "__CERT_FILE__" ) diff --git a/environments/osqueryconf.go b/environments/osqueryconf.go index 3ec45c56..9ac0bbf5 100644 --- a/environments/osqueryconf.go +++ b/environments/osqueryconf.go @@ -36,7 +36,7 @@ type ScheduleQuery struct { } // PacksConf to hold all the packs in the configuration -// https://osquery.readthedocs.io/en/stable/deployment/configuration/#packs +// https://osquery.readthedocs.io/en/stable/deployment`/configuration/#packs type PacksConf map[string]interface{} // PackEntry to hold the struct for a single pack @@ -239,11 +239,11 @@ func (environment *Environment) GenEmptyConfiguration(indent bool) string { return str } -// AddOptionsConf to add a new query to the osquery schedule +// AddOptionsConf to add an osquery option to the configuration func (environment *Environment) AddOptionsConf(name, option string, value interface{}) error { env, err := environment.Get(name) if err != nil { - return fmt.Errorf("error structuring environment %v", err) + return fmt.Errorf("error getting environment %v", err) } // Parse options into struct _options, err := environment.GenStructOptions([]byte(env.Options)) @@ -268,13 +268,42 @@ func (environment *Environment) AddOptionsConf(name, option string, value interf return nil } +// RemoveOptionsConf to remove an osquery option from the configuration +func (environment *Environment) RemoveOptionsConf(name, option string) error { + env, err := environment.Get(name) + if err != nil { + return fmt.Errorf("error getting environment %v", err) + } + // Parse options into struct + _options, err := environment.GenStructOptions([]byte(env.Options)) + if err != nil { + return fmt.Errorf("error structuring options %v", err) + } + // Remove option + delete(_options, option) + // Generate serialized indented options + indentedOptions, err := environment.GenSerializedConf(_options, true) + if err != nil { + return fmt.Errorf("error serializing options %v", err) + } + // Update options in environment + if err := environment.UpdateOptions(name, indentedOptions); err != nil { + return fmt.Errorf("error updating options %v", err) + } + // Refresh all configuration + if err := environment.RefreshConfiguration(name); err != nil { + return fmt.Errorf("error refreshing configuration %v", err) + } + return nil +} + // AddScheduleConfQuery to add a new query to the osquery schedule func (environment *Environment) AddScheduleConfQuery(name, qName string, query ScheduleQuery) error { env, err := environment.Get(name) if err != nil { - return fmt.Errorf("error structuring environment %v", err) + return fmt.Errorf("error getting environment %v", err) } - // Parse options into struct + // Parse schedule into struct _schedule, err := environment.GenStructSchedule([]byte(env.Schedule)) if err != nil { return fmt.Errorf("error structuring schedule %v", err) @@ -296,3 +325,152 @@ func (environment *Environment) AddScheduleConfQuery(name, qName string, query S } return nil } + +// RemoveScheduleConfQuery to remove a query from the osquery schedule +func (environment *Environment) RemoveScheduleConfQuery(name, qName string) error { + env, err := environment.Get(name) + if err != nil { + return fmt.Errorf("error getting environment %v", err) + } + // Parse schedule into struct + _schedule, err := environment.GenStructSchedule([]byte(env.Schedule)) + if err != nil { + return fmt.Errorf("error structuring schedule %v", err) + } + // Remove query + delete(_schedule, qName) + // Generate serialized indented schedule + indentedSchedule, err := environment.GenSerializedConf(_schedule, true) + if err != nil { + return fmt.Errorf("error serializing schedule %v", err) + } + // Update schedule in environment + if err := environment.UpdateSchedule(name, indentedSchedule); err != nil { + return fmt.Errorf("error updating schedule %v", err) + } + // Refresh all configuration + if err := environment.RefreshConfiguration(name); err != nil { + return fmt.Errorf("error refreshing configuration %v", err) + } + return nil +} + +// AddQueryPackConf to add a new query pack to the osquery configuration +func (environment *Environment) AddQueryPackConf(name, pName string, pack interface{}) error { + env, err := environment.Get(name) + if err != nil { + return fmt.Errorf("error getting environment %v", err) + } + // Parse packs into struct + _packs, err := environment.GenStructPacks([]byte(env.Packs)) + if err != nil { + return fmt.Errorf("error structuring packs %v", err) + } + // Add new local pack + _packs[pName] = pack + // Generate serialized indented packs + indentedPacks, err := environment.GenSerializedConf(_packs, true) + if err != nil { + return fmt.Errorf("error serializing packs %v", err) + } + // Update schedule in environment + if err := environment.UpdatePacks(name, indentedPacks); err != nil { + return fmt.Errorf("error updating packs %v", err) + } + // Refresh all configuration + if err := environment.RefreshConfiguration(name); err != nil { + return fmt.Errorf("error refreshing configuration %v", err) + } + return nil +} + +// RemoveQueryPackConf to add a new query pack to the osquery configuration +func (environment *Environment) RemoveQueryPackConf(name, pName string) error { + env, err := environment.Get(name) + if err != nil { + return fmt.Errorf("error getting environment %v", err) + } + // Parse packs into struct + _packs, err := environment.GenStructPacks([]byte(env.Packs)) + if err != nil { + return fmt.Errorf("error structuring packs %v", err) + } + // Remove pack + delete(_packs, pName) + // Generate serialized indented packs + indentedPacks, err := environment.GenSerializedConf(_packs, true) + if err != nil { + return fmt.Errorf("error serializing packs %v", err) + } + // Update schedule in environment + if err := environment.UpdatePacks(name, indentedPacks); err != nil { + return fmt.Errorf("error updating packs %v", err) + } + // Refresh all configuration + if err := environment.RefreshConfiguration(name); err != nil { + return fmt.Errorf("error refreshing configuration %v", err) + } + return nil +} + +// AddQueryToPackConf to add a new query to an existing pack in the osquery configuration +func (environment *Environment) AddQueryToPackConf(name, pName, qName string, query ScheduleQuery) error { + env, err := environment.Get(name) + if err != nil { + return fmt.Errorf("error getting environment %v", err) + } + // Parse packs into struct + _packs, err := environment.GenStructPacks([]byte(env.Packs)) + if err != nil { + return fmt.Errorf("error structuring packs %v", err) + } + // Get pack to add the query + pack := _packs[pName].(PackEntry) + pack.Queries[qName] = query + _packs[pName] = pack + // Generate serialized indented packs + indentedPacks, err := environment.GenSerializedConf(_packs, true) + if err != nil { + return fmt.Errorf("error serializing packs %v", err) + } + // Update schedule in environment + if err := environment.UpdatePacks(name, indentedPacks); err != nil { + return fmt.Errorf("error updating packs %v", err) + } + // Refresh all configuration + if err := environment.RefreshConfiguration(name); err != nil { + return fmt.Errorf("error refreshing configuration %v", err) + } + return nil +} + +// RemoveQueryFromPackConf to remove a query from an existing query pack in the osquery configuration +func (environment *Environment) RemoveQueryFromPackConf(name, pName, qName string) error { + env, err := environment.Get(name) + if err != nil { + return fmt.Errorf("error getting environment %v", err) + } + // Parse packs into struct + _packs, err := environment.GenStructPacks([]byte(env.Packs)) + if err != nil { + return fmt.Errorf("error structuring packs %v", err) + } + // Get pack to remove the query + pack := _packs[pName].(PackEntry) + delete(pack.Queries, qName) + _packs[pName] = pack + // Generate serialized indented packs + indentedPacks, err := environment.GenSerializedConf(_packs, true) + if err != nil { + return fmt.Errorf("error serializing packs %v", err) + } + // Update schedule in environment + if err := environment.UpdatePacks(name, indentedPacks); err != nil { + return fmt.Errorf("error updating packs %v", err) + } + // Refresh all configuration + if err := environment.RefreshConfiguration(name); err != nil { + return fmt.Errorf("error refreshing configuration %v", err) + } + return nil +}