scribe

package module
v0.0.0-...-3fd4271 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 10, 2022 License: MPL-2.0 Imports: 15 Imported by: 7

README

scribe

scribe is a host policy evaluator written in Go.

Build Status Go Report Card

Overview

scribe is a Go library and frontend used to evaluate policies on systems. Policies are specified as a JSON or YAML document containing a series of tests, and these tests return a status indicating if the test criteria matched or not.

Tests reference objects in the policy file. An object can be considered an abstraction of some data from the system, for example a package version or the contents of a specific file. The tests also specify criteria that will be applied to the referenced object. For example, if an object returns a line from a given file, the test could indicate that the data must match specific content. If the match succeeeds, the test returns true.

It is intended to perform functions such as:

  • Identification of software versions that do not meet a specific requirement
  • Evaluation of hardening criteria or other system security policies
  • Any other functions involving extraction and analysis of host information

The software is designed to return only test status criteria, and meta-data associated with the test. It runs directly on the system being evaluated, and requires no data from the system to be returned to a central server for additional processing.

It's primary purpose is integration with Mozilla MIG which allows investigators to perform system evaluation by sending a policy to the MIG agent for execution. It is also suited to executing policies as part of an instance build and testing process, or periodically on an installed system.

Usage

Scribe policies can be evaluated using the scribecmd command line tool, or alternatively the scribe library can be included in another go application.

This example shows evaluation of a given policy file, where only tests that return true are displayed in the results.

$ ./scribecmd -f mypolicy.json -T

scribecmd supports other runtime options, see the usage output for details.

Vulnerability scanning

scribe can be used to perform vulnerability scanning directly on the system using a suitable policy file. The library implements various criteria specifications such as EVR (epoch/version/release) testing that can be used to determine if a given package version is less than what is required.

scribevulnpolicy is a policy generator that integrates with clair for vulnerability data. This tool can be used to generate scribe vulnerability check policies for supported platforms. For details on usage see the documentation for scribevulnpolicy.

Additional documentation

Additional documentation on the library is available at godoc.org.

Documentation

Overview

Package scribe implements the Mozilla scribe host policy evaluator.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/mozilla/scribe"
)

func main() {
	docstr := `---
objects:
  - object: raw
    raw:
      identifiers:
        - identifier: test
          value: Example
tests:
  - test: example
    name: an example test
    object: raw
    regexp:
      value: Example
`

	rdr := strings.NewReader(docstr)
	// Initialize the library.
	scribe.Bootstrap()
	// Load the document from the reader, returning a Document type.
	// LoadDocument() will also call ValidateDocument() to check for any
	// consistency issues.
	doc, err := scribe.LoadDocument(rdr)
	if err != nil {
		fmt.Println("LoadDocument:", err)
		return
	}
	// Analyze the document.
	err = scribe.AnalyzeDocument(doc)
	if err != nil {
		fmt.Println("AnalyzeDocument:", err)
		return
	}
	// Grab the results for the test, most of the time you would loop
	// through the results of GetTestIdentifiers() rather then call a result
	// directly.
	result, err := scribe.GetResults(&doc, "example")
	if err != nil {
		fmt.Println("GetResults:", err)
		return
	}
	if result.MasterResult {
		fmt.Println("true")
	} else {
		fmt.Println("false")
	}

}
Output:

true

Index

Examples

Constants

View Source
const (
	EvropLessThan
	EvropGreaterThan
	EvropEquals
	EvropUnknown
)

EVR operation constants

View Source
const Version = "0.5"

Version is the scribe library version

Variables

This section is empty.

Functions

func AnalyzeDocument

func AnalyzeDocument(d Document) error

AnalyzeDocument analyzes a scribe document on the host system. The will prepare and execute all tests specified in the scribe document. Returns an error if a fatal error occurs.

Note that an error in an individual test does not necessarily represent a fatal error condition. In these cases, the test itself will be marked as having an error condition (stored in the Err field of the Test).

