[doc] tons of new docs, with some CSS changes

This commit is contained in:
Julien Vehent 2015-10-06 09:29:38 -04:00
Родитель 75161adc20
Коммит 7c4a70049e
28 изменённых файлов: 2607 добавлений и 903 удалений

Просмотреть файл

@ -1,10 +1,234 @@
Agent
=====
======================
MIG Agent Architecture
======================
The agent accepts different classes of inputs on stdin, as one-line JSON objects. The most common one is the
``parameters`` class, but it could also receive a ``stop`` input that
indicates that the module should stop its execution immediately. The format of
module input messages is defined by ``modules.Message``.
.. sectnum::
.. contents:: Table of Contents
Initialization process
----------------------------
The agent tries to be as autonomous as possible. One of the goal is to ship
agents without requiring external provisioning tools, such as Chef or Puppet.
Therefore, the agent attempts to install itself as a service, and also supports
a builtin upgrade protocol (described in the next section).
As a portable binary, the agent needs to detect the type of operating system
and init method that is used by an endpoint. Depending on the endpoint,
different initialization methods are used. The diagram below explains the
decision process followed by the agent.
.. image:: .files/mig-agent-initialization-process.png
Go does not provide support for running programs in the backgroud. On endpoints
that run upstart, systemd (linux) or launchd (darwin), this is not an issue
because the init daemon takes care of running the agent in the background,
rerouting its file descriptors and restarting on crash. On Windows and System-V,
however, the agent daemonizes by forking itself into `foreground` mode, and
re-forking itself on error (such as loss of connectivity to the relay).
On Windows and System-V, if the agent is killed, it will not be restarted
automatically.
Registration process
~~~~~~~~~~~~~~~~~~~~
The initialization process goes through several environment detection steps
which are used to select the proper init method. Once started, the agent will
send a heartbeat to the public relay, and also store that heartbeat in its
`run` directory. The location of the `run` directory is platform specific.
* windows: C:\Windows\
* darwin: /Library/Preferences/mig/
* linux: /var/run/mig/
Below is a sample heartbeat message from a linux agent stored in
`/var/run/mig/mig-agent.ok`.
.. code:: json
{
"destructiontime": "0001-01-01T00:00:00Z",
"environment": {
"arch": "amd64",
"ident": "Red Hat Enterprise Linux Server release 6.5 (Santiago)",
"init": "upstart"
},
"heartbeatts": "2014-07-31T14:00:20.00442837-07:00",
"name": "someserver.example.net",
"os": "linux",
"pid": 26256,
"queueloc": "linux.someserver.example.net.5hsa811oda",
"starttime": "2014-07-30T21:34:48.525449401-07:00",
"version": "201407310027+bcbdd94.prod"
}
Check-In mode
~~~~~~~~~~~~~
In infrastructure where running the agent as a permanent process is not
acceptable, it is possible to run the agent as a cron job. By starting the
agent with the flag **-m agent-checkin**, the agent will connect to the
configured relay, retrieve and run outstanding commands, and exit after 10
seconds of inactivity.
Communication with modules
--------------------------
Upon processing of an action, the scheduler will retrieve a list of agents to
send the action to. One action is then derived into multiple commands and sent
to agents.
An agent receives a command from the scheduler on its personal AMQP queue (1).
It parses the command (2) and extracts all of the operations to perform.
Operations are passed to modules and executed in parallel (3). Rather than
maintaining a state of the running command, the agent create a goroutine and a
channel tasked with receiving the results from the modules. Each modules
published its results inside that channel (4). The result parsing goroutine
receives them, and when it has received all of them, populates the `results` (5)
array of the command with the results from each module, and send the command
back to the scheduler(6).
When the agent is done running the command, both the channel and the goroutine
are destroyed.
::
+-------+ [ - - - - - - A G E N T - - - - - - - - - - - - ]
|command|+---->(listener)
+-------+ |(2)
^ V
|(1) (parser)
| + [ m o d u l e s ]
+---------+ | (3)|----------> op1 +----------------+
|SCHEDULER|+---+ |------------> op2 +--------------|
| |<---+ |--------------> op3 +------------|
+---------+ | +----------------> op4 +----------+
| V(4)
|(6) (receiver)
| |
| V(5)
+ (publisher)
+-------+ /
|results|<-----------------------------------------'
+-------+
The command received by the agent is composed of a copy of the action described
previously, but signed with the private key of a trusted investigator. It also
contains additional parameters that are specific to the targetted agent, such as
command processing timestamps, name of the agent queue on the message broker,
action and command unique IDs and status and results of the command. Below is an
command derived from the root password checking action, and ran on the host named
'host1.example.net'.
.. code:: json
{
"id": 1.427392971126604e+18,
"action": { ... SIGNED COPY OF THE ACTION ... },
"agent": {
"id": 1.4271760437936648e+18,
"name": "host1.example.net",
"queueloc": "linux.host1.example.net.981alsd19aos1984",
"mode": "daemon",
"version": "20150324+0d0f88c.prod"
},
"status": "success",
"results": [
{
"foundanything": true,
"success": true,
"elements": {
"root_passwd_hashed_or_disabled": [
{
"file": "/etc/shadow",
"fileinfo": {
"lastmodified": "2015-02-07 01:51:07.17850601 +0000 UTC",
"mode": "----------",
"size": 1684
},
"search": {
"contents": [
"root:(\\*|!|\\$(1|2a|5|6)\\$).+"
],
"options": {
"matchall": false,
"matchlimit": 0,
"maxdepth": 0
},
"paths": [
"/etc"
]
}
}
]
},
"statistics": {
"exectime": "2.017849ms",
"filescount": 1,
"openfailed": 0,
"totalhits": 1
},
"errors": null
}
],
"starttime": "2015-03-26T18:02:51.126605Z",
"finishtime": "2015-03-26T18:03:00.671232Z"
}
The results of the command show that the file '/etc/shadow' has matched, and
thus "FoundAnything" returned "True".
The invocation of the file module has completed successfully, which is
represented by **results->0->success=true**. In our example, there is only one
operation in the **action->operations** array, so only one result is present.
When multiple operations are performed, each has its results listed in a
corresponding entry of the results array (operations[0] is in results[0],
operations[1] in results[1], etc...).
Finally, the agent has performed all operations in the operations array
successfully, and returned **status=success**. Had a failure happened on the
agent, the returned status would be one of "failed", "timeout" or "cancelled".
Command expiration & timeouts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To prevent abuse of resources, agents will kill long-running modules after a
given period of time. That timeout is hardcoded in the agent configuration
at compile time and defaults to 5 minutes.
.. code:: go
// timeout after which a module run is killed
var MODULETIMEOUT time.Duration = 300 * time.Second
That timeout represents the **maximum** execution time of a single operation. If
an action contains 3 operations, each operation gets its own timeout. But because
operations run in parallel in the agent, the maximum runtime of an action should
be very close to the value of MODULETIMEOUT.
In a typical deployment, it is safe to increase MODULETIMEOUT to allow for
longer operations. A value of 20 minutes is usual. Make sure to fine tune this
to your environment, and get the approval of your ops team because mig-agent
may end up consuming resources (but never more than 50% of the cpu available on
a system).
Oftentimes, an investigator will want a timeout that is much shorter than the value
of MODULETIMEOUT. In the MIG command line, the flag `-e` controls the
expiration. It defaults to 5 minutes but can be set to 30 seconds for simple
investigations. When that happens, the agent will calculate an appropriate expiration
for the operations being run. If the expiration set on the action is set to 30 seconds,
the agent will kill operations that run for more than 30 seconds.
If the expiration is larger than the value of MODULETIMEOUT (for example, 2
hours), then MODULETIMEOUT is used. Setting a long expiration may be useful to
allow agents that only check in periodically to pick up actions long after they
are launched.
Agent/Modules message format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The agent accepts different classes of inputs on stdin, as one-line JSON objects.
The most common one is the ``parameters`` class, but it could also receive a
``stop`` input that indicates that the module should stop its execution immediately.
The format of module input messages is defined by ``modules.Message``.
.. code:: go
@ -25,4 +249,104 @@ and copies them into ``Message.Parameters``. It then sets ``Message.Class`` to
``modules.MsgClassParameters``, marshals the struct into JSON, and pass the
resulting ``[]byte`` to the module as an IO stream.
Agent upgrade process
---------------------
MIG supports upgrading agents in the wild. The upgrade protocol is designed with
security in mind. The flow diagram below presents a high-level view:
::
Investigator Scheduler Agent NewAgent FileServer
+-----------+ +-------+ +---+ +------+ +--------+
| | | | |
| 1.initiate | | | |
|------------------>| | | |
| | 2.send command | | |
| |------------------>| 3.verify | |
| | |--------+ | |
| | | | | |
| | | | | |
| | |<-------+ | |
| | | | |
| | | 4.download | |
| | |-------------------------------------->|
| | | | |
| | | 5.checksum | |
| | |--------+ | |
| | | | | |
| | | | | |
| | |<-------+ | |
| | | | |
| | | 6.exec | |
| | |------------------>| |
| | 7.return own PID | | |
| |<------------------| | |
| | | | |
| |------+ 8.mark | | |
| | | agent as | | |
| | | upgraded | | |
| |<-----+ | | |
| | | | |
| | 9.register | | |
| |<--------------------------------------| |
| | | | |
| |------+10.find dup | | |
| | |agents in | | |
| | |registrations | |
| |<-----+ | | |
| | | | |
| | 11.send command to kill PID old agt| |
| |-------------------------------------->| |
| | | | |
| | 12.acknowledge | | |
| |<--------------------------------------| |
All upgrade operations are initiated by an investigator (1). The upgrade is
triggered by an action to the upgrade module with the following parameters:
.. code:: json
"Operations": [
{
"Module": "upgrade",
"Parameters": {
"linux/amd64": {
"to_version": "16eb58b-201404021544",
"location": "http://localhost/mig/bin/linux/amd64/mig-agent",
"checksum": "31fccc576635a29e0a27bbf7416d4f32a0ebaee892475e14708641c0a3620b03"
}
}
}
],
* Each OS family and architecture have their own parameters (ex: "linux/amd64",
"darwin/amd64", "windows/386", ...). Then, in each OS/Arch group, we have:
* to_version is the version an agent should upgrade to
* location points to a HTTPS address that contains the agent binary
* checksum is a SHA256 hash of the agent binary to be verified after download
The parameters above are signed using a standard PGP action signature.
The upgrade action is forwarded to agents (2) like any other action. The action
signature is verified by the agent (3), and the upgrade module is called. The
module downloads the new binary (4), verifies the version and checksum (5) and
installs itself on the system.
Assuming everything checks in, the old agent executes the binary of the new
agent (6). At that point, two agents are running on the same machine, and the
rest of the protocol is designed to shut down the old agent, and clean up.
After executing the new agent, the old agent returns a successful result to the
scheduler, and includes its own PID in the results.
The new agent starts by registering with the scheduler (7). This tells the
scheduler that two agents are running on the same node, and one of them must
terminate. The scheduler sends a kill action to both agents with the PID of the
old agent (8). The kill action may be executed twice, but that doesn't matter.
When the scheduler receives the kill results (9), it sends a new action to check
for `mig-agent` processes (10). Only one should be found in the results (11),
and if that is the case, the scheduler tells the agent to remove the binary of
the old agent (12). When the agent returns (13), the upgrade protocol is done.
If the PID of the old agent lingers on the system, an error is logged for the
investigator to decide what to do next. The scheduler does not attempt to clean
up the situation.

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {
@ -227,10 +229,156 @@ cite {
strong {
color: #C64216;
}
</style></head><body><h1>Agent</h1><p>The agent accepts different classes of inputs on stdin, as one-line JSON objects. The most common one is the
<code>parameters</code> class, but it could also receive a <code>stop</code> input that
indicates that the module should stop its execution immediately. The format of
module input messages is defined by <code>modules.Message</code>.</p><pre><code class="code go"><span class="comment single">// Message defines the input messages received by modules.
</style></head><body><h1>MIG Agent Architecture</h1><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#initialization-process" id="id1">1   Initialization process</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#registration-process" id="id2">1.1   Registration process</a></p></li><li><p><a class="reference internal" href="#check-in-mode" id="id3">1.2   Check-In mode</a></p></li></ul></li><li><p><a class="reference internal" href="#communication-with-modules" id="id4">2   Communication with modules</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#command-expiration-timeouts" id="id5">2.1   Command expiration &amp; timeouts</a></p></li><li><p><a class="reference internal" href="#agent-modules-message-format" id="id6">2.2   Agent/Modules message format</a></p></li></ul></li><li><p><a class="reference internal" href="#agent-upgrade-process" id="id7">3   Agent upgrade process</a></p></li></ul></div><section id="initialization-process"><header><h2><a href="#id1">1   Initialization process</a></h2></header><p>The agent tries to be as autonomous as possible. One of the goal is to ship
agents without requiring external provisioning tools, such as Chef or Puppet.
Therefore, the agent attempts to install itself as a service, and also supports
a builtin upgrade protocol (described in the next section).</p><p>As a portable binary, the agent needs to detect the type of operating system
and init method that is used by an endpoint. Depending on the endpoint,
different initialization methods are used. The diagram below explains the
decision process followed by the agent.</p><img alt=".files/mig-agent-initialization-process.png" src=".files/mig-agent-initialization-process.png"><p>Go does not provide support for running programs in the backgroud. On endpoints
that run upstart, systemd (linux) or launchd (darwin), this is not an issue
because the init daemon takes care of running the agent in the background,
rerouting its file descriptors and restarting on crash. On Windows and System-V,
however, the agent daemonizes by forking itself into <cite>foreground</cite> mode, and
re-forking itself on error (such as loss of connectivity to the relay).
On Windows and System-V, if the agent is killed, it will not be restarted
automatically.</p><section id="registration-process"><header><h3><a href="#id2">1.1   Registration process</a></h3></header><p>The initialization process goes through several environment detection steps
which are used to select the proper init method. Once started, the agent will
send a heartbeat to the public relay, and also store that heartbeat in its
<cite>run</cite> directory. The location of the <cite>run</cite> directory is platform specific.</p><ul><li><p>windows: C:Windows</p></li><li><p>darwin: /Library/Preferences/mig/</p></li><li><p>linux: /var/run/mig/</p></li></ul><p>Below is a sample heartbeat message from a linux agent stored in
<cite>/var/run/mig/mig-agent.ok</cite>.</p><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"destructiontime"</span><span class="punctuation">:</span> <span class="literal string double">"0001-01-01T00:00:00Z"</span><span class="punctuation">,</span>
<span class="name tag">"environment"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"arch"</span><span class="punctuation">:</span> <span class="literal string double">"amd64"</span><span class="punctuation">,</span>
<span class="name tag">"ident"</span><span class="punctuation">:</span> <span class="literal string double">"Red Hat Enterprise Linux Server release 6.5 (Santiago)"</span><span class="punctuation">,</span>
<span class="name tag">"init"</span><span class="punctuation">:</span> <span class="literal string double">"upstart"</span>
<span class="punctuation">},</span>
<span class="name tag">"heartbeatts"</span><span class="punctuation">:</span> <span class="literal string double">"2014-07-31T14:00:20.00442837-07:00"</span><span class="punctuation">,</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"someserver.example.net"</span><span class="punctuation">,</span>
<span class="name tag">"os"</span><span class="punctuation">:</span> <span class="literal string double">"linux"</span><span class="punctuation">,</span>
<span class="name tag">"pid"</span><span class="punctuation">:</span> <span class="literal number integer">26256</span><span class="punctuation">,</span>
<span class="name tag">"queueloc"</span><span class="punctuation">:</span> <span class="literal string double">"linux.someserver.example.net.5hsa811oda"</span><span class="punctuation">,</span>
<span class="name tag">"starttime"</span><span class="punctuation">:</span> <span class="literal string double">"2014-07-30T21:34:48.525449401-07:00"</span><span class="punctuation">,</span>
<span class="name tag">"version"</span><span class="punctuation">:</span> <span class="literal string double">"201407310027+bcbdd94.prod"</span>
<span class="punctuation">}</span></code></pre></section><section id="check-in-mode"><header><h3><a href="#id3">1.2   Check-In mode</a></h3></header><p>In infrastructure where running the agent as a permanent process is not
acceptable, it is possible to run the agent as a cron job. By starting the
agent with the flag <strong>-m agent-checkin</strong>, the agent will connect to the
configured relay, retrieve and run outstanding commands, and exit after 10
seconds of inactivity.</p></section></section><section id="communication-with-modules"><header><h2><a href="#id4">2   Communication with modules</a></h2></header><p>Upon processing of an action, the scheduler will retrieve a list of agents to
send the action to. One action is then derived into multiple commands and sent
to agents.</p><p>An agent receives a command from the scheduler on its personal AMQP queue (1).
It parses the command (2) and extracts all of the operations to perform.
Operations are passed to modules and executed in parallel (3). Rather than
maintaining a state of the running command, the agent create a goroutine and a
channel tasked with receiving the results from the modules. Each modules
published its results inside that channel (4). The result parsing goroutine
receives them, and when it has received all of them, populates the <cite>results</cite> (5)
array of the command with the results from each module, and send the command
back to the scheduler(6).</p><p>When the agent is done running the command, both the channel and the goroutine
are destroyed.</p><blockquote><pre> +-------+ [ - - - - - - A G E N T - - - - - - - - - - - - ]
|command|+----&gt;(listener)
+-------+ |(2)
^ V
|(1) (parser)
| + [ m o d u l e s ]
+---------+ | (3)|----------&gt; op1 +----------------+
|SCHEDULER|+---+ |------------&gt; op2 +--------------|
| |&lt;---+ |--------------&gt; op3 +------------|
+---------+ | +----------------&gt; op4 +----------+
| V(4)
|(6) (receiver)
| |
| V(5)
+ (publisher)
+-------+ /
|results|&lt;-----------------------------------------'
+-------+</pre></blockquote><p>The command received by the agent is composed of a copy of the action described
previously, but signed with the private key of a trusted investigator. It also
contains additional parameters that are specific to the targetted agent, such as
command processing timestamps, name of the agent queue on the message broker,
action and command unique IDs and status and results of the command. Below is an
command derived from the root password checking action, and ran on the host named
'host1.example.net'.</p><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"id"</span><span class="punctuation">:</span> <span class="literal number float">1.427392971126604e+18</span><span class="punctuation">,</span>
<span class="name tag">"action"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="error">...</span> <span class="error">SIGNED</span> <span class="error">COPY</span> <span class="error">OF</span> <span class="error">THE</span> <span class="error">ACTION</span> <span class="error">...</span> <span class="punctuation">},</span>
<span class="name tag">"agent"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"id"</span><span class="punctuation">:</span> <span class="literal number float">1.4271760437936648e+18</span><span class="punctuation">,</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"host1.example.net"</span><span class="punctuation">,</span>
<span class="name tag">"queueloc"</span><span class="punctuation">:</span> <span class="literal string double">"linux.host1.example.net.981alsd19aos1984"</span><span class="punctuation">,</span>
<span class="name tag">"mode"</span><span class="punctuation">:</span> <span class="literal string double">"daemon"</span><span class="punctuation">,</span>
<span class="name tag">"version"</span><span class="punctuation">:</span> <span class="literal string double">"20150324+0d0f88c.prod"</span>
<span class="punctuation">},</span>
<span class="name tag">"status"</span><span class="punctuation">:</span> <span class="literal string double">"success"</span><span class="punctuation">,</span>
<span class="name tag">"results"</span><span class="punctuation">:</span> <span class="punctuation">[</span>
<span class="punctuation">{</span>
<span class="name tag">"foundanything"</span><span class="punctuation">:</span> <span class="keyword constant">true</span><span class="punctuation">,</span>
<span class="name tag">"success"</span><span class="punctuation">:</span> <span class="keyword constant">true</span><span class="punctuation">,</span>
<span class="name tag">"elements"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"root_passwd_hashed_or_disabled"</span><span class="punctuation">:</span> <span class="punctuation">[</span>
<span class="punctuation">{</span>
<span class="name tag">"file"</span><span class="punctuation">:</span> <span class="literal string double">"/etc/shadow"</span><span class="punctuation">,</span>
<span class="name tag">"fileinfo"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"lastmodified"</span><span class="punctuation">:</span> <span class="literal string double">"2015-02-07 01:51:07.17850601 +0000 UTC"</span><span class="punctuation">,</span>
<span class="name tag">"mode"</span><span class="punctuation">:</span> <span class="literal string double">"----------"</span><span class="punctuation">,</span>
<span class="name tag">"size"</span><span class="punctuation">:</span> <span class="literal number integer">1684</span>
<span class="punctuation">},</span>
<span class="name tag">"search"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"contents"</span><span class="punctuation">:</span> <span class="punctuation">[</span>
<span class="literal string double">"root:(\\*|!|\\$(1|2a|5|6)\\$).+"</span>
<span class="punctuation">],</span>
<span class="name tag">"options"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"matchall"</span><span class="punctuation">:</span> <span class="keyword constant">false</span><span class="punctuation">,</span>
<span class="name tag">"matchlimit"</span><span class="punctuation">:</span> <span class="literal number integer">0</span><span class="punctuation">,</span>
<span class="name tag">"maxdepth"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">},</span>
<span class="name tag">"paths"</span><span class="punctuation">:</span> <span class="punctuation">[</span>
<span class="literal string double">"/etc"</span>
<span class="punctuation">]</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span>
<span class="punctuation">]</span>
<span class="punctuation">},</span>
<span class="name tag">"statistics"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"exectime"</span><span class="punctuation">:</span> <span class="literal string double">"2.017849ms"</span><span class="punctuation">,</span>
<span class="name tag">"filescount"</span><span class="punctuation">:</span> <span class="literal number integer">1</span><span class="punctuation">,</span>
<span class="name tag">"openfailed"</span><span class="punctuation">:</span> <span class="literal number integer">0</span><span class="punctuation">,</span>
<span class="name tag">"totalhits"</span><span class="punctuation">:</span> <span class="literal number integer">1</span>
<span class="punctuation">},</span>
<span class="name tag">"errors"</span><span class="punctuation">:</span> <span class="keyword constant">null</span>
<span class="punctuation">}</span>
<span class="punctuation">],</span>
<span class="name tag">"starttime"</span><span class="punctuation">:</span> <span class="literal string double">"2015-03-26T18:02:51.126605Z"</span><span class="punctuation">,</span>
<span class="name tag">"finishtime"</span><span class="punctuation">:</span> <span class="literal string double">"2015-03-26T18:03:00.671232Z"</span>
<span class="punctuation">}</span></code></pre><p>The results of the command show that the file '/etc/shadow' has matched, and
thus "FoundAnything" returned "True".</p><p>The invocation of the file module has completed successfully, which is
represented by <strong>results-&gt;0-&gt;success=true</strong>. In our example, there is only one
operation in the <strong>action-&gt;operations</strong> array, so only one result is present.
When multiple operations are performed, each has its results listed in a
corresponding entry of the results array (operations[0] is in results[0],
operations[1] in results[1], etc...).</p><p>Finally, the agent has performed all operations in the operations array
successfully, and returned <strong>status=success</strong>. Had a failure happened on the
agent, the returned status would be one of "failed", "timeout" or "cancelled".</p><section id="command-expiration-timeouts"><header><h3><a href="#id5">2.1   Command expiration &amp; timeouts</a></h3></header><p>To prevent abuse of resources, agents will kill long-running modules after a
given period of time. That timeout is hardcoded in the agent configuration
at compile time and defaults to 5 minutes.</p><pre><code class="code go"><span class="comment single">// timeout after which a module run is killed
</span><span class="keyword declaration">var</span> <span class="name other">MODULETIMEOUT</span> <span class="name other">time</span><span class="punctuation">.</span><span class="name other">Duration</span> <span class="punctuation">=</span> <span class="literal number integer">300</span> <span class="operator">*</span> <span class="name other">time</span><span class="punctuation">.</span><span class="name other">Second</span></code></pre><p>That timeout represents the <strong>maximum</strong> execution time of a single operation. If
an action contains 3 operations, each operation gets its own timeout. But because
operations run in parallel in the agent, the maximum runtime of an action should
be very close to the value of MODULETIMEOUT.</p><p>In a typical deployment, it is safe to increase MODULETIMEOUT to allow for
longer operations. A value of 20 minutes is usual. Make sure to fine tune this
to your environment, and get the approval of your ops team because mig-agent
may end up consuming resources (but never more than 50% of the cpu available on
a system).</p><p>Oftentimes, an investigator will want a timeout that is much shorter than the value
of MODULETIMEOUT. In the MIG command line, the flag <cite>-e</cite> controls the
expiration. It defaults to 5 minutes but can be set to 30 seconds for simple
investigations. When that happens, the agent will calculate an appropriate expiration
for the operations being run. If the expiration set on the action is set to 30 seconds,
the agent will kill operations that run for more than 30 seconds.</p><p>If the expiration is larger than the value of MODULETIMEOUT (for example, 2
hours), then MODULETIMEOUT is used. Setting a long expiration may be useful to
allow agents that only check in periodically to pick up actions long after they
are launched.</p></section><section id="agent-modules-message-format"><header><h3><a href="#id6">2.2   Agent/Modules message format</a></h3></header><p>The agent accepts different classes of inputs on stdin, as one-line JSON objects.
The most common one is the <code>parameters</code> class, but it could also receive a
<code>stop</code> input that indicates that the module should stop its execution immediately.
The format of module input messages is defined by <code>modules.Message</code>.</p><pre><code class="code go"><span class="comment single">// Message defines the input messages received by modules.
</span><span class="keyword declaration">type</span> <span class="name other">Message</span> <span class="keyword declaration">struct</span> <span class="punctuation">{</span>
<span class="name other">Class</span> <span class="keyword type">string</span> <span class="comment single">// represent the type of message being passed to the module
</span> <span class="name other">Parameters</span> <span class="keyword declaration">interface</span><span class="punctuation">{}</span> <span class="comment single">// for `parameters` class, this interface contains the module parameters
@ -243,4 +391,77 @@ module input messages is defined by <code>modules.Message</code>.</p><pre><code
extracts the operation parameters from <code>Command.Action.Operations[N].Parameters</code>
and copies them into <code>Message.Parameters</code>. It then sets <code>Message.Class</code> to
<code>modules.MsgClassParameters</code>, marshals the struct into JSON, and pass the
resulting <code>[]byte</code> to the module as an IO stream.</p></body></html>
resulting <code>[]byte</code> to the module as an IO stream.</p></section></section><section id="agent-upgrade-process"><header><h2><a href="#id7">3   Agent upgrade process</a></h2></header><p>MIG supports upgrading agents in the wild. The upgrade protocol is designed with
security in mind. The flow diagram below presents a high-level view:</p><blockquote><pre>Investigator Scheduler Agent NewAgent FileServer
+-----------+ +-------+ +---+ +------+ +--------+
| | | | |
| 1.initiate | | | |
|------------------&gt;| | | |
| | 2.send command | | |
| |------------------&gt;| 3.verify | |
| | |--------+ | |
| | | | | |
| | | | | |
| | |&lt;-------+ | |
| | | | |
| | | 4.download | |
| | |--------------------------------------&gt;|
| | | | |
| | | 5.checksum | |
| | |--------+ | |
| | | | | |
| | | | | |
| | |&lt;-------+ | |
| | | | |
| | | 6.exec | |
| | |------------------&gt;| |
| | 7.return own PID | | |
| |&lt;------------------| | |
| | | | |
| |------+ 8.mark | | |
| | | agent as | | |
| | | upgraded | | |
| |&lt;-----+ | | |
| | | | |
| | 9.register | | |
| |&lt;--------------------------------------| |
| | | | |
| |------+10.find dup | | |
| | |agents in | | |
| | |registrations | |
| |&lt;-----+ | | |
| | | | |
| | 11.send command to kill PID old agt| |
| |--------------------------------------&gt;| |
| | | | |
| | 12.acknowledge | | |
| |&lt;--------------------------------------| |</pre></blockquote><p>All upgrade operations are initiated by an investigator (1). The upgrade is
triggered by an action to the upgrade module with the following parameters:</p><pre><code class="code json"><span class="literal string double">"Operations"</span><span class="error">:</span> <span class="punctuation">[</span>
<span class="punctuation">{</span>
<span class="name tag">"Module"</span><span class="punctuation">:</span> <span class="literal string double">"upgrade"</span><span class="punctuation">,</span>
<span class="name tag">"Parameters"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"linux/amd64"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"to_version"</span><span class="punctuation">:</span> <span class="literal string double">"16eb58b-201404021544"</span><span class="punctuation">,</span>
<span class="name tag">"location"</span><span class="punctuation">:</span> <span class="literal string double">"http://localhost/mig/bin/linux/amd64/mig-agent"</span><span class="punctuation">,</span>
<span class="name tag">"checksum"</span><span class="punctuation">:</span> <span class="literal string double">"31fccc576635a29e0a27bbf7416d4f32a0ebaee892475e14708641c0a3620b03"</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span>
<span class="punctuation">]</span><span class="error">,</span></code></pre><ul><li><p>Each OS family and architecture have their own parameters (ex: "linux/amd64",
"darwin/amd64", "windows/386", ...). Then, in each OS/Arch group, we have:</p></li><li><p>to_version is the version an agent should upgrade to</p></li><li><p>location points to a HTTPS address that contains the agent binary</p></li><li><p>checksum is a SHA256 hash of the agent binary to be verified after download</p></li></ul><p>The parameters above are signed using a standard PGP action signature.</p><p>The upgrade action is forwarded to agents (2) like any other action. The action
signature is verified by the agent (3), and the upgrade module is called. The
module downloads the new binary (4), verifies the version and checksum (5) and
installs itself on the system.</p><p>Assuming everything checks in, the old agent executes the binary of the new
agent (6). At that point, two agents are running on the same machine, and the
rest of the protocol is designed to shut down the old agent, and clean up.</p><p>After executing the new agent, the old agent returns a successful result to the
scheduler, and includes its own PID in the results.
The new agent starts by registering with the scheduler (7). This tells the
scheduler that two agents are running on the same node, and one of them must
terminate. The scheduler sends a kill action to both agents with the PID of the
old agent (8). The kill action may be executed twice, but that doesn't matter.
When the scheduler receives the kill results (9), it sends a new action to check
for <cite>mig-agent</cite> processes (10). Only one should be found in the results (11),
and if that is the case, the scheduler tells the agent to remove the binary of
the old agent (12). When the agent returns (13), the upgrade protocol is done.</p><p>If the PID of the old agent lingers on the system, an error is logged for the
investigator to decide what to do next. The scheduler does not attempt to clean
up the situation.</p></section></body></html>

Просмотреть файл

@ -1,7 +1,6 @@
=======
MIG API
=======
:Author: Julien Vehent <jvehent@mozilla.com>
.. sectnum::
.. contents:: Table of Contents
@ -14,186 +13,8 @@ The API follows the core principles of REST, and provides discoverable
endpoints. API responses follows the **cljs** format defined in
`Collection+JSON - Hypermedia Type <http://amundsen.com/media-types/collection/>`_.
Authentication with X-PGPAUTHORIZATION version 1
------------------------------------------------
Authenticating against the MIG API requires sending a PGP signed token in the
request header named `X-PGPAUTHORIZATION`. The key that signs the token must
belong to an active investigator. Construction of the token works as follows:
1. make a string named **str** composed of a version, a UTC timestamp in RFC3339 format
and a random nonce, each separated by semicolons. The current version is **1**
and may be upgraded in the future. The nonce value must be a positive integer.
**str=<VERSION>;<UTC TIMESTAMP RFC3339>;<NONCE>**
UTC is a hard requirement. The timestamp must end with the suffix **Z**
which indicates the UTC timezone. In bash, a correct timestamp can be
generated with the command `$ date -u +%Y-%m-%dT%H:%M:%SZ`.
An example string would look like: `1;2006-01-02T15:04:05Z;1825922807490630059`
The string must be terminated by a newline character, hexadecimal code `0x0a`.
.. code:: bash
$ hexdump -C <<< '1;2006-01-02T15:04:05Z;1825922807490630059'
00000000 31 3b 32 30 30 36 2d 30 31 2d 30 32 54 31 35 3a |1;2006-01-02T15:|
00000010 30 34 3a 30 35 5a 3b 31 38 32 35 39 32 32 38 30 |04:05Z;182592280|
00000020 37 34 39 30 36 33 30 30 35 39 0a |7490630059.|
0000002b
2. PGP sign **str** with the private key of the investigator. Armor and detach
the signature into **armoredSig**::
$ gpg -a --detach-sig <<< '1;2006-01-02T15:04:05Z;1825922807490630059'
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAABCAAGBQJUZ5psAAoJEKPWUhc7dj6PFd8IALWQS4x9Kzssww1pxc7uq9mg
JT/3jHLwAYPQV3ltqFcI5R2EGHo5DsXXjX6lfOc7DgbteB9UV+H++KG0oVUTTjuP
kncmFYmoBEDqbXju6EASBLyUlt3M43N9DmQaAaeoyW2gB0p0aEYRZoN3Cf0O0qhU
b3nnsCz6IyuBcQAZh1Jnmf7AMwRmXier8OflObQ9wJ1iYF9KCD0TgP1Z+kaCvMqC
PWQ5XaNaXn665V19mjAMicOtO9U3A/v4ApYyUSPyq0cuLrT8z/Z1vdjyeZVTaOM8
MhnoKfgBnegQnP+BPQZlWcjaBsquenC/joYRhq20nAEwSjZ1Nm7+qHo/DW0bYOA=
=4nrR
-----END PGP SIGNATURE-----
3. Create **sig** by taking **armoredSig** and removing the PGP headers, footers,
empty lines and newlines.
example: `iQEcBAABCAAGBQJUWPDpAAoJEKPWUhc7dj6PQdgH/0TRMOEAL4SL6v+JvixWtEGJzXBCqBpRBsygHAKT+m4AxwniVa9vr8vfWm14eFpZTGdlDx39Ko+tdFoHn5Z1yKEeQWEQYXqhneAnv0pYR1aIjXM8MY63TNePWBZxUerlRkjv2IH16/W5aBrbOctOxEs1BKuN2pd4Hgubr+2f43gcRcWW+Ww/5Fyg1lKzH8jP84uqiIT8wQOdBrwUkgRdSdfMQbYFjsgY57G+ZsMobNhhlFedgKuZShJCd+G1GlwsfZPsZOSLmVZahI7wjR3vckCJ66eff3e/xX7Gt0zGGa5i1dgH5Q6TSjRGRBE37FwD4C6fycUEuy9yKI7iFziw33Y==k6gT`
4. Create **token** by concatenating **str**, a semicolon, and **sig**.
**token=<str>;<sig>**
example: `1;2006-01-02T15:04:05Z;1825922807490630059;owEBYQGe/pANAwAIAaPWUhc7dj6...<truncated>`
5. Send **token** in the header named **X-PGPAUTHORIZATION** with the request::
$ curl -H 'X-PGPAUTHORIZATION: 1;2006-01-02T15:04:05Z;1825922807490630059;owEBYQGe/pANAwAIAaP...<truncated>' localhost:12345/api/v1/
6. The API verifies the version and validity period of the timestamp. By default, a
token will be rejected if its timestamp deviates from the server time by more
than 10 minutes. Administrators can configure this value. In effect, this
means a timestamp is valid for twice the duration of the window. By default,
that's 10 minutes before current server time, and 10 minutes after current
server time.
7. If the timestamp is valid, the API next verifies the signature against the data
and authenticates the user. Failure to verify the signature returns an error
with the HTTP code 401 Unauthorized.
8. The user is authorized, the API processes and answer the request.
Security implications
~~~~~~~~~~~~~~~~~~~~~
1. A token can be used an unlimited number of times within its validity period.
There is no check to guarantee that a token is only used once. It is
assumed that the token is transmitted over a secure channel such as HTTPS to
prevent token theft by a malicious user.
2. API clients and servers must use proper time synchronization for the timestamp
verification to work. A client or a server that has inaccurate time may not be
able to establish connections. We believe this requirement to be reasonable
considering the sensitivity of the API.
Example 1: invalid timestamp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The signature is valid but the timestamp is beyond the acceptable time window.
.. code:: bash
$ curl -H 'X-PGPAUTHORIZATION: 1;2006-01-02T15:04:05Z;1825922807490630059;iQEcB...<truncated>' http://localhost:12345/api/v1/
{
"collection": {
"error": {
"code": "6077873045059431424",
"message": "Authorization verification failed with error 'verifySignedToken() -> token timestamp is not within acceptable time limits'"
},
"href": "http://localhost:12345/api/v1/",
"template": {},
"version": "1.0"
}
}
Example 2: invalid signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The signature is not valid, or is signed by a key that the API does not
recognize.
.. code:: bash
$ curl -H 'X-PGPAUTHORIZATION: 1;2014-11-04T15:36:05Z;1825922807490630059;iQEcBA...<truncated>' http://localhost:12345/api/v1/
{
"collection": {
"error": {
"code": "6077875007260332032",
"message": "Authorization verification failed with error 'verifySignedToken() -> GetFingerprintFromSignature() -> openpgp: invalid signature: hash tag doesn't match'"
},
"href": "http://localhost:12345/api/v1/",
"template": {},
"version": "1.0"
}
}
Generating a token in Bash
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code::
$ token="1;$(date -u +%Y-%m-%dT%H:%M:%SZ);$RANDOM$RANDOM$RANDOM$RANDOM"; \
sig=$(gpg -a --detach-sig <<< $token |tail -8 |head -7 \
| sed ':a;N;$!ba;s/\n//g'); echo "X-PGPAUTHORIZATION: $token;$sig"
X-PGPAUTHORIZATION: 1;2014-11-04T19:13:37Z;13094113753132512760;iQEcBAA.....
Generating a token in Python
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: python
#!/usr/bin/env python
import os
import gnupg
from time import gmtime, strftime
import random
import requests
import json
def makeToken(gpghome, keyid):
gpg = gnupg.GPG(gnupghome=gpghome)
version = "1"
timestamp = strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
nonce = str(random.randint(10000, 18446744073709551616))
token = version + ";" + timestamp + ";" + nonce
sig = gpg.sign(token + "\n",
keyid=keyid,
detach=True, clearsign=True)
token += ";"
linectr=0
for line in iter(str(sig).splitlines()):
linectr+=1
if linectr < 4 or line.startswith('-') or not line:
continue
token += line
return token
if __name__ == '__main__':
token = makeToken("/home/ulfr/.gnupg",
"E60892BB9BD89A69F759A1A0A3D652173B763E8F")
r = requests.get("http://localhost:12345/api/v1/dashboard",
headers={'X-PGPAUTHORIZATION': token})
print token
print r.text
API endpoints
-------------
Endpoints
---------
The API root is at `/api/v1` by defualt. All the endpoints described below are
reachable behind the root. If you change the location of the API root, update
@ -1125,3 +946,183 @@ Geolocations are returned as CLJS items in this format:
When using the parameter `&report=geolocations`, the `search` endpoint of the
API will generate a list of geolocations from the results of the search.
Authentication with X-PGPAUTHORIZATION version 1
------------------------------------------------
Authenticating against the MIG API requires sending a PGP signed token in the
request header named `X-PGPAUTHORIZATION`. The key that signs the token must
belong to an active investigator. Construction of the token works as follows:
1. make a string named **str** composed of a version, a UTC timestamp in RFC3339 format
and a random nonce, each separated by semicolons. The current version is **1**
and may be upgraded in the future. The nonce value must be a positive integer.
**str=<VERSION>;<UTC TIMESTAMP RFC3339>;<NONCE>**
UTC is a hard requirement. The timestamp must end with the suffix **Z**
which indicates the UTC timezone. In bash, a correct timestamp can be
generated with the command `$ date -u +%Y-%m-%dT%H:%M:%SZ`.
An example string would look like: `1;2006-01-02T15:04:05Z;1825922807490630059`
The string must be terminated by a newline character, hexadecimal code `0x0a`.
.. code:: bash
$ hexdump -C <<< '1;2006-01-02T15:04:05Z;1825922807490630059'
00000000 31 3b 32 30 30 36 2d 30 31 2d 30 32 54 31 35 3a |1;2006-01-02T15:|
00000010 30 34 3a 30 35 5a 3b 31 38 32 35 39 32 32 38 30 |04:05Z;182592280|
00000020 37 34 39 30 36 33 30 30 35 39 0a |7490630059.|
0000002b
2. PGP sign **str** with the private key of the investigator. Armor and detach
the signature into **armoredSig**::
$ gpg -a --detach-sig <<< '1;2006-01-02T15:04:05Z;1825922807490630059'
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAABCAAGBQJUZ5psAAoJEKPWUhc7dj6PFd8IALWQS4x9Kzssww1pxc7uq9mg
JT/3jHLwAYPQV3ltqFcI5R2EGHo5DsXXjX6lfOc7DgbteB9UV+H++KG0oVUTTjuP
kncmFYmoBEDqbXju6EASBLyUlt3M43N9DmQaAaeoyW2gB0p0aEYRZoN3Cf0O0qhU
b3nnsCz6IyuBcQAZh1Jnmf7AMwRmXier8OflObQ9wJ1iYF9KCD0TgP1Z+kaCvMqC
PWQ5XaNaXn665V19mjAMicOtO9U3A/v4ApYyUSPyq0cuLrT8z/Z1vdjyeZVTaOM8
MhnoKfgBnegQnP+BPQZlWcjaBsquenC/joYRhq20nAEwSjZ1Nm7+qHo/DW0bYOA=
=4nrR
-----END PGP SIGNATURE-----
3. Create **sig** by taking **armoredSig** and removing the PGP headers, footers,
empty lines and newlines.
example: `iQEcBAABCAAGBQJUWPDpAAoJEKPWUhc7dj6PQdgH/0TRMOEAL4SL6v+JvixWtEGJzXBCqBpRBsygHAKT+m4AxwniVa9vr8vfWm14eFpZTGdlDx39Ko+tdFoHn5Z1yKEeQWEQYXqhneAnv0pYR1aIjXM8MY63TNePWBZxUerlRkjv2IH16/W5aBrbOctOxEs1BKuN2pd4Hgubr+2f43gcRcWW+Ww/5Fyg1lKzH8jP84uqiIT8wQOdBrwUkgRdSdfMQbYFjsgY57G+ZsMobNhhlFedgKuZShJCd+G1GlwsfZPsZOSLmVZahI7wjR3vckCJ66eff3e/xX7Gt0zGGa5i1dgH5Q6TSjRGRBE37FwD4C6fycUEuy9yKI7iFziw33Y==k6gT`
4. Create **token** by concatenating **str**, a semicolon, and **sig**.
**token=<str>;<sig>**
example: `1;2006-01-02T15:04:05Z;1825922807490630059;owEBYQGe/pANAwAIAaPWUhc7dj6...<truncated>`
5. Send **token** in the header named **X-PGPAUTHORIZATION** with the request::
$ curl -H 'X-PGPAUTHORIZATION: 1;2006-01-02T15:04:05Z;1825922807490630059;owEBYQGe/pANAwAIAaP...<truncated>' localhost:12345/api/v1/
6. The API verifies the version and validity period of the timestamp. By default, a
token will be rejected if its timestamp deviates from the server time by more
than 10 minutes. Administrators can configure this value. In effect, this
means a timestamp is valid for twice the duration of the window. By default,
that's 10 minutes before current server time, and 10 minutes after current
server time.
7. If the timestamp is valid, the API next verifies the signature against the data
and authenticates the user. Failure to verify the signature returns an error
with the HTTP code 401 Unauthorized.
8. The user is authorized, the API processes and answer the request.
Security implications
~~~~~~~~~~~~~~~~~~~~~
1. A token can be used an unlimited number of times within its validity period.
There is no check to guarantee that a token is only used once. It is
assumed that the token is transmitted over a secure channel such as HTTPS to
prevent token theft by a malicious user.
2. API clients and servers must use proper time synchronization for the timestamp
verification to work. A client or a server that has inaccurate time may not be
able to establish connections. We believe this requirement to be reasonable
considering the sensitivity of the API.
Example 1: invalid timestamp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The signature is valid but the timestamp is beyond the acceptable time window.
.. code:: bash
$ curl -H 'X-PGPAUTHORIZATION: 1;2006-01-02T15:04:05Z;1825922807490630059;iQEcB...<truncated>' http://localhost:12345/api/v1/
{
"collection": {
"error": {
"code": "6077873045059431424",
"message": "Authorization verification failed with error 'verifySignedToken() -> token timestamp is not within acceptable time limits'"
},
"href": "http://localhost:12345/api/v1/",
"template": {},
"version": "1.0"
}
}
Example 2: invalid signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The signature is not valid, or is signed by a key that the API does not
recognize.
.. code:: bash
$ curl -H 'X-PGPAUTHORIZATION: 1;2014-11-04T15:36:05Z;1825922807490630059;iQEcBA...<truncated>' http://localhost:12345/api/v1/
{
"collection": {
"error": {
"code": "6077875007260332032",
"message": "Authorization verification failed with error 'verifySignedToken() -> GetFingerprintFromSignature() -> openpgp: invalid signature: hash tag doesn't match'"
},
"href": "http://localhost:12345/api/v1/",
"template": {},
"version": "1.0"
}
}
Generating a token in Bash
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code::
$ token="1;$(date -u +%Y-%m-%dT%H:%M:%SZ);$RANDOM$RANDOM$RANDOM$RANDOM"; \
sig=$(gpg -a --detach-sig <<< $token |tail -8 |head -7 \
| sed ':a;N;$!ba;s/\n//g'); echo "X-PGPAUTHORIZATION: $token;$sig"
X-PGPAUTHORIZATION: 1;2014-11-04T19:13:37Z;13094113753132512760;iQEcBAA.....
Generating a token in Python
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: python
#!/usr/bin/env python
import os
import gnupg
from time import gmtime, strftime
import random
import requests
import json
def makeToken(gpghome, keyid):
gpg = gnupg.GPG(gnupghome=gpghome)
version = "1"
timestamp = strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
nonce = str(random.randint(10000, 18446744073709551616))
token = version + ";" + timestamp + ";" + nonce
sig = gpg.sign(token + "\n",
keyid=keyid,
detach=True, clearsign=True)
token += ";"
linectr=0
for line in iter(str(sig).splitlines()):
linectr+=1
if linectr < 4 or line.startswith('-') or not line:
continue
token += line
return token
if __name__ == '__main__':
token = makeToken("/home/ulfr/.gnupg",
"E60892BB9BD89A69F759A1A0A3D652173B763E8F")
r = requests.get("http://localhost:12345/api/v1/dashboard",
headers={'X-PGPAUTHORIZATION': token})
print token
print r.text

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {
@ -227,113 +229,13 @@ cite {
strong {
color: #C64216;
}
</style></head><body><h1>MIG API</h1><table><tr><td class="field-label">Author</td><td>Julien Vehent &lt;<a class="reference external" href="mailto:jvehent@mozilla.com">jvehent@mozilla.com</a>&gt;</td></tr></table><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#authentication-with-x-pgpauthorization-version-1" id="id1">1   Authentication with X-PGPAUTHORIZATION version 1</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#security-implications" id="id2">1.1   Security implications</a></p></li><li><p><a class="reference internal" href="#example-1-invalid-timestamp" id="id3">1.2   Example 1: invalid timestamp</a></p></li><li><p><a class="reference internal" href="#example-2-invalid-signature" id="id4">1.3   Example 2: invalid signature</a></p></li><li><p><a class="reference internal" href="#generating-a-token-in-bash" id="id5">1.4   Generating a token in Bash</a></p></li><li><p><a class="reference internal" href="#generating-a-token-in-python" id="id6">1.5   Generating a token in Python</a></p></li></ul></li><li><p><a class="reference internal" href="#api-endpoints" id="id7">2   API endpoints</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#get-api-v1-heartbeat" id="id8">2.1   GET /api/v1/heartbeat</a></p></li><li><p><a class="reference internal" href="#get-api-v1-ip" id="id9">2.2   GET /api/v1/ip</a></p></li><li><p><a class="reference internal" href="#get-api-v1-dashboard" id="id10">2.3   GET /api/v1/dashboard</a></p></li><li><p><a class="reference internal" href="#get-api-v1-action" id="id11">2.4   GET /api/v1/action</a></p></li><li><p><a class="reference internal" href="#post-api-v1-action-create" id="id12">2.5   POST /api/v1/action/create/</a></p></li><li><p><a class="reference internal" href="#get-api-v1-agent" id="id13">2.6   GET /api/v1/agent</a></p></li><li><p><a class="reference internal" href="#get-api-v1-command" id="id14">2.7   GET /api/v1/command</a></p></li><li><p><a class="reference internal" href="#get-api-v1-investigator" id="id15">2.8   GET /api/v1/investigator</a></p></li><li><p><a class="reference internal" href="#post-api-v1-investigator-create" id="id16">2.9   POST /api/v1/investigator/create/</a></p></li><li><p><a class="reference internal" href="#post-api-v1-investigator-update" id="id17">2.10   POST /api/v1/investigator/update/</a></p></li><li><p><a class="reference internal" href="#get-api-v1-search" id="id18">2.11   GET /api/v1/search</a></p></li></ul></li><li><p><a class="reference internal" href="#data-transformation" id="id19">3   Data transformation</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#compliance-items" id="id20">3.1   Compliance Items</a></p></li><li><p><a class="reference internal" href="#geolocations" id="id21">3.2   Geolocations</a></p></li></ul></li></ul></div><p>Interactions between an investigator (a human being) and the MIG platform are
</style></head><body><h1>MIG API</h1><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#endpoints" id="id1">1   Endpoints</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#get-api-v1-heartbeat" id="id2">1.1   GET /api/v1/heartbeat</a></p></li><li><p><a class="reference internal" href="#get-api-v1-ip" id="id3">1.2   GET /api/v1/ip</a></p></li><li><p><a class="reference internal" href="#get-api-v1-dashboard" id="id4">1.3   GET /api/v1/dashboard</a></p></li><li><p><a class="reference internal" href="#get-api-v1-action" id="id5">1.4   GET /api/v1/action</a></p></li><li><p><a class="reference internal" href="#post-api-v1-action-create" id="id6">1.5   POST /api/v1/action/create/</a></p></li><li><p><a class="reference internal" href="#get-api-v1-agent" id="id7">1.6   GET /api/v1/agent</a></p></li><li><p><a class="reference internal" href="#get-api-v1-command" id="id8">1.7   GET /api/v1/command</a></p></li><li><p><a class="reference internal" href="#get-api-v1-investigator" id="id9">1.8   GET /api/v1/investigator</a></p></li><li><p><a class="reference internal" href="#post-api-v1-investigator-create" id="id10">1.9   POST /api/v1/investigator/create/</a></p></li><li><p><a class="reference internal" href="#post-api-v1-investigator-update" id="id11">1.10   POST /api/v1/investigator/update/</a></p></li><li><p><a class="reference internal" href="#get-api-v1-search" id="id12">1.11   GET /api/v1/search</a></p></li></ul></li><li><p><a class="reference internal" href="#data-transformation" id="id13">2   Data transformation</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#compliance-items" id="id14">2.1   Compliance Items</a></p></li><li><p><a class="reference internal" href="#geolocations" id="id15">2.2   Geolocations</a></p></li></ul></li><li><p><a class="reference internal" href="#authentication-with-x-pgpauthorization-version-1" id="id16">3   Authentication with X-PGPAUTHORIZATION version 1</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#security-implications" id="id17">3.1   Security implications</a></p></li><li><p><a class="reference internal" href="#example-1-invalid-timestamp" id="id18">3.2   Example 1: invalid timestamp</a></p></li><li><p><a class="reference internal" href="#example-2-invalid-signature" id="id19">3.3   Example 2: invalid signature</a></p></li><li><p><a class="reference internal" href="#generating-a-token-in-bash" id="id20">3.4   Generating a token in Bash</a></p></li><li><p><a class="reference internal" href="#generating-a-token-in-python" id="id21">3.5   Generating a token in Python</a></p></li></ul></li></ul></div><p>Interactions between an investigator (a human being) and the MIG platform are
performed through a REST API. The API exposes functions to create actions,
retrieve results, and generally monitor the activity of the agents.</p><p>The API follows the core principles of REST, and provides discoverable
endpoints. API responses follows the <strong>cljs</strong> format defined in
<a class="reference external" href="http://amundsen.com/media-types/collection/">Collection+JSON - Hypermedia Type</a>.</p><section id="authentication-with-x-pgpauthorization-version-1"><header><h2><a href="#id1">1   Authentication with X-PGPAUTHORIZATION version 1</a></h2></header><p>Authenticating against the MIG API requires sending a PGP signed token in the
request header named <cite>X-PGPAUTHORIZATION</cite>. The key that signs the token must
belong to an active investigator. Construction of the token works as follows:</p><ol class="arabic"><li><p>make a string named <strong>str</strong> composed of a version, a UTC timestamp in RFC3339 format
and a random nonce, each separated by semicolons. The current version is <strong>1</strong>
and may be upgraded in the future. The nonce value must be a positive integer.</p><p><strong>str=&lt;VERSION&gt;;&lt;UTC TIMESTAMP RFC3339&gt;;&lt;NONCE&gt;</strong></p><p>UTC is a hard requirement. The timestamp must end with the suffix <strong>Z</strong>
which indicates the UTC timezone. In bash, a correct timestamp can be
generated with the command <cite>$ date -u +%Y-%m-%dT%H:%M:%SZ</cite>.</p><p>An example string would look like: <cite>1;2006-01-02T15:04:05Z;1825922807490630059</cite></p><p>The string must be terminated by a newline character, hexadecimal code <cite>0x0a</cite>.</p></li></ol><pre><code class="code bash"><span class="name variable">$ </span>hexdump -C <span class="operator">&lt;&lt;&lt;</span> <span class="literal string single">'1;2006-01-02T15:04:05Z;1825922807490630059'</span>
<span class="literal number">00000000</span> <span class="literal number">31</span> 3b <span class="literal number">32</span> <span class="literal number">30</span> <span class="literal number">30</span> <span class="literal number">36</span> 2d <span class="literal number">30</span> <span class="literal number">31</span> 2d <span class="literal number">30</span> <span class="literal number">32</span> <span class="literal number">54</span> <span class="literal number">31</span> <span class="literal number">35</span> 3a <span class="punctuation">|</span>1<span class="punctuation">;</span>2006-01-02T15:<span class="punctuation">|</span>
<span class="literal number">00000010</span> <span class="literal number">30</span> <span class="literal number">34</span> 3a <span class="literal number">30</span> <span class="literal number">35</span> 5a 3b <span class="literal number">31</span> <span class="literal number">38</span> <span class="literal number">32</span> <span class="literal number">35</span> <span class="literal number">39</span> <span class="literal number">32</span> <span class="literal number">32</span> <span class="literal number">38</span> <span class="literal number">30</span> <span class="punctuation">|</span>04:05Z<span class="punctuation">;</span>182592280<span class="punctuation">|</span>
<span class="literal number">00000020</span> <span class="literal number">37</span> <span class="literal number">34</span> <span class="literal number">39</span> <span class="literal number">30</span> <span class="literal number">36</span> <span class="literal number">33</span> <span class="literal number">30</span> <span class="literal number">30</span> <span class="literal number">35</span> <span class="literal number">39</span> 0a <span class="punctuation">|</span>7490630059.<span class="punctuation">|</span>
0000002b</code></pre><ol class="arabic" start="2"><li><p>PGP sign <strong>str</strong> with the private key of the investigator. Armor and detach
the signature into <strong>armoredSig</strong>:</p><pre>$ gpg -a --detach-sig &lt;&lt;&lt; '1;2006-01-02T15:04:05Z;1825922807490630059'
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAABCAAGBQJUZ5psAAoJEKPWUhc7dj6PFd8IALWQS4x9Kzssww1pxc7uq9mg
JT/3jHLwAYPQV3ltqFcI5R2EGHo5DsXXjX6lfOc7DgbteB9UV+H++KG0oVUTTjuP
kncmFYmoBEDqbXju6EASBLyUlt3M43N9DmQaAaeoyW2gB0p0aEYRZoN3Cf0O0qhU
b3nnsCz6IyuBcQAZh1Jnmf7AMwRmXier8OflObQ9wJ1iYF9KCD0TgP1Z+kaCvMqC
PWQ5XaNaXn665V19mjAMicOtO9U3A/v4ApYyUSPyq0cuLrT8z/Z1vdjyeZVTaOM8
MhnoKfgBnegQnP+BPQZlWcjaBsquenC/joYRhq20nAEwSjZ1Nm7+qHo/DW0bYOA=
=4nrR
-----END PGP SIGNATURE-----</pre></li><li><p>Create <strong>sig</strong> by taking <strong>armoredSig</strong> and removing the PGP headers, footers,
empty lines and newlines.</p><blockquote><p>example: <cite>iQEcBAABCAAGBQJUWPDpAAoJEKPWUhc7dj6PQdgH/0TRMOEAL4SL6v+JvixWtEGJzXBCqBpRBsygHAKT+m4AxwniVa9vr8vfWm14eFpZTGdlDx39Ko+tdFoHn5Z1yKEeQWEQYXqhneAnv0pYR1aIjXM8MY63TNePWBZxUerlRkjv2IH16/W5aBrbOctOxEs1BKuN2pd4Hgubr+2f43gcRcWW+Ww/5Fyg1lKzH8jP84uqiIT8wQOdBrwUkgRdSdfMQbYFjsgY57G+ZsMobNhhlFedgKuZShJCd+G1GlwsfZPsZOSLmVZahI7wjR3vckCJ66eff3e/xX7Gt0zGGa5i1dgH5Q6TSjRGRBE37FwD4C6fycUEuy9yKI7iFziw33Y==k6gT</cite></p></blockquote></li><li><p>Create <strong>token</strong> by concatenating <strong>str</strong>, a semicolon, and <strong>sig</strong>.
<strong>token=&lt;str&gt;;&lt;sig&gt;</strong>
example: <cite>1;2006-01-02T15:04:05Z;1825922807490630059;owEBYQGe/pANAwAIAaPWUhc7dj6...&lt;truncated&gt;</cite></p></li><li><p>Send <strong>token</strong> in the header named <strong>X-PGPAUTHORIZATION</strong> with the request:</p><pre>$ curl -H 'X-PGPAUTHORIZATION: 1;2006-01-02T15:04:05Z;1825922807490630059;owEBYQGe/pANAwAIAaP...&lt;truncated&gt;' localhost:12345/api/v1/</pre></li><li><p>The API verifies the version and validity period of the timestamp. By default, a
token will be rejected if its timestamp deviates from the server time by more
than 10 minutes. Administrators can configure this value. In effect, this
means a timestamp is valid for twice the duration of the window. By default,
that's 10 minutes before current server time, and 10 minutes after current
server time.</p></li><li><p>If the timestamp is valid, the API next verifies the signature against the data
and authenticates the user. Failure to verify the signature returns an error
with the HTTP code 401 Unauthorized.</p></li><li><p>The user is authorized, the API processes and answer the request.</p></li></ol><section id="security-implications"><header><h3><a href="#id2">1.1   Security implications</a></h3></header><ol class="arabic"><li><p>A token can be used an unlimited number of times within its validity period.
There is no check to guarantee that a token is only used once. It is
assumed that the token is transmitted over a secure channel such as HTTPS to
prevent token theft by a malicious user.</p></li><li><p>API clients and servers must use proper time synchronization for the timestamp
verification to work. A client or a server that has inaccurate time may not be
able to establish connections. We believe this requirement to be reasonable
considering the sensitivity of the API.</p></li></ol></section><section id="example-1-invalid-timestamp"><header><h3><a href="#id3">1.2   Example 1: invalid timestamp</a></h3></header><p>The signature is valid but the timestamp is beyond the acceptable time window.</p><pre><code class="code bash"><span class="name variable">$ </span>curl -H <span class="literal string single">'X-PGPAUTHORIZATION: 1;2006-01-02T15:04:05Z;1825922807490630059;iQEcB...&lt;truncated&gt;'</span> http://localhost:12345/api/v1/
<span class="operator">{</span>
<span class="literal string double">"collection"</span>: <span class="operator">{</span>
<span class="literal string double">"error"</span>: <span class="operator">{</span>
<span class="literal string double">"code"</span>: <span class="literal string double">"6077873045059431424"</span>,
<span class="literal string double">"message"</span>: <span class="literal string double">"Authorization verification failed with error 'verifySignedToken() -&gt; token timestamp is not within acceptable time limits'"</span>
<span class="operator">}</span>,
<span class="literal string double">"href"</span>: <span class="literal string double">"http://localhost:12345/api/v1/"</span>,
<span class="literal string double">"template"</span>: <span class="operator">{}</span>,
<span class="literal string double">"version"</span>: <span class="literal string double">"1.0"</span>
<span class="operator">}</span>
<span class="operator">}</span></code></pre></section><section id="example-2-invalid-signature"><header><h3><a href="#id4">1.3   Example 2: invalid signature</a></h3></header><p>The signature is not valid, or is signed by a key that the API does not
recognize.</p><pre><code class="code bash"><span class="name variable">$ </span>curl -H <span class="literal string single">'X-PGPAUTHORIZATION: 1;2014-11-04T15:36:05Z;1825922807490630059;iQEcBA...&lt;truncated&gt;'</span> http://localhost:12345/api/v1/
<span class="operator">{</span>
<span class="literal string double">"collection"</span>: <span class="operator">{</span>
<span class="literal string double">"error"</span>: <span class="operator">{</span>
<span class="literal string double">"code"</span>: <span class="literal string double">"6077875007260332032"</span>,
<span class="literal string double">"message"</span>: <span class="literal string double">"Authorization verification failed with error 'verifySignedToken() -&gt; GetFingerprintFromSignature() -&gt; openpgp: invalid signature: hash tag doesn't match'"</span>
<span class="operator">}</span>,
<span class="literal string double">"href"</span>: <span class="literal string double">"http://localhost:12345/api/v1/"</span>,
<span class="literal string double">"template"</span>: <span class="operator">{}</span>,
<span class="literal string double">"version"</span>: <span class="literal string double">"1.0"</span>
<span class="operator">}</span>
<span class="operator">}</span></code></pre></section><section id="generating-a-token-in-bash"><header><h3><a href="#id5">1.4   Generating a token in Bash</a></h3></header><pre><code class="code">$ token="1;$(date -u +%Y-%m-%dT%H:%M:%SZ);$RANDOM$RANDOM$RANDOM$RANDOM"; \
sig=$(gpg -a --detach-sig &lt;&lt;&lt; $token |tail -8 |head -7 \
| sed ':a;N;$!ba;s/\n//g'); echo "X-PGPAUTHORIZATION: $token;$sig"
X-PGPAUTHORIZATION: 1;2014-11-04T19:13:37Z;13094113753132512760;iQEcBAA.....</code></pre></section><section id="generating-a-token-in-python"><header><h3><a href="#id6">1.5   Generating a token in Python</a></h3></header><pre><code class="code python"><span class="comment">#!/usr/bin/env python</span>
<span class="keyword namespace">import</span> <span class="name namespace">os</span>
<span class="keyword namespace">import</span> <span class="name namespace">gnupg</span>
<span class="keyword namespace">from</span> <span class="name namespace">time</span> <span class="keyword namespace">import</span> <span class="name">gmtime</span><span class="punctuation">,</span> <span class="name">strftime</span>
<span class="keyword namespace">import</span> <span class="name namespace">random</span>
<span class="keyword namespace">import</span> <span class="name namespace">requests</span>
<span class="keyword namespace">import</span> <span class="name namespace">json</span>
<span class="keyword">def</span> <span class="name function">makeToken</span><span class="punctuation">(</span><span class="name">gpghome</span><span class="punctuation">,</span> <span class="name">keyid</span><span class="punctuation">):</span>
<span class="name">gpg</span> <span class="operator">=</span> <span class="name">gnupg</span><span class="operator">.</span><span class="name">GPG</span><span class="punctuation">(</span><span class="name">gnupghome</span><span class="operator">=</span><span class="name">gpghome</span><span class="punctuation">)</span>
<span class="name">version</span> <span class="operator">=</span> <span class="literal string">"1"</span>
<span class="name">timestamp</span> <span class="operator">=</span> <span class="name">strftime</span><span class="punctuation">(</span><span class="literal string">"%Y-%m-</span><span class="literal string interpol">%d</span><span class="literal string">T%H:%M:%SZ"</span><span class="punctuation">,</span> <span class="name">gmtime</span><span class="punctuation">())</span>
<span class="name">nonce</span> <span class="operator">=</span> <span class="name builtin">str</span><span class="punctuation">(</span><span class="name">random</span><span class="operator">.</span><span class="name">randint</span><span class="punctuation">(</span><span class="literal number integer">10000</span><span class="punctuation">,</span> <span class="literal number integer">18446744073709551616</span><span class="punctuation">))</span>
<span class="name">token</span> <span class="operator">=</span> <span class="name">version</span> <span class="operator">+</span> <span class="literal string">";"</span> <span class="operator">+</span> <span class="name">timestamp</span> <span class="operator">+</span> <span class="literal string">";"</span> <span class="operator">+</span> <span class="name">nonce</span>
<span class="name">sig</span> <span class="operator">=</span> <span class="name">gpg</span><span class="operator">.</span><span class="name">sign</span><span class="punctuation">(</span><span class="name">token</span> <span class="operator">+</span> <span class="literal string">"</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span>
<span class="name">keyid</span><span class="operator">=</span><span class="name">keyid</span><span class="punctuation">,</span>
<span class="name">detach</span><span class="operator">=</span><span class="name builtin pseudo">True</span><span class="punctuation">,</span> <span class="name">clearsign</span><span class="operator">=</span><span class="name builtin pseudo">True</span><span class="punctuation">)</span>
<span class="name">token</span> <span class="operator">+=</span> <span class="literal string">";"</span>
<span class="name">linectr</span><span class="operator">=</span><span class="literal number integer">0</span>
<span class="keyword">for</span> <span class="name">line</span> <span class="operator word">in</span> <span class="name builtin">iter</span><span class="punctuation">(</span><span class="name builtin">str</span><span class="punctuation">(</span><span class="name">sig</span><span class="punctuation">)</span><span class="operator">.</span><span class="name">splitlines</span><span class="punctuation">()):</span>
<span class="name">linectr</span><span class="operator">+=</span><span class="literal number integer">1</span>
<span class="keyword">if</span> <span class="name">linectr</span> <span class="operator">&lt;</span> <span class="literal number integer">4</span> <span class="operator word">or</span> <span class="name">line</span><span class="operator">.</span><span class="name">startswith</span><span class="punctuation">(</span><span class="literal string">'-'</span><span class="punctuation">)</span> <span class="operator word">or</span> <span class="operator word">not</span> <span class="name">line</span><span class="punctuation">:</span>
<span class="keyword">continue</span>
<span class="name">token</span> <span class="operator">+=</span> <span class="name">line</span>
<span class="keyword">return</span> <span class="name">token</span>
<span class="keyword">if</span> <span class="name">__name__</span> <span class="operator">==</span> <span class="literal string">'__main__'</span><span class="punctuation">:</span>
<span class="name">token</span> <span class="operator">=</span> <span class="name">makeToken</span><span class="punctuation">(</span><span class="literal string">"/home/ulfr/.gnupg"</span><span class="punctuation">,</span>
<span class="literal string">"E60892BB9BD89A69F759A1A0A3D652173B763E8F"</span><span class="punctuation">)</span>
<span class="name">r</span> <span class="operator">=</span> <span class="name">requests</span><span class="operator">.</span><span class="name">get</span><span class="punctuation">(</span><span class="literal string">"http://localhost:12345/api/v1/dashboard"</span><span class="punctuation">,</span>
<span class="name">headers</span><span class="operator">=</span><span class="punctuation">{</span><span class="literal string">'X-PGPAUTHORIZATION'</span><span class="punctuation">:</span> <span class="name">token</span><span class="punctuation">})</span>
<span class="keyword">print</span> <span class="name">token</span>
<span class="keyword">print</span> <span class="name">r</span><span class="operator">.</span><span class="name">text</span></code></pre></section></section><section id="api-endpoints"><header><h2><a href="#id7">2   API endpoints</a></h2></header><p>The API root is at <cite>/api/v1</cite> by defualt. All the endpoints described below are
<a class="reference external" href="http://amundsen.com/media-types/collection/">Collection+JSON - Hypermedia Type</a>.</p><section id="endpoints"><header><h2><a href="#id1">1   Endpoints</a></h2></header><p>The API root is at <cite>/api/v1</cite> by defualt. All the endpoints described below are
reachable behind the root. If you change the location of the API root, update
the query paths accordingly.</p><section id="get-api-v1-heartbeat"><header><h3><a href="#id8">2.1   GET /api/v1/heartbeat</a></h3></header><ul><li><p>Description: basic endpoint that returns a HTTP 200</p></li><li><p>Parameters: none</p></li><li><p>Authentication: none</p></li><li><p>Response Code: 200 OK</p></li><li><p>Reponse: Collection+JSON</p></li></ul><pre><code class="code json"><span class="punctuation">{</span>
the query paths accordingly.</p><section id="get-api-v1-heartbeat"><header><h3><a href="#id2">1.1   GET /api/v1/heartbeat</a></h3></header><ul><li><p>Description: basic endpoint that returns a HTTP 200</p></li><li><p>Parameters: none</p></li><li><p>Authentication: none</p></li><li><p>Response Code: 200 OK</p></li><li><p>Reponse: Collection+JSON</p></li></ul><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"collection"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"error"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
<span class="name tag">"href"</span><span class="punctuation">:</span> <span class="literal string double">"https://api.mig.mozilla.org/api/v1/heartbeat"</span><span class="punctuation">,</span>
@ -351,9 +253,9 @@ the query paths accordingly.</p><section id="get-api-v1-heartbeat"><header><h3><
<span class="name tag">"template"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
<span class="name tag">"version"</span><span class="punctuation">:</span> <span class="literal string double">"1.0"</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span></code></pre></section><section id="get-api-v1-ip"><header><h3><a href="#id9">2.2   GET /api/v1/ip</a></h3></header><ul><li><p>Description: basic endpoint that returns the public IP of the caller. If the
<span class="punctuation">}</span></code></pre></section><section id="get-api-v1-ip"><header><h3><a href="#id3">1.2   GET /api/v1/ip</a></h3></header><ul><li><p>Description: basic endpoint that returns the public IP of the caller. If the
API is behind a load balancer, it returns the value of X-Forwarded-For.</p></li><li><p>Parameters: none</p></li><li><p>Authentication: none</p></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Text</p></li></ul><pre><code class="code bash"><span class="name variable">$ </span>curl https://api.mig.mozilla.org/api/v1/ip
108.36.248.44</code></pre></section><section id="get-api-v1-dashboard"><header><h3><a href="#id10">2.3   GET /api/v1/dashboard</a></h3></header><ul><li><p>Description: returns a status dashboard with counters of active and idle
108.36.248.44</code></pre></section><section id="get-api-v1-dashboard"><header><h3><a href="#id4">1.3   GET /api/v1/dashboard</a></h3></header><ul><li><p>Description: returns a status dashboard with counters of active and idle
agents, and a list of the last 10 actions ran.</p></li><li><p>Parameters: none</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li></ul><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"collection"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"error"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
@ -526,7 +428,7 @@ agents, and a list of the last 10 actions ran.</p></li><li><p>Parameters: none</
<span class="name tag">"template"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
<span class="name tag">"version"</span><span class="punctuation">:</span> <span class="literal string double">"1.0"</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span></code></pre></section><section id="get-api-v1-action"><header><h3><a href="#id11">2.4   GET /api/v1/action</a></h3></header><ul><li><p>Description: retrieve an action by its ID. Include links to related commands.</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters:</dt><dd><ul><li><p><cite>actionid</cite>: a uint64 that identifies an action by its ID</p></li></ul></dd></dl></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li></ul><pre><code class="code json"><span class="punctuation">{</span>
<span class="punctuation">}</span></code></pre></section><section id="get-api-v1-action"><header><h3><a href="#id5">1.4   GET /api/v1/action</a></h3></header><ul><li><p>Description: retrieve an action by its ID. Include links to related commands.</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters:</dt><dd><ul><li><p><cite>actionid</cite>: a uint64 that identifies an action by its ID</p></li></ul></dd></dl></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li></ul><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"collection"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"error"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
<span class="name tag">"href"</span><span class="punctuation">:</span> <span class="literal string double">"https://api.mig.example.net/api/v1/action?actionid=6115472790658567168"</span><span class="punctuation">,</span>
@ -639,7 +541,7 @@ agents, and a list of the last 10 actions ran.</p></li><li><p>Parameters: none</
<span class="name tag">"template"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
<span class="name tag">"version"</span><span class="punctuation">:</span> <span class="literal string double">"1.0"</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span></code></pre></section><section id="post-api-v1-action-create"><header><h3><a href="#id12">2.5   POST /api/v1/action/create/</a></h3></header><ul><li><p>Description: send a signed action to the API for submission to the scheduler.</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters: (POST body)</dt><dd><ul><li><p><cite>action</cite>: a signed action in JSON format</p></li></ul></dd></dl></li><li><p>Response Code: 202 Accepted</p></li><li><p>Response: Collection+JSON</p></li></ul></section><section id="get-api-v1-agent"><header><h3><a href="#id13">2.6   GET /api/v1/agent</a></h3></header><ul><li><p>Description: retrieve an agent by its ID</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters:</dt><dd><ul><li><p><cite>agentid</cite>: a uint64 that identifies an agent by its ID</p></li></ul></dd></dl></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li></ul><pre><code class="code json"><span class="punctuation">{</span>
<span class="punctuation">}</span></code></pre></section><section id="post-api-v1-action-create"><header><h3><a href="#id6">1.5   POST /api/v1/action/create/</a></h3></header><ul><li><p>Description: send a signed action to the API for submission to the scheduler.</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters: (POST body)</dt><dd><ul><li><p><cite>action</cite>: a signed action in JSON format</p></li></ul></dd></dl></li><li><p>Response Code: 202 Accepted</p></li><li><p>Response: Collection+JSON</p></li></ul></section><section id="get-api-v1-agent"><header><h3><a href="#id7">1.6   GET /api/v1/agent</a></h3></header><ul><li><p>Description: retrieve an agent by its ID</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters:</dt><dd><ul><li><p><cite>agentid</cite>: a uint64 that identifies an agent by its ID</p></li></ul></dd></dl></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li></ul><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"collection"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"error"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
<span class="name tag">"href"</span><span class="punctuation">:</span> <span class="literal string double">"https://api.mig.example.net/api/v1/agent?agentid=1423779015943326976"</span><span class="punctuation">,</span>
@ -681,7 +583,7 @@ agents, and a list of the last 10 actions ran.</p></li><li><p>Parameters: none</
<span class="name tag">"template"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
<span class="name tag">"version"</span><span class="punctuation">:</span> <span class="literal string double">"1.0"</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span></code></pre></section><section id="get-api-v1-command"><header><h3><a href="#id14">2.7   GET /api/v1/command</a></h3></header><ul><li><p>Description: retrieve a command by its ID. Include link to related action.</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters:</dt><dd><ul><li><p><cite>commandid</cite>: a uint64 that identifies a command by its ID</p></li></ul></dd></dl></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li></ul><pre><code class="code bash"><span class="operator">{</span>
<span class="punctuation">}</span></code></pre></section><section id="get-api-v1-command"><header><h3><a href="#id8">1.7   GET /api/v1/command</a></h3></header><ul><li><p>Description: retrieve a command by its ID. Include link to related action.</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters:</dt><dd><ul><li><p><cite>commandid</cite>: a uint64 that identifies a command by its ID</p></li></ul></dd></dl></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li></ul><pre><code class="code bash"><span class="operator">{</span>
<span class="literal string double">"collection"</span>: <span class="operator">{</span>
<span class="literal string double">"error"</span>: <span class="operator">{}</span>,
<span class="literal string double">"href"</span>: <span class="literal string double">"https://api.mig.example.net/api/v1/command?commandid=1424700180901330688"</span>,
@ -896,7 +798,7 @@ agents, and a list of the last 10 actions ran.</p></li><li><p>Parameters: none</
"</span>template<span class="literal string double">": {},
"</span>version<span class="literal string double">": "</span>1.0<span class="literal string double">"
}
}</span></code></pre></section><section id="get-api-v1-investigator"><header><h3><a href="#id15">2.8   GET /api/v1/investigator</a></h3></header><ul><li><p>Description: retrieve an investigator by its ID. Include link to the
}</span></code></pre></section><section id="get-api-v1-investigator"><header><h3><a href="#id9">1.8   GET /api/v1/investigator</a></h3></header><ul><li><p>Description: retrieve an investigator by its ID. Include link to the
investigator's action history.</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters:</dt><dd><ul><li><p><cite>investigatorid</cite>: a uint64 that identifies a command by its ID</p></li></ul></dd></dl></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li></ul><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"collection"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"error"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
@ -929,8 +831,8 @@ investigator's action history.</p></li><li><p>Authentication: X-PGPAUTHORIZATION
<span class="name tag">"template"</span><span class="punctuation">:</span> <span class="punctuation">{},</span>
<span class="name tag">"version"</span><span class="punctuation">:</span> <span class="literal string double">"1.0"</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span></code></pre></section><section id="post-api-v1-investigator-create"><header><h3><a href="#id16">2.9   POST /api/v1/investigator/create/</a></h3></header><ul><li><p>Description: create a new investigator in the database</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters: (POST body)</dt><dd><ul><li><p><cite>name</cite>: string that represents the full name</p></li><li><p><cite>publickey</cite>: armored GPG public key</p></li></ul></dd></dl></li><li><p>Response Code: 201 Created</p></li><li><p>Response: Collection+JSON</p></li><li><p>Example: (without authentication)</p></li></ul><pre><code class="code bash"><span class="name variable">$ </span>gpg --export -a --export-options <span class="name builtin">export</span>-minimal bob_kelso@example.net &gt; /tmp/bobpubkey
<span class="name variable">$ </span>curl -iv -F <span class="literal string double">"name=Bob Kelso"</span> -F <span class="name variable">publickey</span><span class="operator">=</span>@/tmp/pubkey https://api.mig.example.net/api/v1/investigator/create/</code></pre></section><section id="post-api-v1-investigator-update"><header><h3><a href="#id17">2.10   POST /api/v1/investigator/update/</a></h3></header><ul><li><p>Description: update an existing investigator in the database</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters: (POST body)</dt><dd><ul><li><p><cite>id</cite>: investigator id, to identify the target investigator</p></li><li><p><cite>status</cite>: new status of the investigator, to be updated</p></li></ul></dd></dl></li><li><p>Response Code: 201 Created</p></li><li><p>Response: Collection+JSON</p></li><li><p>Example: (without authentication)</p></li></ul><pre><code class="code bash"><span class="name variable">$ </span>curl -iv -X POST -d <span class="name variable">id</span><span class="operator">=</span><span class="literal number">1234</span> -d <span class="name variable">status</span><span class="operator">=</span>disabled https://api.mig.example.net/api/v1/investigator/update/</code></pre></section><section id="get-api-v1-search"><header><h3><a href="#id18">2.11   GET /api/v1/search</a></h3></header><ul><li><p>Description: search for actions, commands, agents or investigators.</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li><li><dl><dt>Parameters:</dt><dd><ul><li><p><cite>type</cite>: define the type of item returned by the search.
<span class="punctuation">}</span></code></pre></section><section id="post-api-v1-investigator-create"><header><h3><a href="#id10">1.9   POST /api/v1/investigator/create/</a></h3></header><ul><li><p>Description: create a new investigator in the database</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters: (POST body)</dt><dd><ul><li><p><cite>name</cite>: string that represents the full name</p></li><li><p><cite>publickey</cite>: armored GPG public key</p></li></ul></dd></dl></li><li><p>Response Code: 201 Created</p></li><li><p>Response: Collection+JSON</p></li><li><p>Example: (without authentication)</p></li></ul><pre><code class="code bash"><span class="name variable">$ </span>gpg --export -a --export-options <span class="name builtin">export</span>-minimal bob_kelso@example.net &gt; /tmp/bobpubkey
<span class="name variable">$ </span>curl -iv -F <span class="literal string double">"name=Bob Kelso"</span> -F <span class="name variable">publickey</span><span class="operator">=</span>@/tmp/pubkey https://api.mig.example.net/api/v1/investigator/create/</code></pre></section><section id="post-api-v1-investigator-update"><header><h3><a href="#id11">1.10   POST /api/v1/investigator/update/</a></h3></header><ul><li><p>Description: update an existing investigator in the database</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><dl><dt>Parameters: (POST body)</dt><dd><ul><li><p><cite>id</cite>: investigator id, to identify the target investigator</p></li><li><p><cite>status</cite>: new status of the investigator, to be updated</p></li></ul></dd></dl></li><li><p>Response Code: 201 Created</p></li><li><p>Response: Collection+JSON</p></li><li><p>Example: (without authentication)</p></li></ul><pre><code class="code bash"><span class="name variable">$ </span>curl -iv -X POST -d <span class="name variable">id</span><span class="operator">=</span><span class="literal number">1234</span> -d <span class="name variable">status</span><span class="operator">=</span>disabled https://api.mig.example.net/api/v1/investigator/update/</code></pre></section><section id="get-api-v1-search"><header><h3><a href="#id12">1.11   GET /api/v1/search</a></h3></header><ul><li><p>Description: search for actions, commands, agents or investigators.</p></li><li><p>Authentication: X-PGPAUTHORIZATION</p></li><li><p>Response Code: 200 OK</p></li><li><p>Response: Collection+JSON</p></li><li><dl><dt>Parameters:</dt><dd><ul><li><p><cite>type</cite>: define the type of item returned by the search.
Valid types are: <cite>action</cite>, <cite>command</cite>, <cite>agent</cite> or <cite>investigator</cite>.</p><blockquote><ul><li><p><cite>action</cite>: (default) return a list of actions</p></li><li><p><cite>command</cite>: return a list of commands</p></li><li><p><cite>agent</cite>: return a list of agents that have shown activity</p></li><li><p><cite>investigator</cite>: return a list of investigators that have show activity</p></li></ul></blockquote></li><li><p><cite>actionid</cite>: filter results on numeric action ID</p></li><li><p><cite>actionname</cite>: filter results on string action name, accept <cite>ILIKE</cite> pattern</p></li><li><p><cite>after</cite>: return results recorded after this RFC3339 date. If not set,
return results for last 10 years. Impact on search depends on the type:</p><blockquote><ul><li><p><cite>action</cite>: select actions with a <cite>validfrom</cite> date greater than <cite>after</cite>.</p></li><li><p><cite>agent</cite>: select agents that have sent a heartbeat since <cite>after</cite>.</p></li><li><p><cite>command</cite>: select commands with a <cite>starttime</cite> date greated than <cite>after</cite>.</p></li><li><p><cite>investigator</cite>: select investigators with a <cite>createdat</cite> date greater
than <cite>after</cite>.</p></li></ul></blockquote></li><li><p><cite>agentid</cite>: filter results on the agent ID</p></li><li><p><cite>agentname</cite>: filter results on string agent name, accept <cite>ILIKE</cite> pattern</p></li><li><p><cite>agentversion</cite>: filter results on agent version string, accept <cite>ILIKE</cite> pattern</p></li><li><p><cite>before</cite>: return results recorded before this RFC3339 date. If not set,
@ -948,8 +850,8 @@ parameters, the value is used as a SQL <cite>ILIKE</cite> search pattern, as des
hours. For more information on the <cite>compliance</cite> format, see section 2.</p><pre><code class="code bash">/api/v1/search?type<span class="operator">=</span><span class="name builtin">command</span><span class="punctuation">&amp;</span><span class="name variable">threatfamily</span><span class="operator">=</span>compliance<span class="punctuation">&amp;</span><span class="name variable">status</span><span class="operator">=</span><span class="keyword">done</span>
<span class="punctuation">&amp;</span><span class="name variable">report</span><span class="operator">=</span>complianceitems<span class="punctuation">&amp;</span><span class="name variable">limit</span><span class="operator">=</span>100000
<span class="punctuation">&amp;</span><span class="name variable">after</span><span class="operator">=</span>2014-05-30T00:00:00-04:00<span class="punctuation">&amp;</span><span class="name variable">before</span><span class="operator">=</span>2014-05-30T23:59:59-04:00</code></pre><p>List the agents that have sent a heartbeat in the last hour.</p><pre><code class="code bash">/api/v1/search?type<span class="operator">=</span>agent<span class="punctuation">&amp;</span><span class="name variable">after</span><span class="operator">=</span>2014-05-30T15:00:00-04:00<span class="punctuation">&amp;</span><span class="name variable">limit</span><span class="operator">=</span>200</code></pre><p>Find actions ran between two dates (limited to 10 results as is the default).</p><pre><code class="code bash">/api/v1/search?type<span class="operator">=</span>action<span class="punctuation">&amp;</span><span class="name variable">status</span><span class="operator">=</span>sent
<span class="punctuation">&amp;</span><span class="name variable">after</span><span class="operator">=</span>2014-05-01T00:00:00-00:00<span class="punctuation">&amp;</span><span class="name variable">before</span><span class="operator">=</span>2014-05-30T00:00:00-00:00</code></pre><p>Find the last 10 commands signed by an investigator identified by name.</p><pre><code class="code bash">/api/v1/search?investigatorname<span class="operator">=</span>%25bob%25smith%25<span class="punctuation">&amp;</span><span class="name variable">limit</span><span class="operator">=</span>10<span class="punctuation">&amp;</span><span class="name builtin">type</span><span class="operator">=</span><span class="name builtin">command</span></code></pre></section></section><section id="data-transformation"><header><h2><a href="#id19">3   Data transformation</a></h2></header><p>The API implements several data transformation functions between the base
format of <cite>action</cite> and <cite>command</cite>, and reporting formats.</p><section id="compliance-items"><header><h3><a href="#id20">3.1   Compliance Items</a></h3></header><p>The compliance item format is used to measure the compliance of a target with
<span class="punctuation">&amp;</span><span class="name variable">after</span><span class="operator">=</span>2014-05-01T00:00:00-00:00<span class="punctuation">&amp;</span><span class="name variable">before</span><span class="operator">=</span>2014-05-30T00:00:00-00:00</code></pre><p>Find the last 10 commands signed by an investigator identified by name.</p><pre><code class="code bash">/api/v1/search?investigatorname<span class="operator">=</span>%25bob%25smith%25<span class="punctuation">&amp;</span><span class="name variable">limit</span><span class="operator">=</span>10<span class="punctuation">&amp;</span><span class="name builtin">type</span><span class="operator">=</span><span class="name builtin">command</span></code></pre></section></section><section id="data-transformation"><header><h2><a href="#id13">2   Data transformation</a></h2></header><p>The API implements several data transformation functions between the base
format of <cite>action</cite> and <cite>command</cite>, and reporting formats.</p><section id="compliance-items"><header><h3><a href="#id14">2.1   Compliance Items</a></h3></header><p>The compliance item format is used to measure the compliance of a target with
particular requirement. A single compliance item represent the compliance of
one target (host) with one check (test + value).</p><p>In MIG, an <cite>action</cite> can contain compliance checks. An <cite>action</cite> creates one
<cite>command</cite> per <cite>agent</cite>. Upon completion, the agent stores the results in the
@ -980,7 +882,7 @@ commands could, in turn, generate thousands of compliance items.</p><p>The forma
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"attemptstoaltercrontab_user_config"</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span></code></pre><p>When using the parameter <cite>&amp;report=complianceitems</cite>, the <cite>search</cite> endpoint of the API
will generate a list of compliance items from the results of the search.</p></section><section id="geolocations"><header><h3><a href="#id21">3.2   Geolocations</a></h3></header><p>The geolocations format transforms command results into an array of geolocated
will generate a list of compliance items from the results of the search.</p></section><section id="geolocations"><header><h3><a href="#id15">2.2   Geolocations</a></h3></header><p>The geolocations format transforms command results into an array of geolocated
endpoints for consumption by a map, like Google Maps. The format discards
results details, and only stores the value of FoundAnything.</p><p>This feature requires using <strong>MaxMind's GeoIP2-City</strong> database. The database
must be configured in the API as follow:</p><pre><code class="code">[maxmind]
@ -994,4 +896,104 @@ must be configured in the API as follow:</p><pre><code class="code">[maxmind]
<span class="name tag">"latitude"</span><span class="punctuation">:</span> <span class="literal number float">39.4284</span><span class="punctuation">,</span>
<span class="name tag">"longitude"</span><span class="punctuation">:</span> <span class="literal number float">-74.4957</span>
<span class="punctuation">}</span></code></pre><p>When using the parameter <cite>&amp;report=geolocations</cite>, the <cite>search</cite> endpoint of the
API will generate a list of geolocations from the results of the search.</p></section></section></body></html>
API will generate a list of geolocations from the results of the search.</p></section></section><section id="authentication-with-x-pgpauthorization-version-1"><header><h2><a href="#id16">3   Authentication with X-PGPAUTHORIZATION version 1</a></h2></header><p>Authenticating against the MIG API requires sending a PGP signed token in the
request header named <cite>X-PGPAUTHORIZATION</cite>. The key that signs the token must
belong to an active investigator. Construction of the token works as follows:</p><ol class="arabic"><li><p>make a string named <strong>str</strong> composed of a version, a UTC timestamp in RFC3339 format
and a random nonce, each separated by semicolons. The current version is <strong>1</strong>
and may be upgraded in the future. The nonce value must be a positive integer.</p><p><strong>str=&lt;VERSION&gt;;&lt;UTC TIMESTAMP RFC3339&gt;;&lt;NONCE&gt;</strong></p><p>UTC is a hard requirement. The timestamp must end with the suffix <strong>Z</strong>
which indicates the UTC timezone. In bash, a correct timestamp can be
generated with the command <cite>$ date -u +%Y-%m-%dT%H:%M:%SZ</cite>.</p><p>An example string would look like: <cite>1;2006-01-02T15:04:05Z;1825922807490630059</cite></p><p>The string must be terminated by a newline character, hexadecimal code <cite>0x0a</cite>.</p></li></ol><pre><code class="code bash"><span class="name variable">$ </span>hexdump -C <span class="operator">&lt;&lt;&lt;</span> <span class="literal string single">'1;2006-01-02T15:04:05Z;1825922807490630059'</span>
<span class="literal number">00000000</span> <span class="literal number">31</span> 3b <span class="literal number">32</span> <span class="literal number">30</span> <span class="literal number">30</span> <span class="literal number">36</span> 2d <span class="literal number">30</span> <span class="literal number">31</span> 2d <span class="literal number">30</span> <span class="literal number">32</span> <span class="literal number">54</span> <span class="literal number">31</span> <span class="literal number">35</span> 3a <span class="punctuation">|</span>1<span class="punctuation">;</span>2006-01-02T15:<span class="punctuation">|</span>
<span class="literal number">00000010</span> <span class="literal number">30</span> <span class="literal number">34</span> 3a <span class="literal number">30</span> <span class="literal number">35</span> 5a 3b <span class="literal number">31</span> <span class="literal number">38</span> <span class="literal number">32</span> <span class="literal number">35</span> <span class="literal number">39</span> <span class="literal number">32</span> <span class="literal number">32</span> <span class="literal number">38</span> <span class="literal number">30</span> <span class="punctuation">|</span>04:05Z<span class="punctuation">;</span>182592280<span class="punctuation">|</span>
<span class="literal number">00000020</span> <span class="literal number">37</span> <span class="literal number">34</span> <span class="literal number">39</span> <span class="literal number">30</span> <span class="literal number">36</span> <span class="literal number">33</span> <span class="literal number">30</span> <span class="literal number">30</span> <span class="literal number">35</span> <span class="literal number">39</span> 0a <span class="punctuation">|</span>7490630059.<span class="punctuation">|</span>
0000002b</code></pre><ol class="arabic" start="2"><li><p>PGP sign <strong>str</strong> with the private key of the investigator. Armor and detach
the signature into <strong>armoredSig</strong>:</p><pre>$ gpg -a --detach-sig &lt;&lt;&lt; '1;2006-01-02T15:04:05Z;1825922807490630059'
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAABCAAGBQJUZ5psAAoJEKPWUhc7dj6PFd8IALWQS4x9Kzssww1pxc7uq9mg
JT/3jHLwAYPQV3ltqFcI5R2EGHo5DsXXjX6lfOc7DgbteB9UV+H++KG0oVUTTjuP
kncmFYmoBEDqbXju6EASBLyUlt3M43N9DmQaAaeoyW2gB0p0aEYRZoN3Cf0O0qhU
b3nnsCz6IyuBcQAZh1Jnmf7AMwRmXier8OflObQ9wJ1iYF9KCD0TgP1Z+kaCvMqC
PWQ5XaNaXn665V19mjAMicOtO9U3A/v4ApYyUSPyq0cuLrT8z/Z1vdjyeZVTaOM8
MhnoKfgBnegQnP+BPQZlWcjaBsquenC/joYRhq20nAEwSjZ1Nm7+qHo/DW0bYOA=
=4nrR
-----END PGP SIGNATURE-----</pre></li><li><p>Create <strong>sig</strong> by taking <strong>armoredSig</strong> and removing the PGP headers, footers,
empty lines and newlines.</p><blockquote><p>example: <cite>iQEcBAABCAAGBQJUWPDpAAoJEKPWUhc7dj6PQdgH/0TRMOEAL4SL6v+JvixWtEGJzXBCqBpRBsygHAKT+m4AxwniVa9vr8vfWm14eFpZTGdlDx39Ko+tdFoHn5Z1yKEeQWEQYXqhneAnv0pYR1aIjXM8MY63TNePWBZxUerlRkjv2IH16/W5aBrbOctOxEs1BKuN2pd4Hgubr+2f43gcRcWW+Ww/5Fyg1lKzH8jP84uqiIT8wQOdBrwUkgRdSdfMQbYFjsgY57G+ZsMobNhhlFedgKuZShJCd+G1GlwsfZPsZOSLmVZahI7wjR3vckCJ66eff3e/xX7Gt0zGGa5i1dgH5Q6TSjRGRBE37FwD4C6fycUEuy9yKI7iFziw33Y==k6gT</cite></p></blockquote></li><li><p>Create <strong>token</strong> by concatenating <strong>str</strong>, a semicolon, and <strong>sig</strong>.
<strong>token=&lt;str&gt;;&lt;sig&gt;</strong>
example: <cite>1;2006-01-02T15:04:05Z;1825922807490630059;owEBYQGe/pANAwAIAaPWUhc7dj6...&lt;truncated&gt;</cite></p></li><li><p>Send <strong>token</strong> in the header named <strong>X-PGPAUTHORIZATION</strong> with the request:</p><pre>$ curl -H 'X-PGPAUTHORIZATION: 1;2006-01-02T15:04:05Z;1825922807490630059;owEBYQGe/pANAwAIAaP...&lt;truncated&gt;' localhost:12345/api/v1/</pre></li><li><p>The API verifies the version and validity period of the timestamp. By default, a
token will be rejected if its timestamp deviates from the server time by more
than 10 minutes. Administrators can configure this value. In effect, this
means a timestamp is valid for twice the duration of the window. By default,
that's 10 minutes before current server time, and 10 minutes after current
server time.</p></li><li><p>If the timestamp is valid, the API next verifies the signature against the data
and authenticates the user. Failure to verify the signature returns an error
with the HTTP code 401 Unauthorized.</p></li><li><p>The user is authorized, the API processes and answer the request.</p></li></ol><section id="security-implications"><header><h3><a href="#id17">3.1   Security implications</a></h3></header><ol class="arabic"><li><p>A token can be used an unlimited number of times within its validity period.
There is no check to guarantee that a token is only used once. It is
assumed that the token is transmitted over a secure channel such as HTTPS to
prevent token theft by a malicious user.</p></li><li><p>API clients and servers must use proper time synchronization for the timestamp
verification to work. A client or a server that has inaccurate time may not be
able to establish connections. We believe this requirement to be reasonable
considering the sensitivity of the API.</p></li></ol></section><section id="example-1-invalid-timestamp"><header><h3><a href="#id18">3.2   Example 1: invalid timestamp</a></h3></header><p>The signature is valid but the timestamp is beyond the acceptable time window.</p><pre><code class="code bash"><span class="name variable">$ </span>curl -H <span class="literal string single">'X-PGPAUTHORIZATION: 1;2006-01-02T15:04:05Z;1825922807490630059;iQEcB...&lt;truncated&gt;'</span> http://localhost:12345/api/v1/
<span class="operator">{</span>
<span class="literal string double">"collection"</span>: <span class="operator">{</span>
<span class="literal string double">"error"</span>: <span class="operator">{</span>
<span class="literal string double">"code"</span>: <span class="literal string double">"6077873045059431424"</span>,
<span class="literal string double">"message"</span>: <span class="literal string double">"Authorization verification failed with error 'verifySignedToken() -&gt; token timestamp is not within acceptable time limits'"</span>
<span class="operator">}</span>,
<span class="literal string double">"href"</span>: <span class="literal string double">"http://localhost:12345/api/v1/"</span>,
<span class="literal string double">"template"</span>: <span class="operator">{}</span>,
<span class="literal string double">"version"</span>: <span class="literal string double">"1.0"</span>
<span class="operator">}</span>
<span class="operator">}</span></code></pre></section><section id="example-2-invalid-signature"><header><h3><a href="#id19">3.3   Example 2: invalid signature</a></h3></header><p>The signature is not valid, or is signed by a key that the API does not
recognize.</p><pre><code class="code bash"><span class="name variable">$ </span>curl -H <span class="literal string single">'X-PGPAUTHORIZATION: 1;2014-11-04T15:36:05Z;1825922807490630059;iQEcBA...&lt;truncated&gt;'</span> http://localhost:12345/api/v1/
<span class="operator">{</span>
<span class="literal string double">"collection"</span>: <span class="operator">{</span>
<span class="literal string double">"error"</span>: <span class="operator">{</span>
<span class="literal string double">"code"</span>: <span class="literal string double">"6077875007260332032"</span>,
<span class="literal string double">"message"</span>: <span class="literal string double">"Authorization verification failed with error 'verifySignedToken() -&gt; GetFingerprintFromSignature() -&gt; openpgp: invalid signature: hash tag doesn't match'"</span>
<span class="operator">}</span>,
<span class="literal string double">"href"</span>: <span class="literal string double">"http://localhost:12345/api/v1/"</span>,
<span class="literal string double">"template"</span>: <span class="operator">{}</span>,
<span class="literal string double">"version"</span>: <span class="literal string double">"1.0"</span>
<span class="operator">}</span>
<span class="operator">}</span></code></pre></section><section id="generating-a-token-in-bash"><header><h3><a href="#id20">3.4   Generating a token in Bash</a></h3></header><pre><code class="code">$ token="1;$(date -u +%Y-%m-%dT%H:%M:%SZ);$RANDOM$RANDOM$RANDOM$RANDOM"; \
sig=$(gpg -a --detach-sig &lt;&lt;&lt; $token |tail -8 |head -7 \
| sed ':a;N;$!ba;s/\n//g'); echo "X-PGPAUTHORIZATION: $token;$sig"
X-PGPAUTHORIZATION: 1;2014-11-04T19:13:37Z;13094113753132512760;iQEcBAA.....</code></pre></section><section id="generating-a-token-in-python"><header><h3><a href="#id21">3.5   Generating a token in Python</a></h3></header><pre><code class="code python"><span class="comment">#!/usr/bin/env python</span>
<span class="keyword namespace">import</span> <span class="name namespace">os</span>
<span class="keyword namespace">import</span> <span class="name namespace">gnupg</span>
<span class="keyword namespace">from</span> <span class="name namespace">time</span> <span class="keyword namespace">import</span> <span class="name">gmtime</span><span class="punctuation">,</span> <span class="name">strftime</span>
<span class="keyword namespace">import</span> <span class="name namespace">random</span>
<span class="keyword namespace">import</span> <span class="name namespace">requests</span>
<span class="keyword namespace">import</span> <span class="name namespace">json</span>
<span class="keyword">def</span> <span class="name function">makeToken</span><span class="punctuation">(</span><span class="name">gpghome</span><span class="punctuation">,</span> <span class="name">keyid</span><span class="punctuation">):</span>
<span class="name">gpg</span> <span class="operator">=</span> <span class="name">gnupg</span><span class="operator">.</span><span class="name">GPG</span><span class="punctuation">(</span><span class="name">gnupghome</span><span class="operator">=</span><span class="name">gpghome</span><span class="punctuation">)</span>
<span class="name">version</span> <span class="operator">=</span> <span class="literal string">"1"</span>
<span class="name">timestamp</span> <span class="operator">=</span> <span class="name">strftime</span><span class="punctuation">(</span><span class="literal string">"%Y-%m-</span><span class="literal string interpol">%d</span><span class="literal string">T%H:%M:%SZ"</span><span class="punctuation">,</span> <span class="name">gmtime</span><span class="punctuation">())</span>
<span class="name">nonce</span> <span class="operator">=</span> <span class="name builtin">str</span><span class="punctuation">(</span><span class="name">random</span><span class="operator">.</span><span class="name">randint</span><span class="punctuation">(</span><span class="literal number integer">10000</span><span class="punctuation">,</span> <span class="literal number integer">18446744073709551616</span><span class="punctuation">))</span>
<span class="name">token</span> <span class="operator">=</span> <span class="name">version</span> <span class="operator">+</span> <span class="literal string">";"</span> <span class="operator">+</span> <span class="name">timestamp</span> <span class="operator">+</span> <span class="literal string">";"</span> <span class="operator">+</span> <span class="name">nonce</span>
<span class="name">sig</span> <span class="operator">=</span> <span class="name">gpg</span><span class="operator">.</span><span class="name">sign</span><span class="punctuation">(</span><span class="name">token</span> <span class="operator">+</span> <span class="literal string">"</span><span class="literal string escape">\n</span><span class="literal string">"</span><span class="punctuation">,</span>
<span class="name">keyid</span><span class="operator">=</span><span class="name">keyid</span><span class="punctuation">,</span>
<span class="name">detach</span><span class="operator">=</span><span class="name builtin pseudo">True</span><span class="punctuation">,</span> <span class="name">clearsign</span><span class="operator">=</span><span class="name builtin pseudo">True</span><span class="punctuation">)</span>
<span class="name">token</span> <span class="operator">+=</span> <span class="literal string">";"</span>
<span class="name">linectr</span><span class="operator">=</span><span class="literal number integer">0</span>
<span class="keyword">for</span> <span class="name">line</span> <span class="operator word">in</span> <span class="name builtin">iter</span><span class="punctuation">(</span><span class="name builtin">str</span><span class="punctuation">(</span><span class="name">sig</span><span class="punctuation">)</span><span class="operator">.</span><span class="name">splitlines</span><span class="punctuation">()):</span>
<span class="name">linectr</span><span class="operator">+=</span><span class="literal number integer">1</span>
<span class="keyword">if</span> <span class="name">linectr</span> <span class="operator">&lt;</span> <span class="literal number integer">4</span> <span class="operator word">or</span> <span class="name">line</span><span class="operator">.</span><span class="name">startswith</span><span class="punctuation">(</span><span class="literal string">'-'</span><span class="punctuation">)</span> <span class="operator word">or</span> <span class="operator word">not</span> <span class="name">line</span><span class="punctuation">:</span>
<span class="keyword">continue</span>
<span class="name">token</span> <span class="operator">+=</span> <span class="name">line</span>
<span class="keyword">return</span> <span class="name">token</span>
<span class="keyword">if</span> <span class="name">__name__</span> <span class="operator">==</span> <span class="literal string">'__main__'</span><span class="punctuation">:</span>
<span class="name">token</span> <span class="operator">=</span> <span class="name">makeToken</span><span class="punctuation">(</span><span class="literal string">"/home/ulfr/.gnupg"</span><span class="punctuation">,</span>
<span class="literal string">"E60892BB9BD89A69F759A1A0A3D652173B763E8F"</span><span class="punctuation">)</span>
<span class="name">r</span> <span class="operator">=</span> <span class="name">requests</span><span class="operator">.</span><span class="name">get</span><span class="punctuation">(</span><span class="literal string">"http://localhost:12345/api/v1/dashboard"</span><span class="punctuation">,</span>
<span class="name">headers</span><span class="operator">=</span><span class="punctuation">{</span><span class="literal string">'X-PGPAUTHORIZATION'</span><span class="punctuation">:</span> <span class="name">token</span><span class="punctuation">})</span>
<span class="keyword">print</span> <span class="name">token</span>
<span class="keyword">print</span> <span class="name">r</span><span class="operator">.</span><span class="name">text</span></code></pre></section></section></body></html>

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

34
doc/command_line.rst Normal file
Просмотреть файл

@ -0,0 +1,34 @@
================
MIG command line
================
.. sectnum::
.. contents:: Table of contents
The MIG command line is a terminal-based client interface that provides fast
interaction with the MIG API to launch actions and receive results. Its goal is
to be simple and fast to use for basic investigations. Unlike the mig-console,
it does not provide access to previous actions, search or investigators
management.
To install the MIG command line, use `go get mig.ninja/mig/client/mig`. This
command will place a binary called `mig` under $GOPATH/bin/mig. On first run, it
will invite you to create a configuration:
.. code::
$ mig file -path /etc -name "^passwd$" -content "jvehent"
no configuration file found at /home/jvehent/.migrc
would you like to generate a new configuration file at /home/jvehent/.migrc? Y/n> Y
found key 'Julien Vehent (ulfr) <jvehent@mozilla.com>' with fingerprint 'E60892BB9BD89A69F759A1A0A3D652173B763E8F'.
use this key? Y/n> Y
using key E60892BB9BD89A69F759A1A0A3D652173B763E8F
what is the location of the API? (ex: https://mig.example.net/api/v1/) > https://api.mig.example.net/api/v1/
MIG client configuration generated at /home/jvehent/.migrc
1226 agents will be targeted. ctrl+c to cancel. launching in 5 4....
Subsequent runs of `mig` will read the configuration from `$HOME/.migrc` directly.
For more examples on how to use the mig command line, see the `cheatsheet
<cheatsheet.rst.html>`_.

247
doc/command_line.rst.html Normal file
Просмотреть файл

@ -0,0 +1,247 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
color: #eaeaea;
font: 16px;
line-height: 1.5em;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
}
#table-of-contents ul {
line-height: 1;
}
/* General & 'Reset' Stuff */
.container {
width: 95%;
max-width: 1000px;
margin: 0 auto;
}
section {
display: block;
margin: 0 0 20px 0;
}
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
/*margin: 0;*/
}
/* Header, <header>
* header - container
* h1 - project name
* h2 - project description
* */
header {
background: rgba(0, 0, 0, 0.1);
width: 100%;
/*border-bottom: 1px dashed #b5e853;*/
/*padding: 20px 0;
* margin: 0 0 40px 0;*/
padding: 5px 0;
margin: 0 0 10px 0;
}
header h1 {
font-size: 30px;
line-height: 1.5;
margin: 0 0 0 -40px;
font-weight: bold;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
/*color: #b5e853;*/
color: #089d00;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1),
0 0 5px rgba(181, 232, 83, 0.1),
0 0 10px rgba(181, 232, 83, 0.1);
letter-spacing: -1px;
-webkit-font-smoothing: antialiased;
}
header h1:before {
content: "./ ";
font-size: 24px;
}
header h2 {
font-size: 18px;
font-weight: 300;
}
/* Main Content
* */
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {
max-width: 100%
}
h2 a {
font-weight: bold;
color: #8AB638;
line-height: 1.4em;
font-size: 1.4em;
}
h3 a, h4 a, h5 a, h6 a {
font-weight: bold;
color: #934500;
line-height: 1.4em;
}
h1 {
font-size: 30px;
}
h2 {
font-size: 28px;
border-bottom: 1px dashed #b5e853;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 14px;
}
h5 {
font-size: 12px;
text-transform: uppercase;
margin: 0 0 5px 0;
}
h6 {
font-size: 12px;
text-transform: uppercase;
color: #999;
margin: 0 0 5px 0;
}
dt {
font-style: italic;
font-weight: bold;
}
/*
ul li {
list-style: none;
}
*/
/*
ul li:before {
content: ">>";
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
font-size: 13px;
color: #b5e853;
margin-left: -37px;
margin-right: 21px;
line-height: 16px;
}
*/
blockquote {
color: #aaa;
padding-left: 10px;
border-left: 1px dotted #666;
}
pre {
background: rgba(0, 0, 0, 0.9);
border: 1px solid rgba(255, 255, 255, 0.15);
padding: 10px;
font-size: 14px;
//color: #b5e853;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
text-wrap: normal;
overflow: auto;
overflow-y: hidden;
}
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
code .ln { color: grey; } /* line numbers */
/*code, code { background-color: #eeeeee }*/
code .comment, code .comment, code .c1 { color: #999; }
code .keyword, code .keyword, code .kd, code .kn, code .k, code .o { color: #FC8F3F; font-weight: bold;}
code .nb { color: #c45918;}
code .s {color: #0a77c4;}
code .punctuation, code .p { color: white;}
code .literal.string, code .literal.string { color: #40BF32; }
code .name, code .name.builtin, code .nx { color: white; }
code .deleted, code .deleted { background-color: #DEB0A1}
code .inserted, code .inserted { background-color: #A3D289}
table {
width: 100%;
margin: 0 0 20px 0;
}
th {
text-align: left;
border-bottom: 1px dashed #b5e853;
padding: 5px 10px;
}
td {
padding: 5px 10px;
}
hr {
height: 0;
border: 0;
border-bottom: 1px dashed #b5e853;
color: #b5e853;
}
/* Links
* a, a:hover, a:visited
* */
a {
color: #63c0f5;
/*text-shadow: 0 0 5px rgba(104, 182, 255, 0.5);*/
text-decoration: none;
}
cite {
color: #00FF4A;
}
strong {
color: #C64216;
}
</style></head><body><h1>MIG command line</h1><p>The MIG command line is a terminal-based client interface that provides fast
interaction with the MIG API to launch actions and receive results. Its goal is
to be simple and fast to use for basic investigations. Unlike the mig-console,
it does not provide access to previous actions, search or investigators
management.</p><p>To install the MIG command line, use <cite>go get mig.ninja/mig/client/mig</cite>. This
command will place a binary called <cite>mig</cite> under $GOPATH/bin/mig. On first run, it
will invite you to create a configuration:</p><pre><code class="code">$ mig file -path /etc -name "^passwd$" -content "jvehent"
no configuration file found at /home/jvehent/.migrc
would you like to generate a new configuration file at /home/jvehent/.migrc? Y/n&gt; Y
found key 'Julien Vehent (ulfr) &lt;jvehent@mozilla.com&gt;' with fingerprint 'E60892BB9BD89A69F759A1A0A3D652173B763E8F'.
use this key? Y/n&gt; Y
using key E60892BB9BD89A69F759A1A0A3D652173B763E8F
what is the location of the API? (ex: https://mig.example.net/api/v1/) &gt; https://api.mig.example.net/api/v1/
MIG client configuration generated at /home/jvehent/.migrc
1226 agents will be targeted. ctrl+c to cancel. launching in 5 4....</code></pre><p>Subsequent runs of <cite>mig</cite> will read the configuration from <cite>$HOME/.migrc</cite> directly.</p><p>For more examples on how to use the mig command line, see the <a class="reference external" href="cheatsheet.rst.html">cheatsheet</a>.</p></body></html>

Просмотреть файл

@ -1,7 +1,6 @@
===================================================
Mozilla InvestiGator Concepts & Internal Components
===================================================
:Author: Julien Vehent <jvehent@mozilla.com>
.. sectnum::
.. contents:: Table of Contents
@ -76,11 +75,8 @@ Below is a high-level view of the architecture:
.. image:: .files/MIG-Arch-Diagram.png
Actions and Commands
--------------------
Actions
~~~~~~~
-------
Actions are JSON files created by investigator to perform tasks on agents.
@ -168,8 +164,8 @@ Upon generation, additional fields are appended to the action:
* **validfrom** and **expireafter**: two dates that constrains the validity of the
action to a UTC time window.
Action/Commands workflow
------------------------
Investigation workflow
-----------------------
The diagram below represents the full workflow from the launch of an action by
an investigation, to the retrieval of results from the database. The steps are
explained in the legend of the diagram, and map to various components of MIG.
@ -184,159 +180,6 @@ View `full size diagram`_.
.. image:: .files/action_command_flow.svg
Command execution flow in Agent and Modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Upon processing of an action, the scheduler will retrieve a list of agents to
send the action to. One action is then derived into multiple commands and sent
to agents.
An agent receives a command from the scheduler on its personal AMQP queue (1).
It parses the command (2) and extracts all of the operations to perform.
Operations are passed to modules and executed in parallel (3). Rather than
maintaining a state of the running command, the agent create a goroutine and a
channel tasked with receiving the results from the modules. Each modules
published its results inside that channel (4). The result parsing goroutine
receives them, and when it has received all of them, populates the `results` (5)
array of the command with the results from each module, and send the command
back to the scheduler(6).
When the agent is done running the command, both the channel and the goroutine
are destroyed.
::
+-------+ [ - - - - - - A G E N T - - - - - - - - - - - - ]
|command|+---->(listener)
+-------+ |(2)
^ V
|(1) (parser)
| + [ m o d u l e s ]
+---------+ | (3)|----------> op1 +----------------+
|SCHEDULER|+---+ |------------> op2 +--------------|
| |<---+ |--------------> op3 +------------|
+---------+ | +----------------> op4 +----------+
| V(4)
|(6) (receiver)
| |
| V(5)
+ (publisher)
+-------+ /
|results|<-----------------------------------------'
+-------+
The command received by the agent is composed of a copy of the action described
previously, but signed with the private key of a trusted investigator. It also
contains additional parameters that are specific to the targetted agent, such as
command processing timestamps, name of the agent queue on the message broker,
action and command unique IDs and status and results of the command. Below is an
command derived from the root password checking action, and ran on the host named
'host1.example.net'.
.. code:: json
{
"id": 1.427392971126604e+18,
"action": { ... SIGNED COPY OF THE ACTION ... },
"agent": {
"id": 1.4271760437936648e+18,
"name": "host1.example.net",
"queueloc": "linux.host1.example.net.981alsd19aos1984",
"mode": "daemon",
"version": "20150324+0d0f88c.prod"
},
"status": "success",
"results": [
{
"foundanything": true,
"success": true,
"elements": {
"root_passwd_hashed_or_disabled": [
{
"file": "/etc/shadow",
"fileinfo": {
"lastmodified": "2015-02-07 01:51:07.17850601 +0000 UTC",
"mode": "----------",
"size": 1684
},
"search": {
"contents": [
"root:(\\*|!|\\$(1|2a|5|6)\\$).+"
],
"options": {
"matchall": false,
"matchlimit": 0,
"maxdepth": 0
},
"paths": [
"/etc"
]
}
}
]
},
"statistics": {
"exectime": "2.017849ms",
"filescount": 1,
"openfailed": 0,
"totalhits": 1
},
"errors": null
}
],
"starttime": "2015-03-26T18:02:51.126605Z",
"finishtime": "2015-03-26T18:03:00.671232Z"
}
The results of the command show that the file '/etc/shadow' has matched, and
thus "FoundAnything" returned "True".
The invocation of the file module has completed successfully, which is
represented by **results->0->success=true**. In our example, there is only one
operation in the **action->operations** array, so only one result is present.
When multiple operations are performed, each has its results listed in a
corresponding entry of the results array (operations[0] is in results[0],
operations[1] in results[1], etc...).
Finally, the agent has performed all operations in the operations array
successfully, and returned **status=success**. Had a failure happened on the
agent, the returned status would be one of "failed", "timeout" or "cancelled".
Command expiration & timeouts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To prevent abuse of resources, agents will kill long-running modules after a
given period of time. That timeout is hardcoded in the agent configuration
at compile time and defaults to 5 minutes.
.. code:: go
// timeout after which a module run is killed
var MODULETIMEOUT time.Duration = 300 * time.Second
That timeout represents the **maximum** execution time of a single operation. If
an action contains 3 operations, each operation gets its own timeout. But because
operations run in parallel in the agent, the maximum runtime of an action should
be very close to the value of MODULETIMEOUT.
In a typical deployment, it is safe to increase MODULETIMEOUT to allow for
longer operations. A value of 20 minutes is usual. Make sure to fine tune this
to your environment, and get the approval of your ops team because mig-agent
may end up consuming resources (but never more than 50% of the cpu available on
a system).
Oftentimes, an investigator will want a timeout that is much shorter than the value
of MODULETIMEOUT. In the MIG command line, the flag `-e` controls the
expiration. It defaults to 5 minutes but can be set to 30 seconds for simple
investigations. When that happens, the agent will calculate an appropriate expiration
for the operations being run. If the expiration set on the action is set to 30 seconds,
the agent will kill operations that run for more than 30 seconds.
If the expiration is larger than the value of MODULETIMEOUT (for example, 2
hours), then MODULETIMEOUT is used. Setting a long expiration may be useful to
allow agents that only check in periodically to pick up actions long after they
are launched.
Access Control Lists
--------------------
@ -410,172 +253,6 @@ control to authorize access to specific functions of modules. For example, an
investigator could be authorized to call the `regex` function of filechecker
module, but only in `/etc`. This functionality is not implemented yet.
Agent initialization process
----------------------------
The agent tries to be as autonomous as possible. One of the goal is to ship
agents without requiring external provisioning tools, such as Chef or Puppet.
Therefore, the agent attempts to install itself as a service, and also supports
a builtin upgrade protocol (described in the next section).
As a portable binary, the agent needs to detect the type of operating system
and init method that is used by an endpoint. Depending on the endpoint,
different initialization methods are used. The diagram below explains the
decision process followed by the agent.
.. image:: .files/mig-agent-initialization-process.png
Go does not provide support for running programs in the backgroud. On endpoints
that run upstart, systemd (linux) or launchd (darwin), this is not an issue
because the init daemon takes care of running the agent in the background,
rerouting its file descriptors and restarting on crash. On Windows and System-V,
however, the agent daemonizes by forking itself into `foreground` mode, and
re-forking itself on error (such as loss of connectivity to the relay).
On Windows and System-V, if the agent is killed, it will not be restarted
automatically.
Registration process
~~~~~~~~~~~~~~~~~~~~
The initialization process goes through several environment detection steps
which are used to select the proper init method. Once started, the agent will
send a heartbeat to the public relay, and also store that heartbeat in its
`run` directory. The location of the `run` directory is platform specific.
* windows: C:\Windows\
* darwin: /Library/Preferences/mig/
* linux: /var/run/mig/
Below is a sample heartbeat message from a linux agent stored in
`/var/run/mig/mig-agent.ok`.
.. code:: json
{
"destructiontime": "0001-01-01T00:00:00Z",
"environment": {
"arch": "amd64",
"ident": "Red Hat Enterprise Linux Server release 6.5 (Santiago)",
"init": "upstart"
},
"heartbeatts": "2014-07-31T14:00:20.00442837-07:00",
"name": "someserver.example.net",
"os": "linux",
"pid": 26256,
"queueloc": "linux.someserver.example.net.5hsa811oda",
"starttime": "2014-07-30T21:34:48.525449401-07:00",
"version": "201407310027+bcbdd94.prod"
}
Check-In mode
~~~~~~~~~~~~~
In infrastructure where running the agent as a permanent process is not
acceptable, it is possible to run the agent as a cron job. By starting the
agent with the flag **-m agent-checkin**, the agent will connect to the
configured relay, retrieve and run outstanding commands, and exit after 10
seconds of inactivity.
Agent upgrade process
---------------------
MIG supports upgrading agents in the wild. The upgrade protocol is designed with
security in mind. The flow diagram below presents a high-level view:
::
Investigator Scheduler Agent NewAgent FileServer
+-----------+ +-------+ +---+ +------+ +--------+
| | | | |
| 1.initiate | | | |
|------------------>| | | |
| | 2.send command | | |
| |------------------>| 3.verify | |
| | |--------+ | |
| | | | | |
| | | | | |
| | |<-------+ | |
| | | | |
| | | 4.download | |
| | |-------------------------------------->|
| | | | |
| | | 5.checksum | |
| | |--------+ | |
| | | | | |
| | | | | |
| | |<-------+ | |
| | | | |
| | | 6.exec | |
| | |------------------>| |
| | 7.return own PID | | |
| |<------------------| | |
| | | | |
| |------+ 8.mark | | |
| | | agent as | | |
| | | upgraded | | |
| |<-----+ | | |
| | | | |
| | 9.register | | |
| |<--------------------------------------| |
| | | | |
| |------+10.find dup | | |
| | |agents in | | |
| | |registrations | |
| |<-----+ | | |
| | | | |
| | 11.send command to kill PID old agt| |
| |-------------------------------------->| |
| | | | |
| | 12.acknowledge | | |
| |<--------------------------------------| |
All upgrade operations are initiated by an investigator (1). The upgrade is
triggered by an action to the upgrade module with the following parameters:
.. code:: json
"Operations": [
{
"Module": "upgrade",
"Parameters": {
"linux/amd64": {
"to_version": "16eb58b-201404021544",
"location": "http://localhost/mig/bin/linux/amd64/mig-agent",
"checksum": "31fccc576635a29e0a27bbf7416d4f32a0ebaee892475e14708641c0a3620b03"
}
}
}
],
* Each OS family and architecture have their own parameters (ex: "linux/amd64",
"darwin/amd64", "windows/386", ...). Then, in each OS/Arch group, we have:
* to_version is the version an agent should upgrade to
* location points to a HTTPS address that contains the agent binary
* checksum is a SHA256 hash of the agent binary to be verified after download
The parameters above are signed using a standard PGP action signature.
The upgrade action is forwarded to agents (2) like any other action. The action
signature is verified by the agent (3), and the upgrade module is called. The
module downloads the new binary (4), verifies the version and checksum (5) and
installs itself on the system.
Assuming everything checks in, the old agent executes the binary of the new
agent (6). At that point, two agents are running on the same machine, and the
rest of the protocol is designed to shut down the old agent, and clean up.
After executing the new agent, the old agent returns a successful result to the
scheduler, and includes its own PID in the results.
The new agent starts by registering with the scheduler (7). This tells the
scheduler that two agents are running on the same node, and one of them must
terminate. The scheduler sends a kill action to both agents with the PID of the
old agent (8). The kill action may be executed twice, but that doesn't matter.
When the scheduler receives the kill results (9), it sends a new action to check
for `mig-agent` processes (10). Only one should be found in the results (11),
and if that is the case, the scheduler tells the agent to remove the binary of
the old agent (12). When the agent returns (13), the upgrade protocol is done.
If the PID of the old agent lingers on the system, an error is logged for the
investigator to decide what to do next. The scheduler does not attempt to clean
up the situation.
Threat Model
------------

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {
@ -227,7 +229,7 @@ cite {
strong {
color: #C64216;
}
</style></head><body><h1>Mozilla InvestiGator Concepts &amp; Internal Components</h1><table><tr><td class="field-label">Author</td><td>Julien Vehent &lt;<a class="reference external" href="mailto:jvehent@mozilla.com">jvehent@mozilla.com</a>&gt;</td></tr></table><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#actions-and-commands" id="id1">1   Actions and Commands</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#actions" id="id2">1.1   Actions</a></p></li></ul></li><li><p><a class="reference internal" href="#action-commands-workflow" id="id3">2   Action/Commands workflow</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#command-execution-flow-in-agent-and-modules" id="id4">2.1   Command execution flow in Agent and Modules</a></p></li><li><p><a class="reference internal" href="#command-expiration-timeouts" id="id5">2.2   Command expiration &amp; timeouts</a></p></li></ul></li><li><p><a class="reference internal" href="#access-control-lists" id="id6">3   Access Control Lists</a></p></li><li><p><a class="reference internal" href="#agent-initialization-process" id="id7">4   Agent initialization process</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#registration-process" id="id8">4.1   Registration process</a></p></li><li><p><a class="reference internal" href="#check-in-mode" id="id9">4.2   Check-In mode</a></p></li></ul></li><li><p><a class="reference internal" href="#agent-upgrade-process" id="id10">5   Agent upgrade process</a></p></li><li><p><a class="reference internal" href="#threat-model" id="id11">6   Threat Model</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#strong-gpg-security-model" id="id12">6.1   Strong GPG security model</a></p></li><li><p><a class="reference internal" href="#infrastructure-resiliency" id="id13">6.2   Infrastructure resiliency</a></p></li><li><p><a class="reference internal" href="#no-port-listening" id="id14">6.3   No port listening</a></p></li><li><p><a class="reference internal" href="#protection-of-connections-to-the-relays" id="id15">6.4   Protection of connections to the relays</a></p></li><li><p><a class="reference internal" href="#randomization-of-the-queue-names" id="id16">6.5   Randomization of the queue names</a></p></li><li><p><a class="reference internal" href="#whitelisting-of-agents" id="id17">6.6   Whitelisting of agents</a></p></li><li><p><a class="reference internal" href="#limit-data-extraction-to-a-minimum" id="id18">6.7   Limit data extraction to a minimum</a></p></li></ul></li></ul></div><p>MIG is a platform to perform investigative surgery on remote endpoints.
</style></head><body><h1>Mozilla InvestiGator Concepts &amp; Internal Components</h1><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#actions" id="id1">1   Actions</a></p></li><li><p><a class="reference internal" href="#investigation-workflow" id="id2">2   Investigation workflow</a></p></li><li><p><a class="reference internal" href="#access-control-lists" id="id3">3   Access Control Lists</a></p></li><li><p><a class="reference internal" href="#threat-model" id="id4">4   Threat Model</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#strong-gpg-security-model" id="id5">4.1   Strong GPG security model</a></p></li><li><p><a class="reference internal" href="#infrastructure-resiliency" id="id6">4.2   Infrastructure resiliency</a></p></li><li><p><a class="reference internal" href="#no-port-listening" id="id7">4.3   No port listening</a></p></li><li><p><a class="reference internal" href="#protection-of-connections-to-the-relays" id="id8">4.4   Protection of connections to the relays</a></p></li><li><p><a class="reference internal" href="#randomization-of-the-queue-names" id="id9">4.5   Randomization of the queue names</a></p></li><li><p><a class="reference internal" href="#whitelisting-of-agents" id="id10">4.6   Whitelisting of agents</a></p></li><li><p><a class="reference internal" href="#limit-data-extraction-to-a-minimum" id="id11">4.7   Limit data extraction to a minimum</a></p></li></ul></li></ul></div><p>MIG is a platform to perform investigative surgery on remote endpoints.
It enables investigators to obtain information from large numbers of systems
in parallel, thus accelerating investigation of incidents.</p><p>Besides scalability, MIG is designed to provide strong security primitives:</p><ul><li><p><strong>Access control</strong> is ensured by requiring GPG signatures on all actions. Sensitive
actions can also request signatures from multiple investigators. An attacker
@ -261,7 +263,7 @@ The agents also use the relays to send heartbeat at regular intervals, such that
the scheduler always knows how many agents are alive at a given time.</p><p>The end-to-end workflow is:</p><blockquote><pre>{investigator} -https-&gt; {API} {Scheduler} -amqps-&gt; {Relays} -amqps-&gt; {Agents}
\ /
sql\ /sql
{DATABASE}</pre></blockquote><p>Below is a high-level view of the architecture:</p><img alt=".files/MIG-Arch-Diagram.png" src=".files/MIG-Arch-Diagram.png"><section id="actions-and-commands"><header><h2><a href="#id1">1   Actions and Commands</a></h2></header><section id="actions"><header><h3><a href="#id2">1.1   Actions</a></h3></header><p>Actions are JSON files created by investigator to perform tasks on agents.</p><p>For example, an investigator who wants to verify than root passwords are hashed
{DATABASE}</pre></blockquote><p>Below is a high-level view of the architecture:</p><img alt=".files/MIG-Arch-Diagram.png" src=".files/MIG-Arch-Diagram.png"><section id="actions"><header><h2><a href="#id1">1   Actions</a></h2></header><p>Actions are JSON files created by investigator to perform tasks on agents.</p><p>For example, an investigator who wants to verify than root passwords are hashed
and salted on linux systems, would use the following action:</p><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"verify root password storage method"</span><span class="punctuation">,</span>
<span class="name tag">"target"</span><span class="punctuation">:</span> <span class="literal string double">"agents.queueloc like 'linux.%'"</span><span class="punctuation">,</span>
@ -313,121 +315,10 @@ signed with the investigator's private GPG key. The signature is part of the
action, and used by agents to verify that an action comes from a trusted
investigator. <cite>PGPSignatures</cite> is an array that contains one or more signature
from authorized investigators.</p></li><li><p><strong>validfrom</strong> and <strong>expireafter</strong>: two dates that constrains the validity of the
action to a UTC time window.</p></li></ul></section></section><section id="action-commands-workflow"><header><h2><a href="#id3">2   Action/Commands workflow</a></h2></header><p>The diagram below represents the full workflow from the launch of an action by
action to a UTC time window.</p></li></ul></section><section id="investigation-workflow"><header><h2><a href="#id2">2   Investigation workflow</a></h2></header><p>The diagram below represents the full workflow from the launch of an action by
an investigation, to the retrieval of results from the database. The steps are
explained in the legend of the diagram, and map to various components of MIG.</p><p>Actions are submitted to the API by trusted investigators. PGPSignatures are
verified by the API and each agent prior to running any command.</p><p>View <a class="reference external" href=".files/action_command_flow.svg">full size diagram</a>.</p><object data=".files/action_command_flow.svg" type="image/svg+xml">.files/action_command_flow.svg</object><section id="command-execution-flow-in-agent-and-modules"><header><h3><a href="#id4">2.1   Command execution flow in Agent and Modules</a></h3></header><p>Upon processing of an action, the scheduler will retrieve a list of agents to
send the action to. One action is then derived into multiple commands and sent
to agents.</p><p>An agent receives a command from the scheduler on its personal AMQP queue (1).
It parses the command (2) and extracts all of the operations to perform.
Operations are passed to modules and executed in parallel (3). Rather than
maintaining a state of the running command, the agent create a goroutine and a
channel tasked with receiving the results from the modules. Each modules
published its results inside that channel (4). The result parsing goroutine
receives them, and when it has received all of them, populates the <cite>results</cite> (5)
array of the command with the results from each module, and send the command
back to the scheduler(6).</p><p>When the agent is done running the command, both the channel and the goroutine
are destroyed.</p><blockquote><pre> +-------+ [ - - - - - - A G E N T - - - - - - - - - - - - ]
|command|+----&gt;(listener)
+-------+ |(2)
^ V
|(1) (parser)
| + [ m o d u l e s ]
+---------+ | (3)|----------&gt; op1 +----------------+
|SCHEDULER|+---+ |------------&gt; op2 +--------------|
| |&lt;---+ |--------------&gt; op3 +------------|
+---------+ | +----------------&gt; op4 +----------+
| V(4)
|(6) (receiver)
| |
| V(5)
+ (publisher)
+-------+ /
|results|&lt;-----------------------------------------'
+-------+</pre></blockquote><p>The command received by the agent is composed of a copy of the action described
previously, but signed with the private key of a trusted investigator. It also
contains additional parameters that are specific to the targetted agent, such as
command processing timestamps, name of the agent queue on the message broker,
action and command unique IDs and status and results of the command. Below is an
command derived from the root password checking action, and ran on the host named
'host1.example.net'.</p><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"id"</span><span class="punctuation">:</span> <span class="literal number float">1.427392971126604e+18</span><span class="punctuation">,</span>
<span class="name tag">"action"</span><span class="punctuation">:</span> <span class="punctuation">{</span> <span class="error">...</span> <span class="error">SIGNED</span> <span class="error">COPY</span> <span class="error">OF</span> <span class="error">THE</span> <span class="error">ACTION</span> <span class="error">...</span> <span class="punctuation">},</span>
<span class="name tag">"agent"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"id"</span><span class="punctuation">:</span> <span class="literal number float">1.4271760437936648e+18</span><span class="punctuation">,</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"host1.example.net"</span><span class="punctuation">,</span>
<span class="name tag">"queueloc"</span><span class="punctuation">:</span> <span class="literal string double">"linux.host1.example.net.981alsd19aos1984"</span><span class="punctuation">,</span>
<span class="name tag">"mode"</span><span class="punctuation">:</span> <span class="literal string double">"daemon"</span><span class="punctuation">,</span>
<span class="name tag">"version"</span><span class="punctuation">:</span> <span class="literal string double">"20150324+0d0f88c.prod"</span>
<span class="punctuation">},</span>
<span class="name tag">"status"</span><span class="punctuation">:</span> <span class="literal string double">"success"</span><span class="punctuation">,</span>
<span class="name tag">"results"</span><span class="punctuation">:</span> <span class="punctuation">[</span>
<span class="punctuation">{</span>
<span class="name tag">"foundanything"</span><span class="punctuation">:</span> <span class="keyword constant">true</span><span class="punctuation">,</span>
<span class="name tag">"success"</span><span class="punctuation">:</span> <span class="keyword constant">true</span><span class="punctuation">,</span>
<span class="name tag">"elements"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"root_passwd_hashed_or_disabled"</span><span class="punctuation">:</span> <span class="punctuation">[</span>
<span class="punctuation">{</span>
<span class="name tag">"file"</span><span class="punctuation">:</span> <span class="literal string double">"/etc/shadow"</span><span class="punctuation">,</span>
<span class="name tag">"fileinfo"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"lastmodified"</span><span class="punctuation">:</span> <span class="literal string double">"2015-02-07 01:51:07.17850601 +0000 UTC"</span><span class="punctuation">,</span>
<span class="name tag">"mode"</span><span class="punctuation">:</span> <span class="literal string double">"----------"</span><span class="punctuation">,</span>
<span class="name tag">"size"</span><span class="punctuation">:</span> <span class="literal number integer">1684</span>
<span class="punctuation">},</span>
<span class="name tag">"search"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"contents"</span><span class="punctuation">:</span> <span class="punctuation">[</span>
<span class="literal string double">"root:(\\*|!|\\$(1|2a|5|6)\\$).+"</span>
<span class="punctuation">],</span>
<span class="name tag">"options"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"matchall"</span><span class="punctuation">:</span> <span class="keyword constant">false</span><span class="punctuation">,</span>
<span class="name tag">"matchlimit"</span><span class="punctuation">:</span> <span class="literal number integer">0</span><span class="punctuation">,</span>
<span class="name tag">"maxdepth"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">},</span>
<span class="name tag">"paths"</span><span class="punctuation">:</span> <span class="punctuation">[</span>
<span class="literal string double">"/etc"</span>
<span class="punctuation">]</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span>
<span class="punctuation">]</span>
<span class="punctuation">},</span>
<span class="name tag">"statistics"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"exectime"</span><span class="punctuation">:</span> <span class="literal string double">"2.017849ms"</span><span class="punctuation">,</span>
<span class="name tag">"filescount"</span><span class="punctuation">:</span> <span class="literal number integer">1</span><span class="punctuation">,</span>
<span class="name tag">"openfailed"</span><span class="punctuation">:</span> <span class="literal number integer">0</span><span class="punctuation">,</span>
<span class="name tag">"totalhits"</span><span class="punctuation">:</span> <span class="literal number integer">1</span>
<span class="punctuation">},</span>
<span class="name tag">"errors"</span><span class="punctuation">:</span> <span class="keyword constant">null</span>
<span class="punctuation">}</span>
<span class="punctuation">],</span>
<span class="name tag">"starttime"</span><span class="punctuation">:</span> <span class="literal string double">"2015-03-26T18:02:51.126605Z"</span><span class="punctuation">,</span>
<span class="name tag">"finishtime"</span><span class="punctuation">:</span> <span class="literal string double">"2015-03-26T18:03:00.671232Z"</span>
<span class="punctuation">}</span></code></pre><p>The results of the command show that the file '/etc/shadow' has matched, and
thus "FoundAnything" returned "True".</p><p>The invocation of the file module has completed successfully, which is
represented by <strong>results-&gt;0-&gt;success=true</strong>. In our example, there is only one
operation in the <strong>action-&gt;operations</strong> array, so only one result is present.
When multiple operations are performed, each has its results listed in a
corresponding entry of the results array (operations[0] is in results[0],
operations[1] in results[1], etc...).</p><p>Finally, the agent has performed all operations in the operations array
successfully, and returned <strong>status=success</strong>. Had a failure happened on the
agent, the returned status would be one of "failed", "timeout" or "cancelled".</p></section><section id="command-expiration-timeouts"><header><h3><a href="#id5">2.2   Command expiration &amp; timeouts</a></h3></header><p>To prevent abuse of resources, agents will kill long-running modules after a
given period of time. That timeout is hardcoded in the agent configuration
at compile time and defaults to 5 minutes.</p><pre><code class="code go"><span class="comment single">// timeout after which a module run is killed
</span><span class="keyword declaration">var</span> <span class="name other">MODULETIMEOUT</span> <span class="name other">time</span><span class="punctuation">.</span><span class="name other">Duration</span> <span class="punctuation">=</span> <span class="literal number integer">300</span> <span class="operator">*</span> <span class="name other">time</span><span class="punctuation">.</span><span class="name other">Second</span></code></pre><p>That timeout represents the <strong>maximum</strong> execution time of a single operation. If
an action contains 3 operations, each operation gets its own timeout. But because
operations run in parallel in the agent, the maximum runtime of an action should
be very close to the value of MODULETIMEOUT.</p><p>In a typical deployment, it is safe to increase MODULETIMEOUT to allow for
longer operations. A value of 20 minutes is usual. Make sure to fine tune this
to your environment, and get the approval of your ops team because mig-agent
may end up consuming resources (but never more than 50% of the cpu available on
a system).</p><p>Oftentimes, an investigator will want a timeout that is much shorter than the value
of MODULETIMEOUT. In the MIG command line, the flag <cite>-e</cite> controls the
expiration. It defaults to 5 minutes but can be set to 30 seconds for simple
investigations. When that happens, the agent will calculate an appropriate expiration
for the operations being run. If the expiration set on the action is set to 30 seconds,
the agent will kill operations that run for more than 30 seconds.</p><p>If the expiration is larger than the value of MODULETIMEOUT (for example, 2
hours), then MODULETIMEOUT is used. Setting a long expiration may be useful to
allow agents that only check in periodically to pick up actions long after they
are launched.</p></section></section><section id="access-control-lists"><header><h2><a href="#id6">3   Access Control Lists</a></h2></header><p>Not all keys can perform all actions. The scheduler, for example, sometimes need
verified by the API and each agent prior to running any command.</p><p>View <a class="reference external" href=".files/action_command_flow.svg">full size diagram</a>.</p><object data=".files/action_command_flow.svg" type="image/svg+xml">.files/action_command_flow.svg</object></section><section id="access-control-lists"><header><h2><a href="#id3">3   Access Control Lists</a></h2></header><p>Not all keys can perform all actions. The scheduler, for example, sometimes need
to issue specific actions to agents (such as during the upgrade protocol) but
shouldn't be able to perform more dangerous actions. This is enforced by
an Access Control List, or ACL, stored on the agents. An ACL describes who can
@ -471,127 +362,19 @@ has the following syntax:</p><pre><code class="code json"><span class="punctuati
<span class="punctuation">}</span></code></pre><p>The <cite>default</cite> permission is overridden by module specific permissions.</p><p>The ACL is currently applied to modules. In the future, ACL will have finer
control to authorize access to specific functions of modules. For example, an
investigator could be authorized to call the <cite>regex</cite> function of filechecker
module, but only in <cite>/etc</cite>. This functionality is not implemented yet.</p></section><section id="agent-initialization-process"><header><h2><a href="#id7">4   Agent initialization process</a></h2></header><p>The agent tries to be as autonomous as possible. One of the goal is to ship
agents without requiring external provisioning tools, such as Chef or Puppet.
Therefore, the agent attempts to install itself as a service, and also supports
a builtin upgrade protocol (described in the next section).</p><p>As a portable binary, the agent needs to detect the type of operating system
and init method that is used by an endpoint. Depending on the endpoint,
different initialization methods are used. The diagram below explains the
decision process followed by the agent.</p><img alt=".files/mig-agent-initialization-process.png" src=".files/mig-agent-initialization-process.png"><p>Go does not provide support for running programs in the backgroud. On endpoints
that run upstart, systemd (linux) or launchd (darwin), this is not an issue
because the init daemon takes care of running the agent in the background,
rerouting its file descriptors and restarting on crash. On Windows and System-V,
however, the agent daemonizes by forking itself into <cite>foreground</cite> mode, and
re-forking itself on error (such as loss of connectivity to the relay).
On Windows and System-V, if the agent is killed, it will not be restarted
automatically.</p><section id="registration-process"><header><h3><a href="#id8">4.1   Registration process</a></h3></header><p>The initialization process goes through several environment detection steps
which are used to select the proper init method. Once started, the agent will
send a heartbeat to the public relay, and also store that heartbeat in its
<cite>run</cite> directory. The location of the <cite>run</cite> directory is platform specific.</p><ul><li><p>windows: C:Windows</p></li><li><p>darwin: /Library/Preferences/mig/</p></li><li><p>linux: /var/run/mig/</p></li></ul><p>Below is a sample heartbeat message from a linux agent stored in
<cite>/var/run/mig/mig-agent.ok</cite>.</p><pre><code class="code json"><span class="punctuation">{</span>
<span class="name tag">"destructiontime"</span><span class="punctuation">:</span> <span class="literal string double">"0001-01-01T00:00:00Z"</span><span class="punctuation">,</span>
<span class="name tag">"environment"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"arch"</span><span class="punctuation">:</span> <span class="literal string double">"amd64"</span><span class="punctuation">,</span>
<span class="name tag">"ident"</span><span class="punctuation">:</span> <span class="literal string double">"Red Hat Enterprise Linux Server release 6.5 (Santiago)"</span><span class="punctuation">,</span>
<span class="name tag">"init"</span><span class="punctuation">:</span> <span class="literal string double">"upstart"</span>
<span class="punctuation">},</span>
<span class="name tag">"heartbeatts"</span><span class="punctuation">:</span> <span class="literal string double">"2014-07-31T14:00:20.00442837-07:00"</span><span class="punctuation">,</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"someserver.example.net"</span><span class="punctuation">,</span>
<span class="name tag">"os"</span><span class="punctuation">:</span> <span class="literal string double">"linux"</span><span class="punctuation">,</span>
<span class="name tag">"pid"</span><span class="punctuation">:</span> <span class="literal number integer">26256</span><span class="punctuation">,</span>
<span class="name tag">"queueloc"</span><span class="punctuation">:</span> <span class="literal string double">"linux.someserver.example.net.5hsa811oda"</span><span class="punctuation">,</span>
<span class="name tag">"starttime"</span><span class="punctuation">:</span> <span class="literal string double">"2014-07-30T21:34:48.525449401-07:00"</span><span class="punctuation">,</span>
<span class="name tag">"version"</span><span class="punctuation">:</span> <span class="literal string double">"201407310027+bcbdd94.prod"</span>
<span class="punctuation">}</span></code></pre></section><section id="check-in-mode"><header><h3><a href="#id9">4.2   Check-In mode</a></h3></header><p>In infrastructure where running the agent as a permanent process is not
acceptable, it is possible to run the agent as a cron job. By starting the
agent with the flag <strong>-m agent-checkin</strong>, the agent will connect to the
configured relay, retrieve and run outstanding commands, and exit after 10
seconds of inactivity.</p></section></section><section id="agent-upgrade-process"><header><h2><a href="#id10">5   Agent upgrade process</a></h2></header><p>MIG supports upgrading agents in the wild. The upgrade protocol is designed with
security in mind. The flow diagram below presents a high-level view:</p><blockquote><pre>Investigator Scheduler Agent NewAgent FileServer
+-----------+ +-------+ +---+ +------+ +--------+
| | | | |
| 1.initiate | | | |
|------------------&gt;| | | |
| | 2.send command | | |
| |------------------&gt;| 3.verify | |
| | |--------+ | |
| | | | | |
| | | | | |
| | |&lt;-------+ | |
| | | | |
| | | 4.download | |
| | |--------------------------------------&gt;|
| | | | |
| | | 5.checksum | |
| | |--------+ | |
| | | | | |
| | | | | |
| | |&lt;-------+ | |
| | | | |
| | | 6.exec | |
| | |------------------&gt;| |
| | 7.return own PID | | |
| |&lt;------------------| | |
| | | | |
| |------+ 8.mark | | |
| | | agent as | | |
| | | upgraded | | |
| |&lt;-----+ | | |
| | | | |
| | 9.register | | |
| |&lt;--------------------------------------| |
| | | | |
| |------+10.find dup | | |
| | |agents in | | |
| | |registrations | |
| |&lt;-----+ | | |
| | | | |
| | 11.send command to kill PID old agt| |
| |--------------------------------------&gt;| |
| | | | |
| | 12.acknowledge | | |
| |&lt;--------------------------------------| |</pre></blockquote><p>All upgrade operations are initiated by an investigator (1). The upgrade is
triggered by an action to the upgrade module with the following parameters:</p><pre><code class="code json"><span class="literal string double">"Operations"</span><span class="error">:</span> <span class="punctuation">[</span>
<span class="punctuation">{</span>
<span class="name tag">"Module"</span><span class="punctuation">:</span> <span class="literal string double">"upgrade"</span><span class="punctuation">,</span>
<span class="name tag">"Parameters"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"linux/amd64"</span><span class="punctuation">:</span> <span class="punctuation">{</span>
<span class="name tag">"to_version"</span><span class="punctuation">:</span> <span class="literal string double">"16eb58b-201404021544"</span><span class="punctuation">,</span>
<span class="name tag">"location"</span><span class="punctuation">:</span> <span class="literal string double">"http://localhost/mig/bin/linux/amd64/mig-agent"</span><span class="punctuation">,</span>
<span class="name tag">"checksum"</span><span class="punctuation">:</span> <span class="literal string double">"31fccc576635a29e0a27bbf7416d4f32a0ebaee892475e14708641c0a3620b03"</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span>
<span class="punctuation">]</span><span class="error">,</span></code></pre><ul><li><p>Each OS family and architecture have their own parameters (ex: "linux/amd64",
"darwin/amd64", "windows/386", ...). Then, in each OS/Arch group, we have:</p></li><li><p>to_version is the version an agent should upgrade to</p></li><li><p>location points to a HTTPS address that contains the agent binary</p></li><li><p>checksum is a SHA256 hash of the agent binary to be verified after download</p></li></ul><p>The parameters above are signed using a standard PGP action signature.</p><p>The upgrade action is forwarded to agents (2) like any other action. The action
signature is verified by the agent (3), and the upgrade module is called. The
module downloads the new binary (4), verifies the version and checksum (5) and
installs itself on the system.</p><p>Assuming everything checks in, the old agent executes the binary of the new
agent (6). At that point, two agents are running on the same machine, and the
rest of the protocol is designed to shut down the old agent, and clean up.</p><p>After executing the new agent, the old agent returns a successful result to the
scheduler, and includes its own PID in the results.
The new agent starts by registering with the scheduler (7). This tells the
scheduler that two agents are running on the same node, and one of them must
terminate. The scheduler sends a kill action to both agents with the PID of the
old agent (8). The kill action may be executed twice, but that doesn't matter.
When the scheduler receives the kill results (9), it sends a new action to check
for <cite>mig-agent</cite> processes (10). Only one should be found in the results (11),
and if that is the case, the scheduler tells the agent to remove the binary of
the old agent (12). When the agent returns (13), the upgrade protocol is done.</p><p>If the PID of the old agent lingers on the system, an error is logged for the
investigator to decide what to do next. The scheduler does not attempt to clean
up the situation.</p></section><section id="threat-model"><header><h2><a href="#id11">6   Threat Model</a></h2></header><p>Running an agent as root on a large number of endpoints means that Mozilla
module, but only in <cite>/etc</cite>. This functionality is not implemented yet.</p></section><section id="threat-model"><header><h2><a href="#id4">4   Threat Model</a></h2></header><p>Running an agent as root on a large number of endpoints means that Mozilla
InvestiGator is a target of choice to compromise an infrastructure.
Without proper protections, a vulnerability in the agent or in the platform
could lead to a compromission of the endpoints.</p><p>The architectural choices made in MIG diminish the exposure of the endpoints to
a compromise. And while the risk cannot be reduced to zero entirely, it would
take an attacker direct control on the investigators key material, or be root
on the infrastructure in order to take control of MIG.</p><p>MIG's security controls include:</p><ul><li><p>Strong GPG security model</p></li><li><p>Infrastructure resiliency</p></li><li><p>No port listening</p></li><li><p>Protection of connections to the relays</p></li><li><p>Randomization of the queue names</p></li><li><p>Whitelisting of agents</p></li><li><p>Limit data extraction to a minimum</p></li></ul><section id="strong-gpg-security-model"><header><h3><a href="#id12">6.1   Strong GPG security model</a></h3></header><p>All actions that are passed to the MIG platform and to the agents require
on the infrastructure in order to take control of MIG.</p><p>MIG's security controls include:</p><ul><li><p>Strong GPG security model</p></li><li><p>Infrastructure resiliency</p></li><li><p>No port listening</p></li><li><p>Protection of connections to the relays</p></li><li><p>Randomization of the queue names</p></li><li><p>Whitelisting of agents</p></li><li><p>Limit data extraction to a minimum</p></li></ul><section id="strong-gpg-security-model"><header><h3><a href="#id5">4.1   Strong GPG security model</a></h3></header><p>All actions that are passed to the MIG platform and to the agents require
valid GPG signatures from one or more trusted investigators. The public keys of
trusted investigators are hardcoded in the agents, making it almost impossible
to override without root access to the endpoints, or access to an investigator's
private key. The GPG private keys are never seen by the MIG platform (API,
Scheduler, Database or Relays). A compromise of the platform would not lead to
an attacker taking control of the agents and compromising the endpoints.</p></section><section id="infrastructure-resiliency"><header><h3><a href="#id13">6.2   Infrastructure resiliency</a></h3></header><p>One of the design goal of MIG is to make each components as stateless as
an attacker taking control of the agents and compromising the endpoints.</p></section><section id="infrastructure-resiliency"><header><h3><a href="#id6">4.2   Infrastructure resiliency</a></h3></header><p>One of the design goal of MIG is to make each components as stateless as
possible. The database is used as a primary data store, and the schedulers and
relays keep data in transit in their respective cache. But any of these
components can go down and be rebuilt without compromising the resiliency of
@ -605,12 +388,12 @@ relay whenever they chose to, and pick up outstanding tasks.</p><p>If the relays
reconnect at regular intervals continuously. It is trivial to rebuild
a fresh rabbitmq cluster, even on a new IP space, as long as the FQDN of the
cluster, and the TLS cert/key and credentials of the AMQPS access point
remain the same.</p></section><section id="no-port-listening"><header><h3><a href="#id14">6.3   No port listening</a></h3></header><p>The agents do not accept incoming connections. There is no listening port that
remain the same.</p></section><section id="no-port-listening"><header><h3><a href="#id7">4.3   No port listening</a></h3></header><p>The agents do not accept incoming connections. There is no listening port that
an attacker could use to exploit a vulnerability in the agent. Instead, the
agent connects to the platform by establishing an outbound connection to the
relays. The connection uses TLS, making it theorically impossible for an
attacker to MITM without access to the PKI and DNS, both of which are not
part of the MIG platform.</p></section><section id="protection-of-connections-to-the-relays"><header><h3><a href="#id15">6.4   Protection of connections to the relays</a></h3></header><p>The rabbitmq relay of a MIG infrastructure may very well be listening on the
part of the MIG platform.</p></section><section id="protection-of-connections-to-the-relays"><header><h3><a href="#id8">4.4   Protection of connections to the relays</a></h3></header><p>The rabbitmq relay of a MIG infrastructure may very well be listening on the
public internet. This is used when MIG agents are distributed into various
environments, as opposed to concentrated on a single network location. RabbitMQ
and Erlang provide a stable network stack, but are not shielded from a network
@ -623,7 +406,7 @@ agent will present a username and password to open the AMQP connection. Again,
these credentials are shared across all agents, and are not used to authenticate
individual agents. Their role is to assign an ACL to the agent.
The ACL limits the AMQP action an agent can perform on the cluster.
See <a class="reference external" href="configuration.rst">rabbitmq configuration</a> for more information.</p></section><section id="randomization-of-the-queue-names"><header><h3><a href="#id16">6.5   Randomization of the queue names</a></h3></header><p>The protections above limit the exposure of the AMQP endpoint, but since the
See <a class="reference external" href="configuration.rst">rabbitmq configuration</a> for more information.</p></section><section id="randomization-of-the-queue-names"><header><h3><a href="#id9">4.5   Randomization of the queue names</a></h3></header><p>The protections above limit the exposure of the AMQP endpoint, but since the
secrets are shared across all agents, the possibility still exists that an
attacker gains access to the secrets, and establish a connection to the relays.</p><p>Such access would have very limited capabilities. It cannot be used to publish
commands to the agents, because publication is ACL-limited to the scheduler.
@ -631,7 +414,7 @@ It can be used to publish fake results to the scheduler, or listen on the
agent queue for incoming commands.</p><p>Both are made difficult by prepending a random number to the name of an agent
queue. An agent queue is named using the following scheme:</p><blockquote><p><cite>mig.agt.&lt;OS family&gt;.&lt;Hostname&gt;.&lt;uid&gt;</cite></p></blockquote><p>The OS and hostname of a given agent are easy to guess, but the uid isn't.
The UID is a 64 bits integer composed of nanosecond timestamps and a random 32
bits integer, chosen by the agent on first start. It is specific to an endpoint.</p></section><section id="whitelisting-of-agents"><header><h3><a href="#id17">6.6   Whitelisting of agents</a></h3></header><p>At the moment, MIG does not provide a strong mechanism to authenticate agents.
bits integer, chosen by the agent on first start. It is specific to an endpoint.</p></section><section id="whitelisting-of-agents"><header><h3><a href="#id10">4.6   Whitelisting of agents</a></h3></header><p>At the moment, MIG does not provide a strong mechanism to authenticate agents.
It is a work in progress, but for now agents are whitelisted in the scheduler
using the queuelocs that are advertised in the heartbeat messages. Spoofing the
queueloc string is difficult, because it contains a random value that is
@ -640,7 +423,7 @@ order to spoof an agent's identity. This method provides a basic access control
mechanism. The long term goal is to allow the scheduler to call an external database
to authorize agents. In AWS, the scheduler could call the AWS API to verify that
a given agent does indeed exist in the infrastructure. In a traditional datacenter,
this could be an inventory database.</p></section><section id="limit-data-extraction-to-a-minimum"><header><h3><a href="#id18">6.7   Limit data extraction to a minimum</a></h3></header><p>Agents are not <cite>meant</cite> to retrieve raw data from their endpoints. This is more
this could be an inventory database.</p></section><section id="limit-data-extraction-to-a-minimum"><header><h3><a href="#id11">4.7   Limit data extraction to a minimum</a></h3></header><p>Agents are not <cite>meant</cite> to retrieve raw data from their endpoints. This is more
of a good practice rather than a technical limitation. The modules shipped with
the agent are meant to return boolean answers of the type "match" or "no match".</p><p>It could be argued that answering "match" on sensitive requests is similar to
extracting data from the agents. MIG does not solve this issue.. It is the

Просмотреть файл

@ -1,6 +1,5 @@
Mozilla InvestiGator Deployment and Configuration Documentation
===============================================================
:Author: Julien Vehent <jvehent@mozilla.com>
.. sectnum::
.. contents:: Table of Contents

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

495
doc/console.rst Normal file
Просмотреть файл

@ -0,0 +1,495 @@
===========
MIG CONSOLE
===========
.. sectnum::
.. contents:: Table of contents
`mig-console` is a terminal-based client to the MIG API. It provides a complete
access to data stored in MIG and exposed by the API, in an interface that is
easy to use. Similar to the command line client, `mig-console` reads its
configuration from $HOME/.migrc and will prompt the user to create one if it
doesn't exists.
The base screen of the API presents a dashboard of the current state of the
infrastructure. It includes the number of agents and endpoints, broken down
by version of the agent ,and a list of the latest actions that have run.
Underneath the dasboard, the user is invited to interact in a prompt that
starts with **mig>**.
.. code:: bash
$ mig-console -c ~/.migrc-lnw
## ## _.---._ .---.
# # # /-\ ---|| | /\ __...---' .---. '---'-. '.
# #| | / || | /--\ .-''__.--' _.'( | )'. '. '._ :
# # \_/ ---| \_ \_/ \ .'__-'_ .--'' ._'---'_.-. '. '-'.
### ~ -._ -._''---. -. '-._ '.
# |\ |\ /---------| ~ -.._ _ _ _ ..-_ '. '-._''--.._
# | \| \ / |- |__ | | -~ -._ '-. -. '-._''--.._.--''.
###| \ \/ ---__| | | ~ ~-.__ -._ '-.__ '. '. :
##### ~~ ~---...__ _ ._ .' '.
# /\ --- /-\ |--|---- ~ ~--.....--~
# ### /--\ | | ||-\ //
#####/ \ | \_/ | \//__
+------
| Agents & Endpoints summary:
| * 2 online agents on 2 endpoints
| * 0 idle agents on 0 endpoints
| * 0 endpoints are running 2 or more agents
| * 0 endpoints appeared over the last 7 days
| * 0 endpoints disappeared over the last 7 days
| * 0 endpoints have been flapping
| Online agents by version:
| * version 20150909+f2456f5.dev: 2 agents
| Idle agents by version:
|
| Latest Actions:
| ---- ID ---- + ---- Name ---- + -Sent- + ---- Date ---- + ---- Investigators ----
| 4999271350274 file -c /home/ulfr/.migrc-l... 2 2015-09-29T15:40:35Z Julien Vehent
| 4964811669519 file -c /home/ulfr/.migrc-l... 2 2015-09-23T13:37:16Z Julien Vehent
| 4964811669506 file -c /home/ulfr/.migrc-l... 2 2015-09-23T13:37:03Z Julien Vehent
| 4964764024853 file -c /home/ulfr/.migrc-l... 2 2015-09-23T13:25:26Z Julien Vehent
| 4964764024834 file -c /home/ulfr/.migrc-l... 2 2015-09-23T13:24:57Z Julien Vehent
| 4949328330767 file -c /home/ulfr/.migrc-l... 2 2015-09-20T19:59:39Z Julien Vehent
| 4949328330754 file -c /home/ulfr/.migrc-l... 2 2015-09-20T19:59:25Z Julien Vehent
| 4948324450316 file -c /home/ulfr/.migrc-l... 2 2015-09-20T19:45:51Z Julien Vehent
| 4948324450307 file -c /home/ulfr/.migrc-l... 2 2015-09-20T19:33:17Z Julien Vehent
| 4947944865794 file -c /home/ulfr/.migrc-l... 2 2015-09-20T14:07:36Z Julien Vehent
+------
Connected to https://jaffa.linuxwall.info/api/v1/. Exit with ctrl+d. Type help for help.
mig>
Entering **help** here, or on any other mode of the console, provides the user
with a list of available functionalities::
mig> help
The following orders are available:
action <id> enter interactive action reader mode for action <id>
agent <id> enter interactive agent reader mode for agent <id>
create action create a new action
create investigator create a new investigator, will prompt for name and public key
command <id> enter command reader mode for command <id>
exit leave
help show this help
history <count> print last <count> entries in history. count=10 by default.
investigator <id> enter interactive investigator management mode for investigator <id>
query <uri> send a raw query string, without the base url, to the api
search <search> perform a search. see "search help" for more information.
showcfg display running configuration
status display platform status: connected agents, latest actions, ...
For example, let's review action id 4999271350274::
mig> action 4999271350274
Entering action reader mode. Type exit or press ctrl+d to leave. help may help.
Action: 'file -c /home/ulfr/.migrc-lnw -path /etc -name ^passwd -content julien '.
Launched by 'Julien Vehent' on '2015-09-29 11:40:31.792627 -0400 EDT'.
Status 'completed'.
2 sent, 2 done, 2 succeeded
action 274>
When entering the action reader mode, a short summary of the action is displayed
to the user. We can see that the action was launched by "Julien Vehent" on 2 agents
and that it completed. The prompt is changed to **action 274** to indicate that
we are now in action reader mode. Entering **help** here provides a list of
functionalities specific to that mode::
The following orders are available:
command <id> jump to command reader mode for command <id>
copy enter action launcher mode using current action as template
counters display the counters of the action
details display the details of the action, including status & times
exit exit this mode (also works with ctrl+d)
help show this help
investigators print the list of investigators that signed the action
json show the json of the action
list <show> returns the list of commands with their status
<show>: * set to "all" to get all results (default)
* set to "found" to only display positive results
* set to "notfound" for negative results
list can be followed by a 'filter' pipe:
ex: ls | grep server1.(dom1|dom2) | grep -v example.net
r refresh the action (get latest version from upstream)
results <show> <render> display results of all commands
<show>: * set to "all" to get all results (default)
* set to "found" to only display positive results
* set to "notfound" for negative results
<render>: * set to "text" to print results in console (default)
* set to "map" to generate an open a google map
times show the various timestamps of the action
It is possible to review results by entering **results**. If we only want results
from agents that have found *something*, we can use **results found**. If we
want those results inside a Google Map, enter **results found map**.
The raw json of the action is available via **json**.
To get a list of agents on which the action ran, use **list all**. You can filter
the list using **list found** and **list notfound** to only get agents that have,
or have not, found something. This command also supports a very basic `grep`.
To continue, let's list the agents that have found *something*::
action 274> list found
..
---- Command ID ---- ---- Agent Name & ID----
4999268991155 server1.example.net [4942082344151]
4999268991154 server2.example.net [4942082360682]
2 agents have found things
We can inspect the command that ran on server1 by entering its ID::
action 274> command 4999268991155
Entering command reader mode. Type exit or press ctrl+d to leave. help may help.
Command 4999268991155 ran on agent 'server1.example.net' based on action 'file -c /home/ulfr/.migrc-lnw -path /etc -name ^passwd -content julien '
command 155>
As you can see, the console mode has changed from `action 274` to
`command 155`. This mode has its own set of functionalities that you
can explore via **help**.
Creating actions
----------------
The console provides a fine grained action generation interface. There
are two ways to create a new action:
1. From the **mig>** mode, create a new empty action using **create action**.
2. From the **action>** reader mode, when reviewing a previous action,
copy it to a new action using **copy**.
Both methods enter the action launcher mode. Method 2 only enters this
mode with an preset action, rather than an empty one::
mig> create action
Entering action launcher with empty template
Type exit or press ctrl+d to leave. help may help.
launcher> help
The following orders are available:
addoperation <module> append a new operation of type <module> to the action operations
listagents list agents targetted by an action
deloperation <opnum> remove operation numbered <opnum> from operations array, count starts at zero
details display the action details
exit exit this mode
help show this help
json <pack> show the json of the action
launch <nofollow> launch the action. to return before completion, add "nofollow"
load <path> load an action from a file at <path>
setname <name> set the name of the action
settarget <target> set the target
settimes <start> <stop> set the validity and expiration dates
sign PGP sign the action
times show the various timestamps of the action
Action parameters can be edited prior to launching it:
* **setname** sets the name field of the action to a new string::
launcher> setname Test action that pings google.com
* **settarget** sets the target of the action. The target is evaluated
right away, and a list of targeted agents can be obtained via **listagents**::
launcher> settarget environment->>'os'='linux' and mode='daemon'
2 agents will be targetted. To get the list, use 'listagents'
launcher> listagents
---- ID ---- + ---- Name -------
4942082360682 server1.example.net
4942082344151 server2.example.net
* **settimes** defines the validity period of the action using
<start> and <stop> parameters. <start> can be set to "now", and <stop>
can be a duration relative to "now"::
launcher> settimes now +10m
launcher> times
Valid from '2015-10-06 13:09:36.189134664 +0000 UTC' until '2015-10-06 13:20:36.189134664 +0000 UTC'
Started on '0001-01-01 00:00:00 +0000 UTC'
Last updated '0001-01-01 00:00:00 +0000 UTC'
Finished on '0001-01-01 00:00:00 +0000 UTC'
* **addoperation <module>** is used to add a new operation to the action.
<module> must be a know MIG module, such as `file`, `netstat`, `memory`,
`scribe`, `ping`, `timedrift`, etc... When adding an operation, the console
enters a new module-specific mode that takes the operation parameters. For
example, this is how to add a ping operation that sends 5 TCP requests to
google.com::
launcher> addoperation ping
Ping module checks connectivity between an endpoint and a remote host. It supports
icmp, tcp and udp ping. See doc at http://mig.mozilla.org/doc/module_ping.html
d <ip/fqdn> Destination Address can be ipv4, ipv6 or FQDN
example: d www.mozilla.org
d 63.245.217.105
dp <port> For TCP and UDP, specifies the port to test connectivity to
example: dp 53
p <protocol> Protocol to use for the ping. This can be "icmp", "tcp" or "udp"
example: p udp
c <count> Number of ping/connection attempts. Defaults to 3.
example: c 5
t <timeout> Connection timeout in seconds. Defaults to 5.
example: t 10
ping> p tcp
ping> d google.com
ping> c 5
ping> done
Inserting ping operation with parameters:
{
"module": "ping",
"parameters": {
"destination": google.com",
"protocol": "tcp",
"count": 5
}
}
* **deloperation** removes an operation from the action operations list.
Use **json** to visualize the list, and remove an operation using its
position in the list, starting with zero::
launcher> json
{
"id": 0,
"name": "Test action that pings google.com",
"target": "environment-\u003e\u003e'os'='linux' and mode='daemon'",
"description": {},
"threat": {},
"validfrom": "2015-10-06T13:09:36.189134664Z",
"expireafter": "2015-10-06T13:20:36.189134664Z",
"operations": [
{
"module": "ping",
"parameters": {
"destination": "google.com",
"protocol": "tcp",
"count": 5
}
}
],
"pgpsignatures": null,
"starttime": "0001-01-01T00:00:00Z",
"finishtime": "0001-01-01T00:00:00Z",
"lastupdatetime": "0001-01-01T00:00:00Z",
"counters": {}
}
launcher> deloperation 0
launcher> json
{
"id": 0,
"name": "Test action that pings google.com",
"target": "environment-\u003e\u003e'os'='linux' and mode='daemon'",
"description": {},
"threat": {},
"validfrom": "2015-10-06T13:09:36.189134664Z",
"expireafter": "2015-10-06T13:20:36.189134664Z",
"operations": [],
"pgpsignatures": null,
"starttime": "0001-01-01T00:00:00Z",
"finishtime": "0001-01-01T00:00:00Z",
"lastupdatetime": "0001-01-01T00:00:00Z",
"counters": {}
}
When ready to launch the action, type **launch**. The console will enter
follower mode and print the progress of the action. When completed, the
console will directly enter action reader mode, where you can type **results**
to view the results::
launcher> launch
Action 'Test action that pings google.com' successfully launched with ID '5033038708749' on target 'environment->>'os'='linux' and mode='daemon''
Following action ID 5033038708749.status=inflight...50%.status=completed
- 100.0% done in 10.004244071s
2 sent, 2 done, 2 succeeded
Entering action reader mode. Type exit or press ctrl+d to leave. help may help.
Action: 'Test action that pings google.com'.
Launched by 'Julien Vehent' on '2015-10-06 09:12:31.608546 -0400 EDT'.
Status 'completed'.
2 sent, 2 done, 2 succeeded
action 749> results
server2.example.net ping of google.com failed. Target is no reachable.
server2.example.net command success
server1.example.net ping of google.com failed. Target is no reachable.
server1.example.net command success
2 agents have all results
Searching
---------
Return to the base mode using ctrl+d or **exit**::
command 155> exit
exit
action 274> exit
exit
mig>
When in **mig>** mode, you can use the **search** functionality to
explore passed actions and commands, or find investigators. Details
of how to run searches can be obtains via **mig> search help**.
Searches can be slow if your dataset is very large, so make sure to
use time windows and limits to help speed up a search::
mig> search action where investigatorname=%vehent% and agentname=server1% and after=2015-09-01T00:00:00Z and before=2015-10-01T00:00:00Z
Searching action after 2015-09-01T00:00:00Z and before 2015-10-01T00:00:00Z, limited to 100 results
----- ID ----- + -------- Action Name ------- + ----------- Target ---------- + ---- Investigators ---- + - Sent - + - Status - + --- Last Updated ---
4999271350274 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-29T15:40:35Z
4964811669519 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-23T13:37:16Z
4964811669506 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-23T13:37:03Z
4964764024853 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 inflight 2015-09-23T13:25:26Z
4964764024834 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 inflight 2015-09-23T13:24:57Z
4949328330767 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T19:59:39Z
4949328330754 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T19:59:25Z
4948324450316 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T19:45:51Z
4948324450307 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T19:33:17Z
4947944865794 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T14:07:36Z
4947909869570 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T13:58:41Z
4947901022223 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T13:56:42Z
4947901022210 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T13:56:26Z
4947890798596 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T13:55:02Z
4885615083769 timedrift -c /home/ulfr/.mi... status='online' AND mode='d... Julien Vehent 3 completed 2015-09-09T17:02:56Z
4885615083755 pkg -c /home/ulfr/.migrc-ln... status='online' AND mode='d... Julien Vehent 3 completed 2015-09-09T17:01:33Z
4885615083739 memory -c /home/ulfr/.migrc... status='online' AND mode='d... Julien Vehent 3 completed 2015-09-09T17:01:04Z
4885615083724 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 3 completed 2015-09-09T16:58:00Z
Managing investigators
----------------------
The console can be used to create new investigators, active and
disable them, and well as review their activity.
To review the activity of an investigator, find its ID using the
search command and enter investigator mode::
mig> search investigator where name=%vehent%
Searching investigator after 2011-03-31T13:16:55Z and before 2020-04-12T13:16:55Z, limited to 100 results
- ID - + ---- Name ---- + --- Status ---
2 Julien Vehent active
mig> investigator 2
Entering investigator mode. Type exit or press ctrl+d to leave. help may help.
Investigator 2 named 'Julien Vehent'
inv 2> help
The following orders are available:
details print the details of the investigator
exit exit this mode
help show this help
lastactions <limit> print the last actions ran by the investigator. limit=10 by default.
pubkey show the armored public key of the investigator
r refresh the investigator (get latest version from upstream)
setstatus <status> changes the status of the investigator to <status> (can be 'active' or 'disabled')
The command **lastactions** will print the latest activity of this investigator::
inv 2> lastactions
----- ID ----- + -------- Action Name ------- + ----------- Target ---------- + ---- Date ---- + -- Status --
5033038708749 Test action that pings goog... environment->>'os'='linux' ... 2015-10-06T09:12:31-04:00 completed
4999271350274 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-29T11:40:31-04:00 completed
4964811669519 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-23T09:37:12-04:00 completed
4964811669506 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-23T09:36:59-04:00 completed
4964764024853 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-23T09:25:22-04:00 inflight
4964764024834 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-23T09:24:52-04:00 inflight
4949328330767 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-20T15:59:35-04:00 completed
4949328330754 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-20T15:59:21-04:00 completed
4948324450316 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-20T15:45:47-04:00 completed
4948324450307 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-20T15:33:13-04:00 completed
To disable him, use **setstatus disabled**. Disabled investigators are no longer
allowed to send investigations via the API::
inv 2> setstatus disabled
Investigator status set to disabled
inv 2> details
Investigator ID 2
name Julien Vehent
status disabled
key id E60892BB9BD89A69F759A1A0A3D652173B763E8F
created 2015-09-09 09:53:28.989481 -0400 EDT
modified 2015-09-09 09:53:28.989481 -0400 EDT
inv 2> setstatus active
Investigator status set to active
Creating investigators
~~~~~~~~~~~~~~~~~~~~~~
To create a new investigator, go back to **mig>** mode and type
**create investigator**. The console will prompt the name of the new
investigator as well as the location of her public PGP key. You can either
provide a local path to the public key file on disk, on provide a fingerprint
in the format "0x<40 char sha1 hash>". When a fingerprint is provided, the
console will attempt to retrieve the key from the keyserver `gpg.mozilla.org`::
mig> create investigator
Entering investigator creation mode. Please provide the full name
and the public key of the new investigator.
name> Bob Kelso
Name: 'Bob Kelso'
Please provide a public key. You can either provide a local path to the
armored public key file, or a full length PGP fingerprint.
example:
pubkey> 0x716CFA6BA8EBB21E860AE231645090E64367737B
pubkey> 0x716CFA6BA8EBB21E860AE231645090E64367737B
retrieving public key from http://gpg.mozilla.org
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: SKS 1.1.5
Comment: Hostname: keyserver.mozilla.org
mQENBEbv+5sBCADNHPvUIajRoxb/qylLrzwm9e+9sB8R/jhY4gxOzGZRDHECPvNeTUd9eogV
n24rQDTWowkE+t9sW7vlD3TUWdBEAhXEpDZBfzlTBWIzEb1m3hwPOQM10ZNX6jPS1WlGsfoE
LsUC0HmFTtOx4b5os9mIYbsjsDWd/JZjn0yUIv4eb28+fle6BkbgqIotLW4d1gTrxVlFc3be
m+4OqimQ/v2LZDV+uObEkbh4UvmTtOCCx8zAOyZohPmICUbmJBc8KWWhzLOo8b9ns/GqP41q
/9IuTQDXP2GUAKXzBKSdQiNzJP8Skfu4tPyGsGJSErprPC9t43HPPUgfeW9/sfuaw+vnABEB
AAG0JUp1bGllbiBWRUhFTlQgPGp1bGllbkBsaW51eHdhbGwuaW5mbz6JATYEEwECACAFAkbv
+5sCGy8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRBkUJDmQ2dze5U9CADK4Z6X02TP9afJ
AyWF32zM3UdMksJ/F2wuo2HBHT0iOomw4ecNzHyO1P5BTglm5LC5ZZrV+Dx6Jve75JiSDTSD
V3AhpR+M83rw8YKkeUrbTvfsy3+qhB7HYNIbCKT0lgAAL05SmDnYwYMQIV+p3T0F8BgGhkGT
vHdKLhzEhKNOMaMCwCd1SsiBepA976oBUp9h5Vt6TEFyG6hCcFP90DFjNlK17yMNjbdrgyd6
FkGEePKK3RhaLxcPShAgCnYzYYMABLYu1ow5AxxtEJTBHkJFkIzE9XM/lmyekYhWfX/Q4jpn
1aiiVlf2klZlFSFy/TXuuQH1JO3YlKo9uHjlvSQb
=+Ru1
-----END PGP PUBLIC KEY BLOCK-----
create investigator? (y/n)> y
Investigator 'Bob Kelso' successfully created with ID 4
mig> investigator 4
Entering investigator mode. Type exit or press ctrl+d to leave. help may help.
Investigator 4 named 'Bob Kelso'
inv 4> details
Investigator ID 4
name Bob Kelso
status active
key id 716CFA6BA8EBB21E860AE231645090E64367737B
created 2015-10-06 09:23:14.473307 -0400 EDT
modified 2015-10-06 09:23:14.473307 -0400 EDT
The new investigator now has access to the API.

605
doc/console.rst.html Normal file
Просмотреть файл

@ -0,0 +1,605 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
color: #eaeaea;
font: 16px;
line-height: 1.5em;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
}
#table-of-contents ul {
line-height: 1;
}
/* General & 'Reset' Stuff */
.container {
width: 95%;
max-width: 1000px;
margin: 0 auto;
}
section {
display: block;
margin: 0 0 20px 0;
}
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
/*margin: 0;*/
}
/* Header, <header>
* header - container
* h1 - project name
* h2 - project description
* */
header {
background: rgba(0, 0, 0, 0.1);
width: 100%;
/*border-bottom: 1px dashed #b5e853;*/
/*padding: 20px 0;
* margin: 0 0 40px 0;*/
padding: 5px 0;
margin: 0 0 10px 0;
}
header h1 {
font-size: 30px;
line-height: 1.5;
margin: 0 0 0 -40px;
font-weight: bold;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
/*color: #b5e853;*/
color: #089d00;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1),
0 0 5px rgba(181, 232, 83, 0.1),
0 0 10px rgba(181, 232, 83, 0.1);
letter-spacing: -1px;
-webkit-font-smoothing: antialiased;
}
header h1:before {
content: "./ ";
font-size: 24px;
}
header h2 {
font-size: 18px;
font-weight: 300;
}
/* Main Content
* */
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {
max-width: 100%
}
h2 a {
font-weight: bold;
color: #8AB638;
line-height: 1.4em;
font-size: 1.4em;
}
h3 a, h4 a, h5 a, h6 a {
font-weight: bold;
color: #934500;
line-height: 1.4em;
}
h1 {
font-size: 30px;
}
h2 {
font-size: 28px;
border-bottom: 1px dashed #b5e853;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 14px;
}
h5 {
font-size: 12px;
text-transform: uppercase;
margin: 0 0 5px 0;
}
h6 {
font-size: 12px;
text-transform: uppercase;
color: #999;
margin: 0 0 5px 0;
}
dt {
font-style: italic;
font-weight: bold;
}
/*
ul li {
list-style: none;
}
*/
/*
ul li:before {
content: ">>";
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
font-size: 13px;
color: #b5e853;
margin-left: -37px;
margin-right: 21px;
line-height: 16px;
}
*/
blockquote {
color: #aaa;
padding-left: 10px;
border-left: 1px dotted #666;
}
pre {
background: rgba(0, 0, 0, 0.9);
border: 1px solid rgba(255, 255, 255, 0.15);
padding: 10px;
font-size: 14px;
//color: #b5e853;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
text-wrap: normal;
overflow: auto;
overflow-y: hidden;
}
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
code .ln { color: grey; } /* line numbers */
/*code, code { background-color: #eeeeee }*/
code .comment, code .comment, code .c1 { color: #999; }
code .keyword, code .keyword, code .kd, code .kn, code .k, code .o { color: #FC8F3F; font-weight: bold;}
code .nb { color: #c45918;}
code .s {color: #0a77c4;}
code .punctuation, code .p { color: white;}
code .literal.string, code .literal.string { color: #40BF32; }
code .name, code .name.builtin, code .nx { color: white; }
code .deleted, code .deleted { background-color: #DEB0A1}
code .inserted, code .inserted { background-color: #A3D289}
table {
width: 100%;
margin: 0 0 20px 0;
}
th {
text-align: left;
border-bottom: 1px dashed #b5e853;
padding: 5px 10px;
}
td {
padding: 5px 10px;
}
hr {
height: 0;
border: 0;
border-bottom: 1px dashed #b5e853;
color: #b5e853;
}
/* Links
* a, a:hover, a:visited
* */
a {
color: #63c0f5;
/*text-shadow: 0 0 5px rgba(104, 182, 255, 0.5);*/
text-decoration: none;
}
cite {
color: #00FF4A;
}
strong {
color: #C64216;
}
</style></head><body><h1>MIG CONSOLE</h1><div class="contents" id="table-of-contents"><h2>Table of contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#creating-actions" id="id1">1   Creating actions</a></p></li><li><p><a class="reference internal" href="#searching" id="id2">2   Searching</a></p></li><li><p><a class="reference internal" href="#managing-investigators" id="id3">3   Managing investigators</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#creating-investigators" id="id4">3.1   Creating investigators</a></p></li></ul></li></ul></div><p><cite>mig-console</cite> is a terminal-based client to the MIG API. It provides a complete
access to data stored in MIG and exposed by the API, in an interface that is
easy to use. Similar to the command line client, <cite>mig-console</cite> reads its
configuration from $HOME/.migrc and will prompt the user to create one if it
doesn't exists.</p><p>The base screen of the API presents a dashboard of the current state of the
infrastructure. It includes the number of agents and endpoints, broken down
by version of the agent ,and a list of the latest actions that have run.</p><p>Underneath the dasboard, the user is invited to interact in a prompt that
starts with <strong>mig&gt;</strong>.</p><pre><code class="code bash"><span class="name variable">$ </span>mig-console -c ~/.migrc-lnw
<span class="comment">## ## _.---._ .---.
# # # /-\ ---|| | /\ __...---' .---. '---'-. '.
# #| | / || | /--\ .-''__.--' _.'( | )'. '. '._ :
# # \_/ ---| \_ \_/ \ .'__-'_ .--'' ._'---'_.-. '. '-'.
</span> <span class="comment">### ~ -._ -._''---. -. '-._ '.
</span> <span class="comment"># |\ |\ /---------| ~ -.._ _ _ _ ..-_ '. '-._''--.._
</span> <span class="comment"># | \| \ / |- |__ | | -~ -._ '-. -. '-._''--.._.--''.
</span> <span class="comment">###| \ \/ ---__| | | ~ ~-.__ -._ '-.__ '. '. :
</span> <span class="comment">##### ~~ ~---...__ _ ._ .' '.
</span> <span class="comment"># /\ --- /-\ |--|---- ~ ~--.....--~
</span> <span class="comment"># ### /--\ | | ||-\ //
</span> <span class="comment">#####/ \ | \_/ | \//__
</span>+------
<span class="punctuation">|</span> Agents <span class="punctuation">&amp;</span> Endpoints summary:
<span class="punctuation">|</span> * <span class="literal number">2</span> online agents on <span class="literal number">2</span> endpoints
<span class="punctuation">|</span> * <span class="literal number">0</span> idle agents on <span class="literal number">0</span> endpoints
<span class="punctuation">|</span> * <span class="literal number">0</span> endpoints are running <span class="literal number">2</span> or more agents
<span class="punctuation">|</span> * <span class="literal number">0</span> endpoints appeared over the last <span class="literal number">7</span> days
<span class="punctuation">|</span> * <span class="literal number">0</span> endpoints disappeared over the last <span class="literal number">7</span> days
<span class="punctuation">|</span> * <span class="literal number">0</span> endpoints have been flapping
<span class="punctuation">|</span> Online agents by version:
<span class="punctuation">|</span> * version 20150909+f2456f5.dev: <span class="literal number">2</span> agents
<span class="punctuation">|</span> Idle agents by version:
<span class="punctuation">|</span>
<span class="punctuation">|</span> Latest Actions:
<span class="punctuation">|</span> ---- ID ---- + ---- Name ---- + -Sent- + ---- Date ---- + ---- Investigators ----
<span class="punctuation">|</span> <span class="literal number">4999271350274</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-29T15:40:35Z Julien Vehent
<span class="punctuation">|</span> <span class="literal number">4964811669519</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-23T13:37:16Z Julien Vehent
<span class="punctuation">|</span> <span class="literal number">4964811669506</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-23T13:37:03Z Julien Vehent
<span class="punctuation">|</span> <span class="literal number">4964764024853</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-23T13:25:26Z Julien Vehent
<span class="punctuation">|</span> <span class="literal number">4964764024834</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-23T13:24:57Z Julien Vehent
<span class="punctuation">|</span> <span class="literal number">4949328330767</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-20T19:59:39Z Julien Vehent
<span class="punctuation">|</span> <span class="literal number">4949328330754</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-20T19:59:25Z Julien Vehent
<span class="punctuation">|</span> <span class="literal number">4948324450316</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-20T19:45:51Z Julien Vehent
<span class="punctuation">|</span> <span class="literal number">4948324450307</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-20T19:33:17Z Julien Vehent
<span class="punctuation">|</span> <span class="literal number">4947944865794</span> file -c /home/ulfr/.migrc-l... <span class="literal number">2</span> 2015-09-20T14:07:36Z Julien Vehent
+------
Connected to https://jaffa.linuxwall.info/api/v1/. Exit with ctrl+d. Type <span class="name builtin">help </span><span class="keyword">for</span> help.
mig&gt;</code></pre><p>Entering <strong>help</strong> here, or on any other mode of the console, provides the user
with a list of available functionalities:</p><pre>mig&gt; help
The following orders are available:
action &lt;id&gt; enter interactive action reader mode for action &lt;id&gt;
agent &lt;id&gt; enter interactive agent reader mode for agent &lt;id&gt;
create action create a new action
create investigator create a new investigator, will prompt for name and public key
command &lt;id&gt; enter command reader mode for command &lt;id&gt;
exit leave
help show this help
history &lt;count&gt; print last &lt;count&gt; entries in history. count=10 by default.
investigator &lt;id&gt; enter interactive investigator management mode for investigator &lt;id&gt;
query &lt;uri&gt; send a raw query string, without the base url, to the api
search &lt;search&gt; perform a search. see "search help" for more information.
showcfg display running configuration
status display platform status: connected agents, latest actions, ...</pre><p>For example, let's review action id 4999271350274:</p><pre>mig&gt; action 4999271350274
Entering action reader mode. Type exit or press ctrl+d to leave. help may help.
Action: 'file -c /home/ulfr/.migrc-lnw -path /etc -name ^passwd -content julien '.
Launched by 'Julien Vehent' on '2015-09-29 11:40:31.792627 -0400 EDT'.
Status 'completed'.
2 sent, 2 done, 2 succeeded
action 274&gt;</pre><p>When entering the action reader mode, a short summary of the action is displayed
to the user. We can see that the action was launched by "Julien Vehent" on 2 agents
and that it completed. The prompt is changed to <strong>action 274</strong> to indicate that
we are now in action reader mode. Entering <strong>help</strong> here provides a list of
functionalities specific to that mode:</p><pre>The following orders are available:
command &lt;id&gt; jump to command reader mode for command &lt;id&gt;
copy enter action launcher mode using current action as template
counters display the counters of the action
details display the details of the action, including status &amp; times
exit exit this mode (also works with ctrl+d)
help show this help
investigators print the list of investigators that signed the action
json show the json of the action
list &lt;show&gt; returns the list of commands with their status
&lt;show&gt;: * set to "all" to get all results (default)
* set to "found" to only display positive results
* set to "notfound" for negative results
list can be followed by a 'filter' pipe:
ex: ls | grep server1.(dom1|dom2) | grep -v example.net
r refresh the action (get latest version from upstream)
results &lt;show&gt; &lt;render&gt; display results of all commands
&lt;show&gt;: * set to "all" to get all results (default)
* set to "found" to only display positive results
* set to "notfound" for negative results
&lt;render&gt;: * set to "text" to print results in console (default)
* set to "map" to generate an open a google map
times show the various timestamps of the action</pre><p>It is possible to review results by entering <strong>results</strong>. If we only want results
from agents that have found <em>something</em>, we can use <strong>results found</strong>. If we
want those results inside a Google Map, enter <strong>results found map</strong>.</p><p>The raw json of the action is available via <strong>json</strong>.</p><p>To get a list of agents on which the action ran, use <strong>list all</strong>. You can filter
the list using <strong>list found</strong> and <strong>list notfound</strong> to only get agents that have,
or have not, found something. This command also supports a very basic <cite>grep</cite>.</p><p>To continue, let's list the agents that have found <em>something</em>:</p><pre>action 274&gt; list found
..
---- Command ID ---- ---- Agent Name &amp; ID----
4999268991155 server1.example.net [4942082344151]
4999268991154 server2.example.net [4942082360682]
2 agents have found things</pre><p>We can inspect the command that ran on server1 by entering its ID:</p><pre>action 274&gt; command 4999268991155
Entering command reader mode. Type exit or press ctrl+d to leave. help may help.
Command 4999268991155 ran on agent 'server1.example.net' based on action 'file -c /home/ulfr/.migrc-lnw -path /etc -name ^passwd -content julien '
command 155&gt;</pre><p>As you can see, the console mode has changed from <cite>action 274</cite> to
<cite>command 155</cite>. This mode has its own set of functionalities that you
can explore via <strong>help</strong>.</p><section id="creating-actions"><header><h2><a href="#id1">1   Creating actions</a></h2></header><p>The console provides a fine grained action generation interface. There
are two ways to create a new action:</p><ol class="arabic"><li><p>From the <strong>mig&gt;</strong> mode, create a new empty action using <strong>create action</strong>.</p></li><li><p>From the <strong>action&gt;</strong> reader mode, when reviewing a previous action,
copy it to a new action using <strong>copy</strong>.</p></li></ol><p>Both methods enter the action launcher mode. Method 2 only enters this
mode with an preset action, rather than an empty one:</p><pre>mig&gt; create action
Entering action launcher with empty template
Type exit or press ctrl+d to leave. help may help.
launcher&gt; help
The following orders are available:
addoperation &lt;module&gt; append a new operation of type &lt;module&gt; to the action operations
listagents list agents targetted by an action
deloperation &lt;opnum&gt; remove operation numbered &lt;opnum&gt; from operations array, count starts at zero
details display the action details
exit exit this mode
help show this help
json &lt;pack&gt; show the json of the action
launch &lt;nofollow&gt; launch the action. to return before completion, add "nofollow"
load &lt;path&gt; load an action from a file at &lt;path&gt;
setname &lt;name&gt; set the name of the action
settarget &lt;target&gt; set the target
settimes &lt;start&gt; &lt;stop&gt; set the validity and expiration dates
sign PGP sign the action
times show the various timestamps of the action</pre><p>Action parameters can be edited prior to launching it:</p><ul><li><p><strong>setname</strong> sets the name field of the action to a new string:</p><pre>launcher&gt; setname Test action that pings google.com</pre></li><li><p><strong>settarget</strong> sets the target of the action. The target is evaluated
right away, and a list of targeted agents can be obtained via <strong>listagents</strong>:</p><pre>launcher&gt; settarget environment-&gt;&gt;'os'='linux' and mode='daemon'
2 agents will be targetted. To get the list, use 'listagents'
launcher&gt; listagents
---- ID ---- + ---- Name -------
4942082360682 server1.example.net
4942082344151 server2.example.net</pre></li><li><p><strong>settimes</strong> defines the validity period of the action using
&lt;start&gt; and &lt;stop&gt; parameters. &lt;start&gt; can be set to "now", and &lt;stop&gt;
can be a duration relative to "now":</p><pre>launcher&gt; settimes now +10m
launcher&gt; times
Valid from '2015-10-06 13:09:36.189134664 +0000 UTC' until '2015-10-06 13:20:36.189134664 +0000 UTC'
Started on '0001-01-01 00:00:00 +0000 UTC'
Last updated '0001-01-01 00:00:00 +0000 UTC'
Finished on '0001-01-01 00:00:00 +0000 UTC'</pre></li><li><p><strong>addoperation &lt;module&gt;</strong> is used to add a new operation to the action.
&lt;module&gt; must be a know MIG module, such as <cite>file</cite>, <cite>netstat</cite>, <cite>memory</cite>,
<cite>scribe</cite>, <cite>ping</cite>, <cite>timedrift</cite>, etc... When adding an operation, the console
enters a new module-specific mode that takes the operation parameters. For
example, this is how to add a ping operation that sends 5 TCP requests to
google.com:</p><pre>launcher&gt; addoperation ping
Ping module checks connectivity between an endpoint and a remote host. It supports
icmp, tcp and udp ping. See doc at http://mig.mozilla.org/doc/module_ping.html
d &lt;ip/fqdn&gt; Destination Address can be ipv4, ipv6 or FQDN
example: d www.mozilla.org
d 63.245.217.105
dp &lt;port&gt; For TCP and UDP, specifies the port to test connectivity to
example: dp 53
p &lt;protocol&gt; Protocol to use for the ping. This can be "icmp", "tcp" or "udp"
example: p udp
c &lt;count&gt; Number of ping/connection attempts. Defaults to 3.
example: c 5
t &lt;timeout&gt; Connection timeout in seconds. Defaults to 5.
example: t 10
ping&gt; p tcp
ping&gt; d google.com
ping&gt; c 5
ping&gt; done
Inserting ping operation with parameters:
{
"module": "ping",
"parameters": {
"destination": google.com",
"protocol": "tcp",
"count": 5
}
}</pre></li><li><p><strong>deloperation</strong> removes an operation from the action operations list.
Use <strong>json</strong> to visualize the list, and remove an operation using its
position in the list, starting with zero:</p><pre>launcher&gt; json
{
"id": 0,
"name": "Test action that pings google.com",
"target": "environment-\u003e\u003e'os'='linux' and mode='daemon'",
"description": {},
"threat": {},
"validfrom": "2015-10-06T13:09:36.189134664Z",
"expireafter": "2015-10-06T13:20:36.189134664Z",
"operations": [
{
"module": "ping",
"parameters": {
"destination": "google.com",
"protocol": "tcp",
"count": 5
}
}
],
"pgpsignatures": null,
"starttime": "0001-01-01T00:00:00Z",
"finishtime": "0001-01-01T00:00:00Z",
"lastupdatetime": "0001-01-01T00:00:00Z",
"counters": {}
}
launcher&gt; deloperation 0
launcher&gt; json
{
"id": 0,
"name": "Test action that pings google.com",
"target": "environment-\u003e\u003e'os'='linux' and mode='daemon'",
"description": {},
"threat": {},
"validfrom": "2015-10-06T13:09:36.189134664Z",
"expireafter": "2015-10-06T13:20:36.189134664Z",
"operations": [],
"pgpsignatures": null,
"starttime": "0001-01-01T00:00:00Z",
"finishtime": "0001-01-01T00:00:00Z",
"lastupdatetime": "0001-01-01T00:00:00Z",
"counters": {}
}</pre></li></ul><p>When ready to launch the action, type <strong>launch</strong>. The console will enter
follower mode and print the progress of the action. When completed, the
console will directly enter action reader mode, where you can type <strong>results</strong>
to view the results:</p><pre>launcher&gt; launch
Action 'Test action that pings google.com' successfully launched with ID '5033038708749' on target 'environment-&gt;&gt;'os'='linux' and mode='daemon''
Following action ID 5033038708749.status=inflight...50%.status=completed
- 100.0% done in 10.004244071s
2 sent, 2 done, 2 succeeded
Entering action reader mode. Type exit or press ctrl+d to leave. help may help.
Action: 'Test action that pings google.com'.
Launched by 'Julien Vehent' on '2015-10-06 09:12:31.608546 -0400 EDT'.
Status 'completed'.
2 sent, 2 done, 2 succeeded
action 749&gt; results
server2.example.net ping of google.com failed. Target is no reachable.
server2.example.net command success
server1.example.net ping of google.com failed. Target is no reachable.
server1.example.net command success
2 agents have all results</pre></section><section id="searching"><header><h2><a href="#id2">2   Searching</a></h2></header><p>Return to the base mode using ctrl+d or <strong>exit</strong>:</p><pre>command 155&gt; exit
exit
action 274&gt; exit
exit
mig&gt;</pre><p>When in <strong>mig&gt;</strong> mode, you can use the <strong>search</strong> functionality to
explore passed actions and commands, or find investigators. Details
of how to run searches can be obtains via <strong>mig&gt; search help</strong>.</p><p>Searches can be slow if your dataset is very large, so make sure to
use time windows and limits to help speed up a search:</p><pre>mig&gt; search action where investigatorname=%vehent% and agentname=server1% and after=2015-09-01T00:00:00Z and before=2015-10-01T00:00:00Z
Searching action after 2015-09-01T00:00:00Z and before 2015-10-01T00:00:00Z, limited to 100 results
----- ID ----- + -------- Action Name ------- + ----------- Target ---------- + ---- Investigators ---- + - Sent - + - Status - + --- Last Updated ---
4999271350274 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-29T15:40:35Z
4964811669519 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-23T13:37:16Z
4964811669506 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-23T13:37:03Z
4964764024853 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 inflight 2015-09-23T13:25:26Z
4964764024834 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 inflight 2015-09-23T13:24:57Z
4949328330767 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T19:59:39Z
4949328330754 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T19:59:25Z
4948324450316 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T19:45:51Z
4948324450307 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T19:33:17Z
4947944865794 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T14:07:36Z
4947909869570 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T13:58:41Z
4947901022223 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T13:56:42Z
4947901022210 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T13:56:26Z
4947890798596 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 2 completed 2015-09-20T13:55:02Z
4885615083769 timedrift -c /home/ulfr/.mi... status='online' AND mode='d... Julien Vehent 3 completed 2015-09-09T17:02:56Z
4885615083755 pkg -c /home/ulfr/.migrc-ln... status='online' AND mode='d... Julien Vehent 3 completed 2015-09-09T17:01:33Z
4885615083739 memory -c /home/ulfr/.migrc... status='online' AND mode='d... Julien Vehent 3 completed 2015-09-09T17:01:04Z
4885615083724 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... Julien Vehent 3 completed 2015-09-09T16:58:00Z</pre></section><section id="managing-investigators"><header><h2><a href="#id3">3   Managing investigators</a></h2></header><p>The console can be used to create new investigators, active and
disable them, and well as review their activity.</p><p>To review the activity of an investigator, find its ID using the
search command and enter investigator mode:</p><pre>mig&gt; search investigator where name=%vehent%
Searching investigator after 2011-03-31T13:16:55Z and before 2020-04-12T13:16:55Z, limited to 100 results
- ID - + ---- Name ---- + --- Status ---
2 Julien Vehent active
mig&gt; investigator 2
Entering investigator mode. Type exit or press ctrl+d to leave. help may help.
Investigator 2 named 'Julien Vehent'
inv 2&gt; help
The following orders are available:
details print the details of the investigator
exit exit this mode
help show this help
lastactions &lt;limit&gt; print the last actions ran by the investigator. limit=10 by default.
pubkey show the armored public key of the investigator
r refresh the investigator (get latest version from upstream)
setstatus &lt;status&gt; changes the status of the investigator to &lt;status&gt; (can be 'active' or 'disabled')</pre><p>The command <strong>lastactions</strong> will print the latest activity of this investigator:</p><pre>inv 2&gt; lastactions
----- ID ----- + -------- Action Name ------- + ----------- Target ---------- + ---- Date ---- + -- Status --
5033038708749 Test action that pings goog... environment-&gt;&gt;'os'='linux' ... 2015-10-06T09:12:31-04:00 completed
4999271350274 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-29T11:40:31-04:00 completed
4964811669519 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-23T09:37:12-04:00 completed
4964811669506 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-23T09:36:59-04:00 completed
4964764024853 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-23T09:25:22-04:00 inflight
4964764024834 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-23T09:24:52-04:00 inflight
4949328330767 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-20T15:59:35-04:00 completed
4949328330754 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-20T15:59:21-04:00 completed
4948324450316 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-20T15:45:47-04:00 completed
4948324450307 file -c /home/ulfr/.migrc-l... status='online' AND mode='d... 2015-09-20T15:33:13-04:00 completed</pre><p>To disable him, use <strong>setstatus disabled</strong>. Disabled investigators are no longer
allowed to send investigations via the API:</p><pre>inv 2&gt; setstatus disabled
Investigator status set to disabled
inv 2&gt; details
Investigator ID 2
name Julien Vehent
status disabled
key id E60892BB9BD89A69F759A1A0A3D652173B763E8F
created 2015-09-09 09:53:28.989481 -0400 EDT
modified 2015-09-09 09:53:28.989481 -0400 EDT
inv 2&gt; setstatus active
Investigator status set to active</pre><section id="creating-investigators"><header><h3><a href="#id4">3.1   Creating investigators</a></h3></header><p>To create a new investigator, go back to <strong>mig&gt;</strong> mode and type
<strong>create investigator</strong>. The console will prompt the name of the new
investigator as well as the location of her public PGP key. You can either
provide a local path to the public key file on disk, on provide a fingerprint
in the format "0x&lt;40 char sha1 hash&gt;". When a fingerprint is provided, the
console will attempt to retrieve the key from the keyserver <cite>gpg.mozilla.org</cite>:</p><pre>mig&gt; create investigator
Entering investigator creation mode. Please provide the full name
and the public key of the new investigator.
name&gt; Bob Kelso
Name: 'Bob Kelso'
Please provide a public key. You can either provide a local path to the
armored public key file, or a full length PGP fingerprint.
example:
pubkey&gt; 0x716CFA6BA8EBB21E860AE231645090E64367737B
pubkey&gt; 0x716CFA6BA8EBB21E860AE231645090E64367737B
retrieving public key from http://gpg.mozilla.org
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: SKS 1.1.5
Comment: Hostname: keyserver.mozilla.org
mQENBEbv+5sBCADNHPvUIajRoxb/qylLrzwm9e+9sB8R/jhY4gxOzGZRDHECPvNeTUd9eogV
n24rQDTWowkE+t9sW7vlD3TUWdBEAhXEpDZBfzlTBWIzEb1m3hwPOQM10ZNX6jPS1WlGsfoE
LsUC0HmFTtOx4b5os9mIYbsjsDWd/JZjn0yUIv4eb28+fle6BkbgqIotLW4d1gTrxVlFc3be
m+4OqimQ/v2LZDV+uObEkbh4UvmTtOCCx8zAOyZohPmICUbmJBc8KWWhzLOo8b9ns/GqP41q
/9IuTQDXP2GUAKXzBKSdQiNzJP8Skfu4tPyGsGJSErprPC9t43HPPUgfeW9/sfuaw+vnABEB
AAG0JUp1bGllbiBWRUhFTlQgPGp1bGllbkBsaW51eHdhbGwuaW5mbz6JATYEEwECACAFAkbv
+5sCGy8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRBkUJDmQ2dze5U9CADK4Z6X02TP9afJ
AyWF32zM3UdMksJ/F2wuo2HBHT0iOomw4ecNzHyO1P5BTglm5LC5ZZrV+Dx6Jve75JiSDTSD
V3AhpR+M83rw8YKkeUrbTvfsy3+qhB7HYNIbCKT0lgAAL05SmDnYwYMQIV+p3T0F8BgGhkGT
vHdKLhzEhKNOMaMCwCd1SsiBepA976oBUp9h5Vt6TEFyG6hCcFP90DFjNlK17yMNjbdrgyd6
FkGEePKK3RhaLxcPShAgCnYzYYMABLYu1ow5AxxtEJTBHkJFkIzE9XM/lmyekYhWfX/Q4jpn
1aiiVlf2klZlFSFy/TXuuQH1JO3YlKo9uHjlvSQb
=+Ru1
-----END PGP PUBLIC KEY BLOCK-----
create investigator? (y/n)&gt; y
Investigator 'Bob Kelso' successfully created with ID 4
mig&gt; investigator 4
Entering investigator mode. Type exit or press ctrl+d to leave. help may help.
Investigator 4 named 'Bob Kelso'
inv 4&gt; details
Investigator ID 4
name Bob Kelso
status active
key id 716CFA6BA8EBB21E860AE231645090E64367737B
created 2015-10-06 09:23:14.473307 -0400 EDT
modified 2015-10-06 09:23:14.473307 -0400 EDT</pre><p>The new investigator now has access to the API.</p></section></section></body></html>

Просмотреть файл

@ -1,7 +1,6 @@
========
MIG Data
========
:Author: Julien Vehent <jvehent@mozilla.com>
.. sectnum::
.. contents:: Table of Contents

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {
@ -227,7 +229,7 @@ cite {
strong {
color: #C64216;
}
</style></head><body><h1>MIG Data</h1><table><tr><td class="field-label">Author</td><td>Julien Vehent &lt;<a class="reference external" href="mailto:jvehent@mozilla.com">jvehent@mozilla.com</a>&gt;</td></tr></table><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#postgresql" id="id1">1   Postgresql</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#database-creation-script" id="id2">1.1   Database creation script</a></p></li><li><p><a class="reference internal" href="#structure-tables" id="id3">1.2   Structure &amp; Tables</a></p></li></ul></li><li><p><a class="reference internal" href="#queries" id="id4">2   Queries</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#adding-investigators" id="id5">2.1   Adding Investigators</a></p></li><li><p><a class="reference internal" href="#finding-offline-agents" id="id6">2.2   Finding offline agents</a></p></li><li><p><a class="reference internal" href="#finding-double-agents" id="id7">2.3   Finding double agents</a></p></li></ul></li><li><p><a class="reference internal" href="#scheduler-spool" id="id8">3   Scheduler Spool</a></p></li></ul></div><section id="postgresql"><header><h2><a href="#id1">1   Postgresql</a></h2></header><section id="database-creation-script"><header><h3><a href="#id2">1.1   Database creation script</a></h3></header><p>Two scripts can be used to create a database for MIG.</p><ul><li><p><a class="reference external" href="https://github.com/mozilla/mig/blob/master/src/mig/database/createlocaldb.sh">createlocaldb.sh</a> will create a database on an instance of postgresql
</style></head><body><h1>MIG Data</h1><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#postgresql" id="id1">1   Postgresql</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#database-creation-script" id="id2">1.1   Database creation script</a></p></li><li><p><a class="reference internal" href="#structure-tables" id="id3">1.2   Structure &amp; Tables</a></p></li></ul></li><li><p><a class="reference internal" href="#queries" id="id4">2   Queries</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#adding-investigators" id="id5">2.1   Adding Investigators</a></p></li><li><p><a class="reference internal" href="#finding-offline-agents" id="id6">2.2   Finding offline agents</a></p></li><li><p><a class="reference internal" href="#finding-double-agents" id="id7">2.3   Finding double agents</a></p></li></ul></li><li><p><a class="reference internal" href="#scheduler-spool" id="id8">3   Scheduler Spool</a></p></li></ul></div><section id="postgresql"><header><h2><a href="#id1">1   Postgresql</a></h2></header><section id="database-creation-script"><header><h3><a href="#id2">1.1   Database creation script</a></h3></header><p>Two scripts can be used to create a database for MIG.</p><ul><li><p><a class="reference external" href="https://github.com/mozilla/mig/blob/master/src/mig/database/createlocaldb.sh">createlocaldb.sh</a> will create a database on an instance of postgresql
running locally. This is used by the standalone installation script.</p></li></ul><ul><li><p><a class="reference external" href="https://github.com/mozilla/mig/blob/master/src/mig/database/createremotedb.sh">createremotedb.sh</a> will connect to an existing MIG database on a remote
postgresql server. This is a standard production setup. It assumes that you
have created a database beforehand. You can pass the DB credentials by

Просмотреть файл

@ -1,6 +1,6 @@
body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {

Просмотреть файл

@ -1,7 +1,6 @@
===========
MIG Modules
===========
:Author: Julien Vehent <jvehent@mozilla.com>
.. sectnum::
.. contents:: Table of Contents

Просмотреть файл

@ -1,6 +1,6 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 900px;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
@ -29,7 +29,7 @@ section {
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
margin: 0;
/*margin: 0;*/
}
/* Header, <header>
@ -78,6 +78,8 @@ header h2 {
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {
@ -227,7 +229,7 @@ cite {
strong {
color: #C64216;
}
</style></head><body><h1>MIG Modules</h1><table><tr><td class="field-label">Author</td><td>Julien Vehent &lt;<a class="reference external" href="mailto:jvehent@mozilla.com">jvehent@mozilla.com</a>&gt;</td></tr></table><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#module-logic" id="id3">1   Module logic</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#registration" id="id4">1.1   Registration</a></p></li><li><p><a class="reference internal" href="#execution" id="id5">1.2   Execution</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#runner-interface" id="id6">1.2.1   Runner Interface</a></p></li><li><p><a class="reference internal" href="#parameters" id="id7">1.2.2   Parameters</a></p></li><li><p><a class="reference internal" href="#run" id="id8">1.2.3   Run</a></p></li><li><p><a class="reference internal" href="#validate-parameters" id="id9">1.2.4   Validate Parameters</a></p></li></ul></li><li><p><a class="reference internal" href="#results" id="id10">1.3   Results</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#success" id="id11">1.3.1   Success</a></p></li><li><p><a class="reference internal" href="#foundanything" id="id12">1.3.2   FoundAnything</a></p></li><li><p><a class="reference internal" href="#elements" id="id13">1.3.3   Elements</a></p></li><li><p><a class="reference internal" href="#statistics" id="id14">1.3.4   Statistics</a></p></li><li><p><a class="reference internal" href="#errors" id="id15">1.3.5   Errors</a></p></li></ul></li><li><p><a class="reference internal" href="#additional-interfaces" id="id16">1.4   Additional interfaces</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#hasresultsprinter" id="id17">1.4.1   HasResultsPrinter</a></p></li><li><p><a class="reference internal" href="#hasparamscreator" id="id18">1.4.2   HasParamsCreator</a></p></li><li><p><a class="reference internal" href="#hasparamsparser" id="id19">1.4.3   HasParamsParser</a></p></li></ul></li></ul></li><li><p><a class="reference internal" href="#the-example-module" id="id20">2   The Example module</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#headers-and-structs" id="id21">2.1   Headers and structs</a></p></li><li><p><a class="reference internal" href="#id1" id="id22">2.2   Validate Parameters</a></p></li><li><p><a class="reference internal" href="#id2" id="id23">2.3   Run</a></p></li><li><p><a class="reference internal" href="#doing-work-and-building-results" id="id24">2.4   Doing work and building results</a></p></li><li><p><a class="reference internal" href="#printing-results" id="id25">2.5   Printing results</a></p></li><li><p><a class="reference internal" href="#creating-parameters" id="id26">2.6   Creating parameters</a></p></li></ul></li></ul></div><p>In this document, we explain how modules are written and integrated into MIG.</p><p>The reception of a command by an agent triggers the execution of modules. A
</style></head><body><h1>MIG Modules</h1><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#module-logic" id="id3">1   Module logic</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#registration" id="id4">1.1   Registration</a></p></li><li><p><a class="reference internal" href="#execution" id="id5">1.2   Execution</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#runner-interface" id="id6">1.2.1   Runner Interface</a></p></li><li><p><a class="reference internal" href="#parameters" id="id7">1.2.2   Parameters</a></p></li><li><p><a class="reference internal" href="#run" id="id8">1.2.3   Run</a></p></li><li><p><a class="reference internal" href="#validate-parameters" id="id9">1.2.4   Validate Parameters</a></p></li></ul></li><li><p><a class="reference internal" href="#results" id="id10">1.3   Results</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#success" id="id11">1.3.1   Success</a></p></li><li><p><a class="reference internal" href="#foundanything" id="id12">1.3.2   FoundAnything</a></p></li><li><p><a class="reference internal" href="#elements" id="id13">1.3.3   Elements</a></p></li><li><p><a class="reference internal" href="#statistics" id="id14">1.3.4   Statistics</a></p></li><li><p><a class="reference internal" href="#errors" id="id15">1.3.5   Errors</a></p></li></ul></li><li><p><a class="reference internal" href="#additional-interfaces" id="id16">1.4   Additional interfaces</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#hasresultsprinter" id="id17">1.4.1   HasResultsPrinter</a></p></li><li><p><a class="reference internal" href="#hasparamscreator" id="id18">1.4.2   HasParamsCreator</a></p></li><li><p><a class="reference internal" href="#hasparamsparser" id="id19">1.4.3   HasParamsParser</a></p></li></ul></li></ul></li><li><p><a class="reference internal" href="#the-example-module" id="id20">2   The Example module</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#headers-and-structs" id="id21">2.1   Headers and structs</a></p></li><li><p><a class="reference internal" href="#id1" id="id22">2.2   Validate Parameters</a></p></li><li><p><a class="reference internal" href="#id2" id="id23">2.3   Run</a></p></li><li><p><a class="reference internal" href="#doing-work-and-building-results" id="id24">2.4   Doing work and building results</a></p></li><li><p><a class="reference internal" href="#printing-results" id="id25">2.5   Printing results</a></p></li><li><p><a class="reference internal" href="#creating-parameters" id="id26">2.6   Creating parameters</a></p></li></ul></li></ul></div><p>In this document, we explain how modules are written and integrated into MIG.</p><p>The reception of a command by an agent triggers the execution of modules. A
module is a Go package that is imported into the agent at compilation, and that
performs a very specific set of tasks. For example, the <code>file</code> module
provides a way to scan a file system for files that contain regexes, match a

Просмотреть файл

@ -1,7 +1,6 @@
==========
MIG RUNNER
==========
:Author: Aaron Meihm <ameihm@mozilla.com>
.. sectnum::
.. contents:: Table of contents

293
doc/runner.rst.html Normal file
Просмотреть файл

@ -0,0 +1,293 @@
<!DOCTYPE html><html><head><meta charset="utf-8"><title></title><style type="text/css">body {
width: 95%;
max-width: 70%;
margin: 20px;
padding: 0;
background: #151515 url("../images/bkg.png") 0 0;
color: #eaeaea;
font: 16px;
line-height: 1.5em;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
}
#table-of-contents ul {
line-height: 1;
}
/* General & 'Reset' Stuff */
.container {
width: 95%;
max-width: 1000px;
margin: 0 auto;
}
section {
display: block;
margin: 0 0 20px 0;
}
h1, h2, h3, h4, h5, h6 {
/*margin: 0 0 20px;*/
/*margin: 0;*/
}
/* Header, <header>
* header - container
* h1 - project name
* h2 - project description
* */
header {
background: rgba(0, 0, 0, 0.1);
width: 100%;
/*border-bottom: 1px dashed #b5e853;*/
/*padding: 20px 0;
* margin: 0 0 40px 0;*/
padding: 5px 0;
margin: 0 0 10px 0;
}
header h1 {
font-size: 30px;
line-height: 1.5;
margin: 0 0 0 -40px;
font-weight: bold;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
/*color: #b5e853;*/
color: #089d00;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1),
0 0 5px rgba(181, 232, 83, 0.1),
0 0 10px rgba(181, 232, 83, 0.1);
letter-spacing: -1px;
-webkit-font-smoothing: antialiased;
}
header h1:before {
content: "./ ";
font-size: 24px;
}
header h2 {
font-size: 18px;
font-weight: 300;
}
/* Main Content
* */
body {
width: 100%;
margin-left: auto;
margin-right: auto;
-webkit-font-smoothing: antialiased;
}
section img {
max-width: 100%
}
h2 a {
font-weight: bold;
color: #8AB638;
line-height: 1.4em;
font-size: 1.4em;
}
h3 a, h4 a, h5 a, h6 a {
font-weight: bold;
color: #934500;
line-height: 1.4em;
}
h1 {
font-size: 30px;
}
h2 {
font-size: 28px;
border-bottom: 1px dashed #b5e853;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 14px;
}
h5 {
font-size: 12px;
text-transform: uppercase;
margin: 0 0 5px 0;
}
h6 {
font-size: 12px;
text-transform: uppercase;
color: #999;
margin: 0 0 5px 0;
}
dt {
font-style: italic;
font-weight: bold;
}
/*
ul li {
list-style: none;
}
*/
/*
ul li:before {
content: ">>";
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
font-size: 13px;
color: #b5e853;
margin-left: -37px;
margin-right: 21px;
line-height: 16px;
}
*/
blockquote {
color: #aaa;
padding-left: 10px;
border-left: 1px dotted #666;
}
pre {
background: rgba(0, 0, 0, 0.9);
border: 1px solid rgba(255, 255, 255, 0.15);
padding: 10px;
font-size: 14px;
//color: #b5e853;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
text-wrap: normal;
overflow: auto;
overflow-y: hidden;
}
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
code .ln { color: grey; } /* line numbers */
/*code, code { background-color: #eeeeee }*/
code .comment, code .comment, code .c1 { color: #999; }
code .keyword, code .keyword, code .kd, code .kn, code .k, code .o { color: #FC8F3F; font-weight: bold;}
code .nb { color: #c45918;}
code .s {color: #0a77c4;}
code .punctuation, code .p { color: white;}
code .literal.string, code .literal.string { color: #40BF32; }
code .name, code .name.builtin, code .nx { color: white; }
code .deleted, code .deleted { background-color: #DEB0A1}
code .inserted, code .inserted { background-color: #A3D289}
table {
width: 100%;
margin: 0 0 20px 0;
}
th {
text-align: left;
border-bottom: 1px dashed #b5e853;
padding: 5px 10px;
}
td {
padding: 5px 10px;
}
hr {
height: 0;
border: 0;
border-bottom: 1px dashed #b5e853;
color: #b5e853;
}
/* Links
* a, a:hover, a:visited
* */
a {
color: #63c0f5;
/*text-shadow: 0 0 5px rgba(104, 182, 255, 0.5);*/
text-decoration: none;
}
cite {
color: #00FF4A;
}
strong {
color: #C64216;
}
</style></head><body><h1>MIG RUNNER</h1><div class="contents" id="table-of-contents"><h2>Table of contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#runner-configuration-file" id="id1">1   Runner configuration file</a></p></li><li><p><a class="reference internal" href="#job-configuration" id="id2">2   Job configuration</a></p></li><li><p><a class="reference internal" href="#output-plugins" id="id3">3   Output plugins</a></p></li></ul></div><p>MIG runner is a service that can be deployed to automatically schedule actions
to run within the MIG environment and retrieve/process the results.</p><p>The runner interacts directly with the MIG API in the same manner as a client
would. When an action is scheduled to run, the runner will deploy the action
and schedule a time to gather results (shortly after the action has expired).
Once the action has expired, the runner will retrieve results from the API
and store these results in the runner directory. The runner can also send the
results from MIG to an external program for automatic parsing or formatting,
for example to create events for MozDef and send them.</p><section id="runner-configuration-file"><header><h2><a href="#id1">1   Runner configuration file</a></h2></header><p>An example configuration file for use by mig-runner is shown below.</p><pre><code class="code">; Sample MIG runner configuration file
[runner]
directory = "/home/mig-runner/runner" ; The path to the root runner directory
checkdirectory = 30 ; How often to check runners/ for job changes
[logging]
mode = "stdout" ; stdout | file | syslog
level = "debug"
[client]
clientconfpath = "default" ; Path to client conf, default for $HOME/.migrc
delayresults = "30s"; Duration after action expiry to fetch results</code></pre><p>If the GPG key used by mig-runner is protected by a passphrase, the
<cite>passphrase</cite> option can be included under the <cite>client</cite> section. If this is
specified this passphrase will be used to access the private key.</p><p>The <cite>delayresults</cite> value is optional. If not set, the runner will attempt
to fetch action results when the action has expired. If this is set to a
duration string value, the runner will wait the specified duration after
action expiry before fetching results (for example to ensure all results
are written to the database by the scheduler).</p><p>The <cite>checkdirectory</cite> option specifies the number of seconds that elapse
between scans of the runner directory for job changes. The runner will
automatically add or remove jobs as new jobs are added in the spool
directory. When the runner identifies changes to a job, this will be
indicated in the log file as the old job configuration will be removed
and the new configuration installed.</p><p>The <cite>directory</cite> option specifies the root directory that stores all the
mig-runner related control information. A typical runner directory may look
something like this.</p><pre><code class="code">runner/
|
+ runners/
| |
| + job1/
| + job2/
|
+ plugins/</code></pre></section><section id="job-configuration"><header><h2><a href="#id2">2   Job configuration</a></h2></header><p>Under each job directory, a file entity.cfg defines the parameters used to
run this job.</p><pre><code class="code">[configuration]
schedule = "&lt;cronexpr&gt;"
plugin = "&lt;plugin name&gt;"</code></pre><p>The schedule option should be set to a cron style expression to note when
the job should be run.</p><p>The plugin is optional. If set, the value will be interpreted as an
executable in the plugins directory. The results of the job will be piped
into stdin of this executable in JSON format (mig.RunnerResult). The
plugin can then parse and forward the data as needed.</p><p>Optionally the <cite>expiry</cite> setting can be set to a go Duration string to use
for action expiry (for example 10m for 10 minutes). If this is not set
in the job configuration, a default of 5 minutes will be used.</p><p>Optionally the <cite>sendonly</cite> setting can be set to true, which will result in
the runner only dispatching the action, but not attempting to retrieve
any results. As an example, this can be used to deploy actions that would
be processed by MIG workers, rather than retrieved and processed on the
runner side.</p><p>The results are also written into a <cite>results/</cite> subdirectory under the
runner directory, using the action ID as a file name. This happens
regardless of any plugin configuration for the job.</p><p>In the job directory, the MIG action should should be launched should be
called <cite>action.json</cite>. The time validity and expiration fields will be
filled in by the runner process before dispatching the action to the
API.</p></section><section id="output-plugins"><header><h2><a href="#id3">3   Output plugins</a></h2></header><p>The runner writes JSON output to stdin of any configured output plugin. This
is intended to provide flexibility, allowing plugins to be developed in
any language. If a plugin is being developed in go, the mig.RunnerResult
type can be used to parse incoming data. In other languages the JSON can
be parsed as desired.</p></section></body></html>