Documentation
¶
Overview ¶
Package cwhub is responsible for providing the state of the local hub to the security engine and cscli command. Installation, upgrade and removal of items or data files has been moved to pkg/hubops.
Definitions ¶
- A hub ITEM is a file that defines a parser, a scenario, a collection... in the case of a collection, it has dependencies on other hub items.
- The hub INDEX is a JSON file that contains a tree of available hub items.
- A REMOTE HUB is an HTTP server that hosts the hub index and the hub items. It can serve from several branches, usually linked to the CrowdSec version.
- A LOCAL HUB is a directory that contains a copy of the hub index and the downloaded hub items.
Once downloaded, hub items can be installed by linking to them from the configuration directory. If an item is present in the configuration directory but it's not a link to the local hub, it is considered as a LOCAL ITEM and won't be removed or upgraded.
Directory Structure ¶
A typical directory layout is the following:
For the local hub (HubDir = /etc/crowdsec/hub):
- /etc/crowdsec/hub/.index.json
- /etc/crowdsec/hub/parsers/{stage}/{author}/{parser-name}.yaml
- /etc/crowdsec/hub/scenarios/{author}/{scenario-name}.yaml
For the configuration directory (InstallDir = /etc/crowdsec):
- /etc/crowdsec/parsers/{stage}/{parser-name.yaml} -> /etc/crowdsec/hub/parsers/{stage}/{author}/{parser-name}.yaml
- /etc/crowdsec/scenarios/{scenario-name.yaml} -> /etc/crowdsec/hub/scenarios/{author}/{scenario-name}.yaml
- /etc/crowdsec/scenarios/local-scenario.yaml
Note that installed items are not grouped by author, this may change in the future if we want to support items with the same name from different authors.
Only parsers and postoverflows have the concept of stage.
Additionally, an item can reference a DATA SET that is installed in a different location than the item itself. These files are stored in the data directory (InstallDataDir = /var/lib/crowdsec/data).
- /var/lib/crowdsec/data/http_path_traversal.txt
- /var/lib/crowdsec/data/jira_cve_2021-26086.txt
- /var/lib/crowdsec/data/log4j2_cve_2021_44228.txt
- /var/lib/crowdsec/data/sensitive_data.txt
Using the package ¶
The main entry point is the Hub struct. You can create a new instance with NewHub(). This constructor takes three parameters, but only the LOCAL HUB configuration is required:
import ( "fmt" "github.com/crowdsecurity/crowdsec/pkg/csconfig" "github.com/crowdsecurity/crowdsec/pkg/cwhub" ) localHub := csconfig.LocalHubCfg{ HubIndexFile: "/etc/crowdsec/hub/.index.json", HubDir: "/etc/crowdsec/hub", InstallDir: "/etc/crowdsec", InstallDataDir: "/var/lib/crowdsec/data", } hub, err := cwhub.NewHub(localHub, nil, logger) if err != nil { return fmt.Errorf("unable to initialize hub: %w", err) }
If the logger is nil, the item-by-item messages will be discarded, including warnings. After configuring the hub, you must sync its state with items on disk.
err := hub.Load() if err != nil { return fmt.Errorf("unable to load hub: %w", err) }
Now you can use the hub object to access the existing items:
// list all the parsers for _, parser := range hub.GetItemsByType(cwhub.PARSERS, false) { fmt.Printf("parser: %s\n", parser.Name) } // retrieve a specific collection coll := hub.GetItem(cwhub.COLLECTIONS, "crowdsecurity/linux") if coll == nil { return fmt.Errorf("collection not found") }
Some commands require an object to provide the hub index, or contents:
indexProvider := cwhub.Downloader{ URLTemplate: "https://cdn-hub.crowdsec.net/crowdsecurity/%s/%s", Branch: "master", }
The URLTemplate is a string that will be used to build the URL of the remote hub. It must contain two placeholders: the branch and the file path (it will be an index or an item).
Before calling hub.Load(), you can update the index file by calling the Update() method:
err := hub.Update(context.Background(), indexProvider) if err != nil { return fmt.Errorf("unable to update hub index: %w", err) }
Note that the command will fail if the hub has already been synced. If you want to do it (ex. after a configuration change the application is notified with SIGHUP) you have to instantiate a new hub object and dispose of the old one.
Index ¶
- Constants
- Variables
- func SafePath(dir, filePath string) (string, error)
- type ContentProvider
- type Dependencies
- type Downloader
- type Hub
- func (h *Hub) GetDataDir() string
- func (h *Hub) GetInstalledByType(itemType string, sorted bool) []*Item
- func (h *Hub) GetInstalledListForAPI() []string
- func (h *Hub) GetItem(itemType string, itemName string) *Item
- func (h *Hub) GetItemByPath(itemPath string) *Item
- func (h *Hub) GetItemFQ(itemFQName string) (*Item, error)
- func (h *Hub) GetItemMap(itemType string) map[string]*Item
- func (h *Hub) GetItemsByType(itemType string, sorted bool) []*Item
- func (h *Hub) ItemStats() []string
- func (h *Hub) Load() error
- func (h *Hub) Update(ctx context.Context, indexProvider IndexProvider, withContent bool) error
- type HubItems
- type IndexProvider
- type Item
- func (i *Item) Ancestors() []*Item
- func (i *Item) CurrentDependencies() Dependencies
- func (i *Item) DownloadPath() (string, error)
- func (i *Item) FQName() string
- func (i *Item) FetchContentTo(ctx context.Context, contentProvider ContentProvider, destPath string) (bool, string, error)
- func (i *Item) HasSubItems() bool
- func (i *Item) InstallPath() (string, error)
- func (i *Item) LatestDependencies() Dependencies
- func (i Item) MarshalJSON() ([]byte, error)
- func (i Item) MarshalYAML() (interface{}, error)
- func (i *Item) SafeToRemoveDeps() ([]*Item, error)
- type ItemState
- type ItemVersion
- type NotFoundError
Constants ¶
const ( // managed item types. COLLECTIONS = "collections" PARSERS = "parsers" POSTOVERFLOWS = "postoverflows" SCENARIOS = "scenarios" CONTEXTS = "contexts" APPSEC_CONFIGS = "appsec-configs" APPSEC_RULES = "appsec-rules" )
Variables ¶
var ErrSkipPath = errors.New("sentinel")
A sentinel to skip regular files because "nil, nil" is ambiguous. Returning SkipDir with files would skip the rest of the directory.
var ErrUpdateAfterSync = errors.New("cannot update hub index after load/sync")
var HubClient = &http.Client{ Timeout: 120 * time.Second, Transport: &hubTransport{http.DefaultTransport}, }
HubClient is the HTTP client used to communicate with the CrowdSec Hub.
var ItemTypes = []string{PARSERS, POSTOVERFLOWS, SCENARIOS, CONTEXTS, APPSEC_CONFIGS, APPSEC_RULES, COLLECTIONS}
The order is important, as it is used to range over sub-items in collections.
Functions ¶
Types ¶
type ContentProvider ¶ added in v1.6.5
type ContentProvider interface {
FetchContent(ctx context.Context, remotePath, destPath, wantHash string, logger *logrus.Logger) (bool, string, error)
}
ContentProvider retrieves and writes the YAML files with the item content.
type Dependencies ¶ added in v1.6.5
type Dependencies struct { Parsers []string `json:"parsers,omitempty" yaml:"parsers,omitempty"` PostOverflows []string `json:"postoverflows,omitempty" yaml:"postoverflows,omitempty"` Scenarios []string `json:"scenarios,omitempty" yaml:"scenarios,omitempty"` Collections []string `json:"collections,omitempty" yaml:"collections,omitempty"` Contexts []string `json:"contexts,omitempty" yaml:"contexts,omitempty"` AppsecConfigs []string `json:"appsec-configs,omitempty" yaml:"appsec-configs,omitempty"` AppsecRules []string `json:"appsec-rules,omitempty" yaml:"appsec-rules,omitempty"` }
type Downloader ¶ added in v1.6.5
Downloader is used to retrieve index and items from a remote hub, with cache control.
func (*Downloader) FetchContent ¶ added in v1.6.5
func (d *Downloader) FetchContent(ctx context.Context, remotePath, destPath, wantHash string, logger *logrus.Logger) (bool, string, error)
FetchContent downloads the content to the specified path, through a temporary file to avoid partial downloads. If the hash does not match, it will not overwrite and log a warning.
func (*Downloader) FetchIndex ¶ added in v1.6.5
func (d *Downloader) FetchIndex(ctx context.Context, destPath string, withContent bool, logger *logrus.Logger) (bool, error)
FetchIndex downloads the index from the hub and writes it to the filesystem. It uses a temporary file to avoid partial downloads, and won't overwrite the original if it has not changed.
type Hub ¶ added in v1.6.0
type Hub struct { Warnings []string // Warnings encountered during sync // contains filtered or unexported fields }
Hub is the main structure for the package.
func NewHub ¶ added in v1.6.0
NewHub returns a new Hub instance with local and (optionally) remote configuration. The hub is not synced automatically. Load() must be called to read the index, sync the local state, and check for unmanaged items.
func (*Hub) GetDataDir ¶ added in v1.6.0
GetDataDir returns the data directory, where data sets are installed.
func (*Hub) GetInstalledByType ¶ added in v1.6.3
GetInstalledByType returns a slice of all the installed items of a given type, optionally sorted by case-insensitive name. A non-existent type will silently return an empty slice.
func (*Hub) GetInstalledListForAPI ¶ added in v1.6.3
GetInstalledListForAPI returns a slice of names of all the installed scenarios and appsec-rules. The returned list is sorted by type (scenarios first) and case-insensitive name.
func (*Hub) GetItem ¶ added in v1.6.0
GetItem returns an item from hub based on its type and full name (author/name).
func (*Hub) GetItemByPath ¶ added in v1.6.0
GetItemByPath returns an item from hub based on its (absolute) local path.
func (*Hub) GetItemFQ ¶ added in v1.6.0
GetItemFQ returns an item from hub based on its type and name (type:author/name).
func (*Hub) GetItemMap ¶ added in v1.6.0
GetItemMap returns the map of items for a given type.
func (*Hub) GetItemsByType ¶ added in v1.6.2
GetItemsByType returns a slice of all the items of a given type, installed or not, optionally sorted by case-insensitive name. A non-existent type will silently return an empty slice.
func (*Hub) ItemStats ¶ added in v1.6.0
ItemStats returns total counts of the hub items, including local and tainted.
type IndexProvider ¶ added in v1.6.5
type IndexProvider interface {
FetchIndex(ctx context.Context, indexFile string, withContent bool, logger *logrus.Logger) (bool, error)
}
IndexProvider retrieves and writes .index.json
type Item ¶
type Item struct { State ItemState `json:"-" yaml:"-"` // local state, not stored in the index Type string `json:"type,omitempty" yaml:"type,omitempty"` Stage string `json:"stage,omitempty" yaml:"stage,omitempty"` // Stage for parser|postoverflow: s00-raw/s01-... Name string `json:"name,omitempty" yaml:"name,omitempty"` // usually "author/name" FileName string `json:"file_name,omitempty" yaml:"file_name,omitempty"` // eg. apache2-logs.yaml Description string `json:"description,omitempty" yaml:"description,omitempty"` Content string `json:"content,omitempty" yaml:"-"` References []string `json:"references,omitempty" yaml:"references,omitempty"` // NOTE: RemotePath could be derived from the other fields RemotePath string `json:"path,omitempty" yaml:"path,omitempty"` // path relative to the base URL eg. /parsers/stage/author/file.yaml Version string `json:"version,omitempty" yaml:"version,omitempty"` // the last available version Versions map[string]ItemVersion `json:"versions,omitempty" yaml:"-"` // all the known versions // The index contains the dependencies of the "latest" version (collections only) Dependencies // contains filtered or unexported fields }
Item is created from an index file and enriched with local info.
func (*Item) Ancestors ¶ added in v1.6.0
Ancestors returns a slice of items (typically collections) that have this item as a direct or indirect dependency.
func (*Item) CurrentDependencies ¶ added in v1.6.5
func (i *Item) CurrentDependencies() Dependencies
CurrentSubItems returns a slice of sub-items of the installed version, excluding the ones that were not found. The list comes from the content file if parseable, otherwise from the index (same as LatestDependencies).
func (*Item) DownloadPath ¶ added in v1.6.5
DownloadPath returns the location of the actual config file in the hub (eg. /etc/crowdsec/hub/collections/author/xyz.yaml). Raises an error if the path goes outside of the hub dir.
func (*Item) FQName ¶ added in v1.6.0
FQName returns the fully qualified name of the item (ie. parsers:crowdsecurity/apache2-logs).
func (*Item) FetchContentTo ¶ added in v1.6.2
func (i *Item) FetchContentTo(ctx context.Context, contentProvider ContentProvider, destPath string) (bool, string, error)
FetchContentTo writes the last version of the item's YAML file to the specified path. If the file is embedded in the index file, it will be written directly without downloads. Returns whether the file was downloaded (to inform if the security engine needs reloading) and the remote url for feedback purposes.
func (*Item) HasSubItems ¶ added in v1.6.0
HasSubItems returns true if items of this type can have sub-items. Currently only collections.
func (*Item) InstallPath ¶ added in v1.6.5
InstallPath returns the location of the symlink to the item in the hub, or the path of the item itself if it's local (eg. /etc/crowdsec/collections/xyz.yaml). Raises an error if the path goes outside of the install dir.
func (*Item) LatestDependencies ¶ added in v1.6.5
func (i *Item) LatestDependencies() Dependencies
LatestDependencies returns a slice of sub-items of the "latest" available version of the item, as opposed to the version that is actually installed. The information comes from the index.
func (Item) MarshalJSON ¶ added in v1.6.0
MarshalJSON is used to prepare the output for "cscli ... inspect -o json". It must not use a pointer receiver.
func (Item) MarshalYAML ¶ added in v1.6.0
MarshalYAML is used to prepare the output for "cscli ... inspect -o raw". It must not use a pointer receiver.
func (*Item) SafeToRemoveDeps ¶ added in v1.6.5
SafeToRemoveDeps returns a slice of dependencies that can be safely removed when this item is removed. The returned slice can contain items that are not installed, or not downloaded.
type ItemState ¶ added in v1.6.0
type ItemState struct { LocalPath string `json:"local_path,omitempty" yaml:"local_path,omitempty"` LocalVersion string `json:"local_version,omitempty" yaml:"local_version,omitempty"` LocalHash string `json:"local_hash,omitempty" yaml:"local_hash,omitempty"` Installed bool `json:"installed"` Downloaded bool `json:"downloaded"` UpToDate bool `json:"up_to_date"` Tainted bool `json:"tainted"` TaintedBy []string `json:"tainted_by,omitempty" yaml:"tainted_by,omitempty"` BelongsToCollections []string `json:"belongs_to_collections,omitempty" yaml:"belongs_to_collections,omitempty"` // contains filtered or unexported fields }
ItemState is used to keep the local state (i.e. at runtime) of an item. This data is not stored in the index, but is displayed with "cscli ... inspect".
func (*ItemState) Emoji ¶ added in v1.6.0
Emoji returns the status of the item as an emoji (eg. emoji.Warning).
type ItemVersion ¶
type ItemVersion struct { Digest string `json:"digest,omitempty" yaml:"digest,omitempty"` Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` }
ItemVersion is used to detect the version of a given item by comparing the hash of each version to the local file. If the item does not match any known version, it is considered tainted (modified).
type NotFoundError ¶ added in v1.6.5
type NotFoundError = downloader.NotFoundError
no need to import the lib package to use this