func Bootstrap

func Bootstrap() (err error)

Bootstrap the scribe library. This function is currently not used but code should call this function before any other functions in the library. An error is returned if one occurs.

Applications should call this as it may be mandatory in the future to do more explicit initialization of the library outside of init().

func ExpectedCallback

func ExpectedCallback(f func(TestResult))

ExpectedCallback can be used to set a callback function for test results.

Set an expected result callback. f should be a function that takes a TestResult type as an argument. When this is set, if the result of a test does not match the value set in "expectedresult" for the test, the function is immediately called with the applicable TestResult as an argument.

func InstallFileLocator

func InstallFileLocator(f func(string, bool, string, int) ([]string, error))

InstallFileLocator installs alternate file walking functions.

Install an alternate file location function. This overrides use of the SimpleFileLocator locate() function, and allows specification of an alternate function to use for locating candidate files on the filesystem.

This function is primarily used within the scribe mig module to make use of the file module traversal function.

func SetDebug

func SetDebug(f bool, w io.Writer)

SetDebug enables or disables debugging. If debugging is enabled, output is written to the io.Writer specified by w.

func TestEvrCompare

func TestEvrCompare(op int, actual string, check string) (bool, error)

TestEvrCompare is an exported version of the EVR comparison operation. op is used to specify an EVR comparison operation (e.g., EvropLessThan). actual and check are the version strings to test. Returns status of test evaluation, or an error if an error occurs.

func TestHooks

func TestHooks(f bool)

TestHooks enables or disables testing hooks in the library.

Enable or disable test hooks. If test hooks are enabled, certain functions such as requesting package data from the host system are bypassed in favor of test tables.

Types

type Document

type Document struct {
	Variables []Variable `json:"variables,omitempty" yaml:"variables,omitempty"`
	Objects   []Object   `json:"objects,omitempty" yaml:"objects,omitempty"`
	Tests     []Test     `json:"tests,omitempty" yaml:"tests,omitempty"`
}

Document describes a scribe document; a document contains all tests and other infomration used to execute a policy check

func LoadDocument

func LoadDocument(r io.Reader) (Document, error)

LoadDocument loads a scribe JSON or YAML document from the reader specified by r. Returns a Document type that can be passed to AnalyzeDocument(). On error, LoadDocument() returns the error that occurred.

func (*Document) GetTest

func (d *Document) GetTest(testid string) (*Test, error)

Return a pointer to a test instance of the test whose identifier matches

func (*Document) GetTestIdentifiers

func (d *Document) GetTestIdentifiers() []string

GetTestIdentifiers returns the test identifiers for all tests present in the document.

func (*Document) Validate

func (d *Document) Validate() error

Validate a scribe document for consistency. This identifies any errors in the document that are not JSON syntax related, including missing fields or references to tests that do not exist. Returns an error if validation fails.

type EVRTest

type EVRTest struct {
	Operation string `json:"operation,omitempty" yaml:"operation,omitempty"`
	Value     string `json:"value,omitempty" yaml:"value,omitempty"`
}

EVRTest describes the EVR option that will be performed as part of a test. For example, Operation may be "<" and Value may be a version string such as "1.2.3".

type ExactMatch

type ExactMatch struct {
	Value string `json:"value,omitempty" yaml:"value,omitempty"`
}

ExactMatch is used to indicate a test should match Value exactly against the referenced object

type FileContent

type FileContent struct {
	Path       string `json:"path,omitempty" yaml:"path,omitempty"`
	File       string `json:"file,omitempty" yaml:"file,omitempty"`
	Expression string `json:"expression,omitempty" yaml:"expression,omitempty"`
	Concat     string `json:"concat,omitempty" yaml:"concat,omitempty"`

	ImportChain []string `json:"import-chain,omitempty" yaml:"import-chain,omitempty"`
	// contains filtered or unexported fields
}

FileContent is used to perform tests against the content of a given file on the file system.

type FileName

type FileName struct {
	Path string `json:"path,omitempty" yaml:"path,omitempty"`
	File string `json:"file,omitempty" yaml:"file,omitempty"`
	// contains filtered or unexported fields
}

FileName is used to perform tests against a given file name on the file system

type HasLine

type HasLine struct {
	Path       string `json:"path,omitempty" yaml:"path,omitempty"`
	File       string `json:"file,omitempty" yaml:"file,omitempty"`
	Expression string `json:"expression,omitempty" yaml:"expression,omitempty"`
	// contains filtered or unexported fields
}

HasLine is used to perform tests against whether or not a file contains a given regular expression

type Object

type Object struct {
	Object      string      `json:"object" yaml:"object"`
	FileContent FileContent `json:"filecontent" yaml:"filecontent"`
	FileName    FileName    `json:"filename" yaml:"filename"`
	Package     Pkg         `json:"package" yaml:"package"`
	Raw         Raw         `json:"raw" yaml:"raw"`
	HasLine     HasLine     `json:"hasline" yaml:"hasline"`
	// contains filtered or unexported fields
}

Object describes data that will be sourced from the system and used in a test. Tests specify the criteria that will be applied to determine a true or false result, and tests reference an Object which provides the data the criteria will be compared to.

type PackageInfo

type PackageInfo struct {
	Name    string `json:"name" yaml:"name"`       // Package name.
	Version string `json:"version" yaml:"version"` // Package version.
	Type    string `json:"type" yaml:"type"`       // Package type.
	Arch    string `json:"arch" yaml:"arch"`       // Package architecture
}

PackageInfo stores information from the system as returned by QueryPackages().

func QueryPackages

func QueryPackages() []PackageInfo

QueryPackages will query packages on the system, returning a slice of all identified packages in PackageInfo form.

type Pkg

type Pkg struct {
	Name         string `json:"name,omitempty" yaml:"name,omitempty"`
	CollectMatch string `json:"collectmatch,omitempty" yaml:"collectmatch,omitempty"`
	OnlyNewest   bool   `json:"onlynewest,omitempty" yaml:"onlynewest,omitempty"`
	// contains filtered or unexported fields
}

Pkg is used to perform tests against packages that are installed on the system, for example package version tests.

Normally when a Pkg object is prepared, the pkgInfo list will be filled with information related to any package installed which exactly matches Name. If the optional CollectMatch parameter is set, this regular expression will be used to match packages, but the package name will still be Name.

For example, if Name is set to linux-image-generic, and CollectMatch is set to ^linux-image-.*-generic$, it will result in the object being populated with a set of version strings from all installed packages that match the regexp.

This is intended to handle a case where we want to do a kernel package version comparison, but the kernel package name actually includes the a version string which makes a direct package name -> name comparison harder.

If OnlyNewest is true, the object will only be populated with the newest instance of a given package if there are multiple versions of the same package installed.

type Raw

type Raw struct {
	Identifiers []RawIdentifiers `json:"identifiers,omitempty" yaml:"identifiers,omitempty"`
}

Raw can be used to create an object that has values already defined directly in the policy file. For example, an object with a raw entry is not populated from the system, but the raw values themselves are referencable from a test or from another object using an import-chain.

type RawIdentifiers

type RawIdentifiers struct {
	Identifier string `json:"identifier,omitempty" yaml:"identifier,omitempty"`
	Value      string `json:"value,omitempty" yaml:"value,omitempty"`
}

RawIdentifiers are the identifier/value pairs that make up raw entries in an object.

type Regex

type Regex struct {
	Value string `json:"value,omitempty" yaml:"value,omitempty"`
}

Regex is used to specify regular expression matching criteria within a test.

type Test

type Test struct {
	TestID      string `json:"test" yaml:"test"`     // The ID for this test.
	TestName    string `json:"name" yaml:"name"`     // An optional name for this test
	Object      string `json:"object" yaml:"object"` // The object this test references.
	Description string `json:"description,omitempty" yaml:"description,omitempty"`

	// Evaluators
	EVR    EVRTest    `json:"evr,omitempty" yaml:"evr,omitempty"`               // EVR version comparison
	Regexp Regex      `json:"regexp,omitempty" yaml:"regexp,omitempty"`         // Regular expression comparison
	EMatch ExactMatch `json:"exactmatch,omitempty" yaml:"exactmatch,omitempty"` // Exact string match

	Tags []TestTag `json:"tags,omitempty" yaml:"tags,omitempty"` // Tags associated with the test

	If []string `json:"if,omitempty" yaml:"if,omitempty"` // Slice of test names for dependencies

	// These values are optional but can be set to use the expected result
	// callback handler. These are primarily used for testing but can also
	// be used to trigger scribecmd to return and a non-zero exit status
	// if a test does not evaluate to the desired value.
	ExpectedResult bool `json:"expectedresult,omitempty" yaml:"expectedresult,omitempty"` // Expected master result for test
	ExpectError    bool `json:"expecterror,omitempty" yaml:"expecterror,omitempty"`       // True if test should result in error
	// contains filtered or unexported fields
}

Test is a test within the policy document that will be executed. Tests specify various criteria, and then compare this criteria against the data returned by the object the test references.

type TestResult

type TestResult struct {
	TestID      string    `json:"testid" yaml:"testid"`                 // The identifier for the test.
	TestName    string    `json:"name" yaml:"name"`                     // Optional test name for display
	Description string    `json:"description" yaml:"description"`       // Test description
	Tags        []TestTag `json:"tags,omitempty" yaml:"tags,omitempty"` // Tags for the test.

	IsError bool   `json:"iserror" yaml:"iserror"` // True of error is encountered during evaluation.
	Error   string `json:"error" yaml:"error"`     // Error associated with test.

	MasterResult   bool `json:"masterresult" yaml:"masterresult"`     // Master result of test.
	HasTrueResults bool `json:"hastrueresults" yaml:"hastrueresults"` // True if > 0 evaluations resulted in true.

	Results []TestSubResult `json:"results" yaml:"results"` // The sub-results for the test.
}

TestResult describes the results of a test. The type can be marshaled into a JSON string as required.

func GetResults

func GetResults(d *Document, name string) (TestResult, error)

GetResults returns test results for a given test. Returns an error if for some reason the results can not be returned.

func (*TestResult) JSON

func (r *TestResult) JSON() string

JSON is a helper function to convert TestResult into a JSON string.

func (*TestResult) SingleLineResults

func (r *TestResult) SingleLineResults() []string

SingleLineResults is a helper function to convert Testresult r into a slice of greppable single line results. Note that each line returned is not terminated with a line feed.

func (*TestResult) String

func (r *TestResult) String() string

A helper function to convert TestResult into a human readable result suitable for display.

type TestSubResult

type TestSubResult struct {
	Result     bool   `json:"result" yaml:"result"`         // The result of evaluation for an identifier source.
	Identifier string `json:"identifier" yaml:"identifier"` // The identifier for the source.
}

TestSubResult describes a sub-result for a test.

For a given test, a number of sources can be identified that match the criteria. For example, multiple files can be identified with a given filename. Each test tracks individual results for these cases.

type TestTag

type TestTag struct {
	Key   string `json:"key,omitempty" yaml:"key,omitempty"`
	Value string `json:"value,omitempty" yaml:"value,omitempty"`
}

TestTag describes arbitrary key value tags that can be associated with a test

type Variable

type Variable struct {
	Key   string `json:"key" yaml:"key"`
	Value string `json:"value" yaml:"value"`
}

Variable defines variables that can be included in the policy document. Variables are expanded in objects at runtime.

Directories

Path Synopsis
This Source Code Form is subject to the terms of the Mozilla Public License, v.
This Source Code Form is subject to the terms of the Mozilla Public License, v.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL