mig/doc/configuration.rst.html

1105 строки
106 KiB
HTML
Исходник Ответственный История

Этот файл содержит невидимые символы Юникода!

Этот файл содержит невидимые символы Юникода, которые могут быть отображены не так, как показано ниже. Если это намеренно, можете спокойно проигнорировать это предупреждение. Используйте кнопку Экранировать, чтобы показать скрытые символы.

<!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>Mozilla InvestiGator Deployment and Configuration Documentation</h1><div class="contents" id="table-of-contents"><h2>Table of Contents</h2><ul class="auto-toc"><li><p><a class="reference internal" href="#prepare-a-build-environment" id="id4">1   Prepare a build environment</a></p></li><li><p><a class="reference internal" href="#deploy-the-postgresql-database" id="id5">2   Deploy the Postgresql database</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#deploying-on-a-remote-database-like-aws-rds" id="id6">2.1   Deploying on a remote database, like AWS RDS</a></p></li></ul></li><li><p><a class="reference internal" href="#create-a-pki" id="id7">3   Create a PKI</a></p></li><li><p><a class="reference internal" href="#deploy-the-rabbitmq-relay" id="id8">4   Deploy the Rabbitmq relay</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#installation" id="id9">4.1   Installation</a></p></li><li><p><a class="reference internal" href="#scripted-rabbitmq-configuration" id="id10">4.2   Scripted RabbitMQ Configuration</a></p></li></ul></li><li><p><a class="reference internal" href="#scheduler-configuration" id="id11">5   Scheduler Configuration</a></p></li><li><p><a class="reference internal" href="#api-configuration" id="id12">6   API configuration</a></p></li><li><p><a class="reference internal" href="#build-the-clients-and-create-an-investigator" id="id13">7   Build the clients and create an investigator</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#enable-api-authentication" id="id14">7.1   Enable API Authentication</a></p></li></ul></li><li><p><a class="reference internal" href="#agent-configuration" id="id15">8   Agent Configuration</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#amqps-configuration" id="id16">8.1   AMQPS configuration</a></p></li><li><p><a class="reference internal" href="#id1" id="id17">8.2   API Configuration</a></p></li><li><p><a class="reference internal" href="#proxy-support" id="id18">8.3   Proxy support</a></p></li><li><p><a class="reference internal" href="#stat-socket" id="id19">8.4   Stat socket</a></p></li><li><p><a class="reference internal" href="#logging" id="id20">8.5   Logging</a></p></li><li><p><a class="reference internal" href="#access-control-lists" id="id21">8.6   Access Control Lists</a></p></li><li><p><a class="reference internal" href="#investigators-s-public-keys" id="id22">8.7   Investigators's public keys</a></p></li><li><p><a class="reference internal" href="#customize-the-configuration" id="id23">8.8   Customize the configuration</a></p></li><li><p><a class="reference internal" href="#agent-build-instructions" id="id24">8.9   Agent build instructions</a></p></li><li><p><a class="reference internal" href="#run-your-first-investigation" id="id25">8.10   Run your first investigation</a></p></li></ul></li><li><p><a class="reference internal" href="#appendix-a-manual-rabbitmq-configuration" id="id26">9   Appendix A: Manual RabbitMQ Configuration</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#rabbitmq-tls-configuration" id="id27">9.1   RabbitMQ TLS configuration</a></p></li><li><p><a class="reference internal" href="#queues-mirroring" id="id28">9.2   Queues mirroring</a></p></li><li><p><a class="reference internal" href="#cluster-management" id="id29">9.3   Cluster management</a></p></li><li><p><a class="reference internal" href="#supporting-more-than-1024-connections" id="id30">9.4   Supporting more than 1024 connections</a></p></li><li><p><a class="reference internal" href="#serving-amqps-on-port-443" id="id31">9.5   Serving AMQPS on port 443</a></p></li></ul></li><li><p><a class="reference internal" href="#appendix-b-scheduler-configuration-reference" id="id32">10   Appendix B: Scheduler configuration reference</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#spool-directories" id="id33">10.1   Spool directories</a></p></li><li><p><a class="reference internal" href="#whitelist" id="id34">10.2   Whitelist</a></p></li><li><p><a class="reference internal" href="#database-tuning" id="id35">10.3   Database tuning</a></p></li><li><p><a class="reference internal" href="#id2" id="id36">10.4   Logging</a></p></li><li><p><a class="reference internal" href="#id3" id="id37">10.5   AMQPS configuration</a></p></li><li><p><a class="reference internal" href="#collector" id="id38">10.6   Collector</a></p></li><li><p><a class="reference internal" href="#periodic" id="id39">10.7   Periodic</a></p></li><li><p><a class="reference internal" href="#pgp" id="id40">10.8   PGP</a></p></li></ul></li><li><p><a class="reference internal" href="#appendix-c-advanced-agent-configuration" id="id41">11   Appendix C: Advanced agent configuration</a></p><ul class="auto-toc"><li><p><a class="reference internal" href="#agent-external-configuration-file" id="id42">11.1   Agent external configuration file</a></p></li><li><p><a class="reference internal" href="#building-agents-packages" id="id43">11.2   Building agents packages</a></p></li></ul></li></ul></div><p>This document describes the steps to build and configure a MIG platform.
MIG has 6 major components. The Postgresql database and RabbitMQ relay are
external dependencies, and while this document shows one way of deploying them,
you are free to use your own method. All other components (scheduler, api,
agents and clients) require specific compilation and configuration steps that
are explained in this document.</p><p>Due to the fast changing pace of Go, MIG and its third party packages, we do
not currently provide binary packages. You will have to compile the components
yourself, which is explained below.</p><p>A complete environment should be configured in the following order:</p><ol class="arabic"><li><p>retrieve the source and prepare your build environment</p></li><li><p>deploy the postgresql database</p></li><li><p>create a PKI</p></li><li><p>deploy the rabbitmq relay</p></li><li><p>build, configure and deploy the scheduler</p></li><li><p>build, configure and deploy the api</p></li><li><p>build the clients and create an investigator</p></li><li><p>configure and deploy agents</p></li></ol><section id="prepare-a-build-environment"><header><h2><a href="#id4">1   Prepare a build environment</a></h2></header><p>Install <strong>Go 1.5</strong> from your package manager , via <a class="reference external" href="https://github.com/moovweb/gvm">gvm</a> or <a class="reference external" href="http://golang.org/doc/install/source">from source</a>.</p><p>You <strong>must</strong> use Go 1.5 because MIG uses vendoring that isn't available in prior
versions.</p><pre><code class="code bash"><span class="name variable">$ </span>go version
go version go1.5 linux/amd64</code></pre><p>As with any Go setup, make sure your GOPATH is exported, for example by setting
it to <cite>$HOME/go</cite></p><pre><code class="code bash"><span class="name variable">$ </span><span class="name builtin">export </span><span class="name variable">GOPATH</span><span class="operator">=</span><span class="literal string double">"</span><span class="name variable">$HOME</span><span class="literal string double">/go"</span>
<span class="name variable">$ </span>mkdir <span class="name variable">$GOPATH</span></code></pre><p>Then retrieve MIG's source code using go get:</p><pre><code class="code bash"><span class="name variable">$ </span>go get mig.ninja/mig</code></pre><p>Go get will place MIG under <cite>$GOPATH/src/mig.ninja/mig</cite>. Change directory to
this path and build the components. Note that, if you're on a Debian or Ubuntu
box, you can run <cite>make deb-server</cite> directly which will build the scheduler, api
and workers into a single DEB package. Otherwise, use the following make
commands:</p><pre><code class="code bash"><span class="name variable">$ </span>make mig-scheduler
<span class="name variable">$ </span>make mig-api
<span class="name variable">$ </span>make worker-agent-intel
<span class="name variable">$ </span>make worker-compliance-item</code></pre><p>Or just run <cite>make</cite> that will build everything and runs tests as well.</p><p>Note: running <cite>make</cite> will build everything including the mig-console which
requires <strong>readline</strong> to be installed (<cite>readline-devel</cite> on rhel/fedora or
<cite>libreadline-dev</cite> on debian/ubuntu).</p><pre><code class="code bash"><span class="name variable">$ </span>make</code></pre></section><section id="deploy-the-postgresql-database"><header><h2><a href="#id5">2   Deploy the Postgresql database</a></h2></header><p>Install postgres 9.3+ on a server and copy the scripts
<cite>database/createlocaldb.sh</cite> and <cite>database/schema.sql</cite>. Make sure you have sudo
access to the server and run the script (or run the commands from createlocaldb.sh
manually).</p><pre><code class="code bash"><span class="name variable">$ </span>./createlocaldb.sh
Created user migadmin with password <span class="literal string single">'l1bZowe8fy1'</span>
Created user migapi with password <span class="literal string single">'p4oid18'</span>
Created user migscheduler with password <span class="literal string single">'48Cm12Taodf928wqojdlsa1981'</span>
MIG Database created successfully.</code></pre><p>This creates a local database called <cite>mig</cite> with the relevant admin, api and
scheduler users. Make sure you save the passwords generated by the script in a
safe location, you'll need them later.</p><p>To verify the DB, use the psql command line:</p><pre><code class="code bash"><span class="name variable">$ </span>sudo su - postgres
postgres@jaffatower:~<span class="name variable">$ </span>psql
psql <span class="operator">(</span>9.4.4<span class="operator">)</span>
Type <span class="literal string double">"help"</span> <span class="keyword">for</span> help.
<span class="name variable">postgres</span><span class="operator">=</span><span class="comment"># \c mig
</span>You are now connected to database <span class="literal string double">"mig"</span> as user <span class="literal string double">"postgres"</span>.
<span class="name variable">mig</span><span class="operator">=</span><span class="comment"># \d
</span> List of relations
Schema <span class="punctuation">|</span> Name <span class="punctuation">|</span> Type <span class="punctuation">|</span> Owner
--------+----------------------+----------+----------
public <span class="punctuation">|</span> actions <span class="punctuation">|</span> table <span class="punctuation">|</span> migadmin
public <span class="punctuation">|</span> agents <span class="punctuation">|</span> table <span class="punctuation">|</span> migadmin
public <span class="punctuation">|</span> agents_stats <span class="punctuation">|</span> table <span class="punctuation">|</span> postgres
public <span class="punctuation">|</span> agtmodreq <span class="punctuation">|</span> table <span class="punctuation">|</span> migadmin
public <span class="punctuation">|</span> commands <span class="punctuation">|</span> table <span class="punctuation">|</span> migadmin
public <span class="punctuation">|</span> invagtmodperm <span class="punctuation">|</span> table <span class="punctuation">|</span> migadmin
public <span class="punctuation">|</span> investigators <span class="punctuation">|</span> table <span class="punctuation">|</span> migadmin
public <span class="punctuation">|</span> investigators_id_seq <span class="punctuation">|</span> sequence <span class="punctuation">|</span> postgres
public <span class="punctuation">|</span> modules <span class="punctuation">|</span> table <span class="punctuation">|</span> migadmin
public <span class="punctuation">|</span> signatures <span class="punctuation">|</span> table <span class="punctuation">|</span> migadmin
<span class="operator">(</span><span class="literal number">10</span> rows<span class="operator">)</span></code></pre><section id="deploying-on-a-remote-database-like-aws-rds"><header><h3><a href="#id6">2.1   Deploying on a remote database, like AWS RDS</a></h3></header><p>If you are using a remote database, create a database and an admin user, then
modify the variables at the top of <a class="reference external" href="https://github.com/mozilla/mig/blob/master/src/mig/database/createremotedb.sh">src/mig/database/createremotedb.sh</a> and
run it. The script will create the DB schema and output the credentials for
users <cite>migscheduler</cite> and <cite>migapi</cite>. These credentials need to be references in
the MIG Scheduler and API configuration files.</p><p>Edit the variables in the script <cite>createremotedb.sh</cite>:</p><pre><code class="code bash"><span class="name variable">$ </span>vim createremotedb.sh
<span class="name variable">PGDATABASE</span><span class="operator">=</span><span class="literal string single">'mig'</span>
<span class="name variable">PGUSER</span><span class="operator">=</span><span class="literal string single">'migadmin'</span>
<span class="name variable">PGPASS</span><span class="operator">=</span><span class="literal string single">'MYDATABASEPASSWORD'</span>
<span class="name variable">PGHOST</span><span class="operator">=</span><span class="literal string single">'192.168.0.1'</span>
<span class="name variable">PGPORT</span><span class="operator">=</span>5432</code></pre><p>Then run it against your database server. Make sure that the Postgresql client
command line <cite>psql</cite> is installed locally.</p><pre><code class="code bash"><span class="name variable">$ </span>which psql
/usr/bin/psql
<span class="name variable">$ </span>bash createremotedb.sh
<span class="operator">[</span>... bunch of sql queries ...<span class="operator">]</span>
created users:
migscheduler 4NvQFdwdQ8UOU4ekEOgWDWi3gzG5cg2X
migapi xcJyJhLg1cldIp7eXcxv0U-UqV80tMb-</code></pre></section></section><section id="create-a-pki"><header><h2><a href="#id7">3   Create a PKI</a></h2></header><p>Skip this step if you want to reuse an existing PKI. MIG will need a server
certificate for RabbitMQ, and client certificates for agents, schedulers and
workers. The PKI is only used to protect connection to the public AMQP endpoint.</p><p>Use the script is <cite>tools/create_mig_ca.sh</cite> to generate a new CA and signed
certificates for each component.</p><p>Create a new directory that will hold the CA, copy the script in it, and run it.
The script will prompt for one piece of information: the public DNS of the
rabbitmq relay. It's important that you set this to the correct value to allow
AMQP clients to validate the rabbitmq certificate correctly.</p><pre><code class="code bash"><span class="name variable">$ </span>mkdir migca
<span class="name variable">$ </span><span class="name builtin">cd </span>migca
<span class="name variable">$ </span>cp <span class="name variable">$GOPATH</span>/src/mig.ninja/mig/tools/create_mig_ca.sh .
<span class="name variable">$ </span>bash create_mig_ca.sh
<span class="operator">[</span>...<span class="operator">]</span>
enter the public dns name of the rabbitmq server agents will connect to&gt; mymigrelay.example.net
<span class="operator">[</span>...<span class="operator">]</span>
<span class="name variable">$ </span>ls -l
total 76
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">5163</span> Sep <span class="literal number">9</span> 00:06 agent.crt
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">1033</span> Sep <span class="literal number">9</span> 00:06 agent.csr
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">1704</span> Sep <span class="literal number">9</span> 00:06 agent.key
drwxr-xr-x <span class="literal number">3</span> julien julien <span class="literal number">4096</span> Sep <span class="literal number">9</span> 00:06 ca
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">3608</span> Sep <span class="literal number">9</span> 00:06 create_mig_ca.sh
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">2292</span> Sep <span class="literal number">9</span> 00:06 openssl.cnf
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">5161</span> Sep <span class="literal number">9</span> 00:06 rabbitmq.crt
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">1029</span> Sep <span class="literal number">9</span> 00:06 rabbitmq.csr
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">1704</span> Sep <span class="literal number">9</span> 00:06 rabbitmq.key
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">5183</span> Sep <span class="literal number">9</span> 00:06 scheduler.crt
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">1045</span> Sep <span class="literal number">9</span> 00:06 scheduler.csr
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">1704</span> Sep <span class="literal number">9</span> 00:06 scheduler.key
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">5169</span> Sep <span class="literal number">9</span> 00:06 worker.crt
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">1033</span> Sep <span class="literal number">9</span> 00:06 worker.csr
-rw-r--r-- <span class="literal number">1</span> julien julien <span class="literal number">1704</span> Sep <span class="literal number">9</span> 00:06 worker.key</code></pre><p>These certificates can now be used in each component.</p></section><section id="deploy-the-rabbitmq-relay"><header><h2><a href="#id8">4   Deploy the Rabbitmq relay</a></h2></header><section id="installation"><header><h3><a href="#id9">4.1   Installation</a></h3></header><p>Install the RabbitMQ server from your distribution's packaging system. If your
distribution does not provide a RabbitMQ package, install <cite>erlang</cite> from yum or
apt, and then install RabbitMQ using the packages from rabbitmq.com</p></section><section id="scripted-rabbitmq-configuration"><header><h3><a href="#id10">4.2   Scripted RabbitMQ Configuration</a></h3></header><p>The script in <cite>tools/create_rabbitmq_config.sh</cite> can be run against a local
instance of rabbitmq to configure the necessary users and permissions.</p><pre><code class="code bash"><span class="name variable">$ </span>bash createrabbitmqconfig.sh
<span class="operator">[</span> ... <span class="operator">]</span>
<span class="operator">[</span> ok <span class="operator">]</span> Restarting message broker: rabbitmq-server.
rabbitmq configured with the following users:
admin 5IRociqhefiehekjqqhfeq
scheduler MM8972olkjwqashrieygrh
agent p1938oanvdjknxcbveufif
worker 80912lsdkjj718tdfxmlqx
copy ca.crt and rabbitmq.<span class="operator">{</span>crt,key<span class="operator">}</span> into /etc/rabbitmq/
<span class="keyword">then</span> run <span class="name variable">$ </span>service rabbitmq-server restart</code></pre><p>Save the credentials in a safe location, we will need them later.</p><p>Copy the ca.crt, rabbitmq.key and rabbitmq.crt we generate in the PKI into
/etc/rabbitmq and restart the service. You should see Beam listen on port
5671.</p><pre><code class="code bash"><span class="name variable">$ </span>netstat -taupen<span class="punctuation">|</span>grep 5671
tcp6 <span class="literal number">0</span> <span class="literal number">0</span> :::5671 :::* LISTEN <span class="literal number">110</span> <span class="literal number">658831</span> 11467/beam.smp</code></pre><p>If you care about the detail of Rabbitmq's configuration, read the manual
configuration section in the appendix at the end of this document.</p></section></section><section id="scheduler-configuration"><header><h2><a href="#id11">5   Scheduler Configuration</a></h2></header><p>If you deploy the scheduler using the package build by the <cite>deb-server</cite> target,
a template configuration will be placed in /etc/mig/scheduler.cfg. Otherwise,
you can find one in <cite>conf/scheduler.cfg.inc</cite>.</p><p>If you use <cite>deb-server</cite>, simply <cite>dpkg -i</cite> the package and the scheduler will be
installed into /opt/mig/bin/mig-scheduler, its configuration kept in /etc/mig.</p><p>If you build your own binary, get one by running <cite>make mig-scheduler</cite>.</p><p>Start by copying the ca.crt, scheduler.key and scheduler.crt we generated in the
PKI into the /etc/mig/ folder.</p><p>Then edit the configuration file to replace the DB and RabbitMQ parameters with
the ones that we obtained in previous steps. The default configurations provided
for both Postgres and RabbitMQ are purposedly wrong and need to be replaced,
otherwise the scheduler will fail to connect. Below is an example configuration
that would work with the setup we have prepared.</p><pre><code class="code">[agent]
; timeout controls the inactivity period after which
; agents are marked offline
timeout = "60m"
; heartbeatfreq maps to the agent configuration and helps
; the scheduler detect duplicate agents, and some other things
heartbeatfreq = "5m"
; whitelist contains a list of agent queues that are allowed
; to send heartbeats and receive commands
whitelist = "/var/cache/mig/agents_whitelist.txt"
; detect endpoints that are running multiple agents
detectmultiagents = true
; issue kill orders to duplicate agents running on the same endpoint
killdupagents = true
; the collector continuously pulls
; pending messages from the spool
[collector]
; frequency at which the collector runs,
; default is to run every second
freq = "1s"
; the periodic runs less often that
; the collector and does cleanup and DB updates
[periodic]
; frequency at which the periodic jobs run
freq = "87s"
; delete finished actions, commands and invalids after
; this period has passed
deleteafter = "360h"
; run a rabbitmq unused queues cleanup job at this frequency
; this is DB &amp; amqp intensive so don't run it too often
queuescleanupfreq = "24h"
[directories]
spool = "/var/cache/mig/"
tmp = "/var/tmp/"
[postgres]
host = "192.168.1.240"
port = 5432
dbname = "mig"
user = "migscheduler"
password = "4NvQFdwdQ8UOU4ekEOgWDWi3gzG5cg2X"
sslmode = "disable"
maxconn = 10
[mq]
host = "rabbitmq.mig.example.net"
port = 5671
user = "scheduler"
pass = "MM8972olkjwqashrieygrh"
vhost = "mig"
; TLS options
usetls = true
cacert = "/etc/mig/ca.crt"
tlscert = "/etc/mig/scheduler.crt"
tlskey = "/etc/mig/scheduler.key"
; AMQP options
; timeout defaults to 10 minutes
; keep this higher than the agent heartbeat value
timeout = "10m"
[logging]
mode = "stdout" ; stdout | file | syslog
level = "debug"
; for file logging
; file = "mig_scheduler.log"
; for syslog, logs go into local3
; host = "localhost"
; port = 514
; protocol = "udp"</code></pre><p>The sample above needs to be tweaked further to match your environment. This
document explains each section in Appendix B. For now, let's test our setup
with this basic conf by running mig-scheduler in foreground, as root.</p><pre><code class="code bash"><span class="comment"># /opt/mig/bin/mig-scheduler
</span>Initializing Scheduler context...OK
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initChannels<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initDirectories<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> Database connection opened
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initDB<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> AMQP connection opened
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initRelay<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving makeSecring<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> no key found in database. generating a private key <span class="keyword">for</span> user migscheduler
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> created migscheduler identity with ID %!d<span class="operator">(</span><span class="name variable">float64</span><span class="operator">=</span>1<span class="operator">)</span> and key ID A8E1ED58512FCD9876DBEA4FEA513B95032D9932
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving makeSchedulerInvestigator<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> loaded scheduler private key from database
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving makeSecring<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> Loaded scheduler investigator with key id A8E1ED58512FCD9876DBEA4FEA513B95032D9932
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initSecring<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> mig.ProcessLog<span class="operator">()</span> routine started
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> processNewAction<span class="operator">()</span> routine started
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> sendCommands<span class="operator">()</span> routine started
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> terminateCommand<span class="operator">()</span> routine started
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> updateAction<span class="operator">()</span> routine started
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> agents heartbeats listener initialized
2015/09/09 04:25:47 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving startHeartbeatsListener<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> agents heartbeats listener routine started
2015/09/09 04:25:47 <span class="literal number">4883372310530</span> - - <span class="operator">[</span>info<span class="operator">]</span> agents results listener initialized
2015/09/09 04:25:47 <span class="literal number">4883372310530</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving startResultsListener<span class="operator">()</span>
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> agents results listener routine started
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> collector routine started
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> periodic routine started
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> queue cleanup routine started
2015/09/09 04:25:47 - - - <span class="operator">[</span>info<span class="operator">]</span> killDupAgents<span class="operator">()</span> routine started
2015/09/09 04:25:47 <span class="literal number">4883372310531</span> - - <span class="operator">[</span>debug<span class="operator">]</span> initiating spool inspection
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>info<span class="operator">]</span> initiating periodic run
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving cleanDir<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving cleanDir<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310531</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving loadNewActionsFromDB<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310531</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving loadNewActionsFromSpool<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310531</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving loadReturnedCommands<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310531</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving expireCommands<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310531</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving spoolInspection<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving markOfflineAgents<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310533</span> - - <span class="operator">[</span>debug<span class="operator">]</span> QueuesCleanup<span class="operator">()</span>: found <span class="literal number">0</span> offline endpoints between 2015-09-08 01:25:47.292598629 +0000 UTC and now
2015/09/09 04:25:47 <span class="literal number">4883372310533</span> - - <span class="operator">[</span>info<span class="operator">]</span> QueuesCleanup<span class="operator">()</span>: <span class="keyword">done</span> in 7.389363ms
2015/09/09 04:25:47 <span class="literal number">4883372310533</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving QueuesCleanup<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving markIdleAgents<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> CountNewEndpoints<span class="operator">()</span> took 7.666476ms to run
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> CountIdleEndpoints<span class="operator">()</span> took 99.925426ms to run
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> SumIdleAgentsByVersion<span class="operator">()</span> took 99.972162ms to run
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> SumOnlineAgentsByVersion<span class="operator">()</span> took 100.037988ms to run
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> CountFlappingEndpoints<span class="operator">()</span> took 100.134112ms to run
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> CountOnlineEndpoints<span class="operator">()</span> took 99.976176ms to run
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> CountDoubleAgents<span class="operator">()</span> took 99.959133ms to run
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> CountDisappearedEndpoints<span class="operator">()</span> took 99.900215ms to run
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving computeAgentsStats<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving detectMultiAgents<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>debug<span class="operator">]</span> leaving periodic<span class="operator">()</span>
2015/09/09 04:25:47 <span class="literal number">4883372310532</span> - - <span class="operator">[</span>info<span class="operator">]</span> periodic run <span class="keyword">done</span> in 110.647479ms</code></pre><p>Among the debug logs, we can see that the scheduler successfully connected
to both PostgresSQL and RabbitMQ. It detected that no scheduler key was
present in the database and created one with Key ID
"A8E1ED58512FCD9876DBEA4FEA513B95032D9932". It then proceeded to wait for
work to do, waking up regularly to perform maintenance tasks.</p><p>This working scheduler allows us to move on to the next component: the API.</p></section><section id="api-configuration"><header><h2><a href="#id12">6   API configuration</a></h2></header><p>MIG's REST API is the interface between investigators and the rest of the
infrastructure. It is also accessed by agents to discover their public IP.</p><p>The API needs to be deployed like a normal web application, preferably behind a
reverse proxy that handles TLS.</p><pre><code class="code">{investigators}-\
--&gt; {reverse proxy} -&gt; {api} -&gt; {database} -&gt; {scheduler} -&gt; {rabbitmq} -&gt; {agents}
{agents}--------/</code></pre><p>For this documentation, we will assume that the API listens on its local IP,
which is 192.168.1.150, on port 51664. The public endpoint of the api is
<cite>api.mig.example.net</cite>. A configuration could be defined as follow:</p><pre><code class="code">[authentication]
# turn this on after initial setup, once you have at least
# one investigator created
enabled = off
# when validating token timestamps, accept a timestamp that is
# within this duration of the local clock
tokenduration = 10m
[server]
# local listening ip
ip = "192.168.1.150"
# local listening port
port = 51664
# public location of the API endpoint
host = "https://api.mig.example.net"
# API base route, all endpoints are below this path
# ex: http://localhost:12345/api/v1/action/create/
# |------&lt;host&gt;--------|&lt;base&gt;|--&lt;endpoint&gt;--|
baseroute = "/api/v1"
[postgres]
host = "192.168.1.240"
port = 5432
dbname = "mig"
user = "migapi"
password = "p4QfcStzn8JIH4T4Tfr_kUzYHiPher1H"
sslmode = "disable"
[logging]
mode = "stdout" ; stdout | file | syslog
level = "debug"
; for file logging
; file = "mig_api.log"
; for syslog, logs go into local3
; host = "localhost"
; port = 514
; protocol = "udp"</code></pre><p>Note in the configuration above that authentication is disabled for now.</p><p>The Postgres credentials are taken from the user/password we generated for
user <cite>migapi</cite> during the database configuration.</p><p>Under the <cite>[server]</cite> section:</p><ul><li><p><cite>ip</cite> and <cite>port</cite> define the socket the API will be listening on.</p></li><li><p><cite>host</cite> is the public URL of the API, that clients will be connecting to</p></li><li><p><cite>baseroute</cite> is the location of the base of the API, without the trailing slash.</p></li></ul><p>In this example, to reach the home of the API, we would point our browser to
<cite>https://api.mig.example.net/api/v1/</cite>.</p><p>A sample Nginx reverse proxy configuration is shown below:</p><pre><code class="code">server {
listen 443;
ssl on;
root /var/www;
index index.html index.htm;
server_name api.mig.example.net;
client_max_body_size 200M;
# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_certificate /etc/nginx/certs/api.mig.example.net.crt;
ssl_certificate_key /etc/nginx/certs/api.mig.example.net.key;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /etc/nginx/certs/dhparam;
# modern configuration. tweak to your needs.
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
ssl_prefer_server_ciphers on;
location /api/v1/ {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://192.168.1.150:51664/api/v1/;
}
}</code></pre><p>If you're going to enable HTTPS in front of the API, make sure to use a trusted
certificate. Agents don't connect to untrusted certificates. If you can't get
one, or don't want to for a test environment, don't use HTTPS and configure the
API and Nginx to use HTTP instead. Credentials are never passed to the API, only
PGP tokens, so the worst you could expose is investigation results.</p><p>You can test that the API works properly by performing a request to the
dashboard endpoint. It should return a JSON document with all counters at zero,
since we don't have any agent connected yet.</p><pre><code class="code json"><span class="error">$</span> <span class="error">curl</span> <span class="error">https://jaffa.linuxwall.info/api/v</span><span class="literal number integer">1</span><span class="error">/dashboard</span> <span class="error">|</span> <span class="error">python</span> <span class="error">-mjson.tool</span>
<span class="punctuation">{</span>
<span class="name tag">"collection"</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="name tag">"href"</span><span class="punctuation">:</span> <span class="literal string double">"https://api.mig.example.net/api/v1/dashboard"</span><span class="punctuation">,</span>
<span class="name tag">"items"</span><span class="punctuation">:</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/dashboard"</span><span class="punctuation">,</span>
<span class="name tag">"data"</span><span class="punctuation">:</span> <span class="punctuation">[</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"online agents"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">},</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"online agents by version"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="keyword constant">null</span>
<span class="punctuation">},</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"online endpoints"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">},</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"idle agents"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">},</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"idle agents by version"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="keyword constant">null</span>
<span class="punctuation">},</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"idle endpoints"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">},</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"new endpoints"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">},</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"endpoints running 2 or more agents"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">},</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"disappeared endpoints"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">},</span>
<span class="punctuation">{</span>
<span class="name tag">"name"</span><span class="punctuation">:</span> <span class="literal string double">"flapping endpoints"</span><span class="punctuation">,</span>
<span class="name tag">"value"</span><span class="punctuation">:</span> <span class="literal number integer">0</span>
<span class="punctuation">}</span>
<span class="punctuation">]</span>
<span class="punctuation">}</span>
<span class="punctuation">],</span>
<span class="name tag">"template"</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="punctuation">}</span>
<span class="punctuation">}</span></code></pre></section><section id="build-the-clients-and-create-an-investigator"><header><h2><a href="#id13">7   Build the clients and create an investigator</a></h2></header><p>MIG has multiple command line clients that can be used to interact with the API
and run investigations or view results. The two main clients are <cite>mig</cite>, a
command line tool that can run investigations quickly, and <cite>mig-console</cite>, a
readline console that can also run investigations but browse through passed
investigations as well and manage investigators. We will use <cite>mig-console</cite> to
create our first investigator.</p><p>Here we will assume you already have GnuPG installed, and that you generate a
keypair for yourself (see the <a class="reference external" href="https://www.gnupg.org/gph/en/manual.html#AEN26">doc on gnupg.org</a>).
You should be able to access your PGP Fingerprint using this command:</p><pre><code class="code">$ gpg --fingerprint myinvestigator@example.net
pub 2048R/3B763E8F 2013-04-30
Key fingerprint = E608 92BB 9BD8 9A69 F759 A1A0 A3D6 5217 3B76 3E8F
uid My Investigator &lt;myinvestigator@example.net&gt;
sub 2048R/8026F39F 2013-04-30</code></pre><p>Next, create the client configuration file in <cite>$HOME/.migrc</cite>. Below is a sample
you can reuse with your own values.</p><pre><code class="code">$ cat ~/.migrc
[api]
url = "https://api.mig.example.net/api/v1/"
[gpg]
home = "/home/myuser/.gnupg/"
keyid = "E60892BB9BD89A69F759A1A0A3D652173B763E8F"</code></pre><p>Make sure have the dev library of readline installed (<cite>readline-devel</cite> on
rhel/fedora or <cite>libreadline-dev</cite> on debian/ubuntu) and <cite>go get</cite> the binary from
its source repository</p><pre><code class="code">$ sudo apt-get install libreadline-dev
$ go get mig.ninja/mig/client/mig-console
$ $GOPATH/bin/mig-console
## ## _.---._ .---.
# # # /-\ ---|| | /\ __...---' .---. '---'-. '.
# #| | / || | /--\ .-''__.--' _.'( | )'. '. '._ :
# # \_/ ---| \_ \_/ \ .'__-'_ .--'' ._'---'_.-. '. '-'.
### ~ -._ -._''---. -. '-._ '.
# |\ |\ /---------| ~ -.._ _ _ _ ..-_ '. '-._''--.._
# | \| \ / |- |__ | | -~ -._ '-. -. '-._''--.._.--''.
###| \ \/ ---__| | | ~ ~-.__ -._ '-.__ '. '.
##### ~~ ~---...__ _ ._ .' '.
# /\ --- /-\ |--|---- ~ ~--.....--~
# ### /--\ | | ||-\ //
#####/ \ | \_/ | \//__
+------
| Agents &amp; Endpoints summary:
| * 0 online agents on 0 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:
| Idle agents by version:
|
| Latest Actions:
| ---- ID ---- + ---- Name ---- + -Sent- + ---- Date ---- + ---- Investigators ----
+------
Connected to https://api.mig.example.net/api/v1/. Exit with ctrl+d. Type help for help.
mig&gt;</code></pre><p>The console wait for input on the <cite>mig&gt;</cite> prompt. Enter <cite>help</cite> is you want to
explore all the available functions. For now, we will only create a new
investigator in the database.</p><p>The investigator will be defined with its public key, so the first thing we
need to do is export our public key to a local file that can be given to the
console during the creation process.</p><pre><code class="code">$ gpg --export -a myinvestigator@example.net &gt; /tmp/myinvestigator_pubkey.asc</code></pre><p>Then in the console prompt, enter the following commands:</p><ul><li><p><cite>create investigator</cite></p></li><li><p>enter a name, such as <cite>Bob The Investigator</cite></p></li><li><p>enter the path to the public key <cite>/tmp/myinvestigator_pubkey.asc</cite></p></li><li><p>enter <cite>y</cite> to confirm the creation</p></li></ul><p>The console should display "Investigator 'Bob The Investigator' successfully
created with ID 2". We can view the details of this new investigator by entering
<cite>investigator 2</cite> on the console prompt.</p><pre><code class="code">mig&gt; investigator 2
Entering investigator mode. Type exit or press ctrl+d to leave. help may help.
Investigator 2 named 'Bob The Investigator'
inv 2&gt; details
Investigator ID 2
name Bob The Investigator
status active
key id E60892BB9BD89A69F759A1A0A3D652173B763E8F
created 2015-09-09 09:53:28.989481 -0400 EDT
modified 2015-09-09 09:53:28.989481 -0400 EDT</code></pre><section id="enable-api-authentication"><header><h3><a href="#id14">7.1   Enable API Authentication</a></h3></header><p>Now that we have an active investigator created, we can enable authentication
in the API. Go back to the API server and modify the configuration in
<cite>/etc/mig/api.cfg</cite>.</p><pre><code class="code">[authentication]
# turn this on after initial setup, once you have at least
# one investigator created
enabled = on</code></pre><p>Reopen the mig-console, and you will see the investigator name in the API logs:</p><pre><code class="code">2015/09/09 13:56:09 4885615083520 - - [info] src=192.168.1.243,192.168.1.1 auth=[Bob The Investigator 2] GET HTTP/1.0 /api/v1/dashboard resp_code=200 resp_size=600 user-agent=MIG Client console-20150826+62ea662.dev</code></pre><p>The benefit of the PGP token approach is the API never needs access to private keys,
and thus a compromise of the API doesn't leak credentials of investigators.</p><p>This concludes the configuration of the server side of MIG. Next we need to
build agents that can be deployed across our infrastructure.</p></section></section><section id="agent-configuration"><header><h2><a href="#id15">8   Agent Configuration</a></h2></header><p>The MIG Agent configuration must be prepared before build. The configuration is
hardwired into the agent, such that no external file is required to run it.</p><p>TLS Certificates, PGP public keys and configuration variables would normally
be stored in external files, that would make installing an agent on an endpoint
more complex. The approach of building all of the configuration parameters into
the agent means that we can ship a single binary that is self-sufficient. Go's
approach to statically built binary also helps greatly eliminate the need for
external dependencies. Once the agent is built, ship it to an endpoint, run it,
and you're done.</p><p>A template of agent configuration is in 'conf/mig-agent-conf.go.inc'. Copy this
to 'conf/mig-agent-conf.go' and edit the file. Make sure to respect Go syntax
format.</p><pre><code class="code bash"><span class="name variable">$ </span>go get mig.ninja/mig
<span class="name variable">$ </span><span class="name builtin">cd</span> <span class="name variable">$GOPATH</span>/src/mig.ninja/mig
<span class="name variable">$ </span>cp conf/mig-agent-conf.go.inc example.net.agents-conf.go
<span class="name variable">$ </span>vim conf/example.net.agents-conf.go</code></pre><p>Later on, when you run 'make mig-agent', the Makefile will copy the agent
configuration to the agent source code, and build the binary. If the
configuration file is missing, Makefile will alert you. If you have an error in
the format of the file, the Go compiler will return a list of compilation errors
for you to fix.</p><section id="amqps-configuration"><header><h3><a href="#id16">8.1   AMQPS configuration</a></h3></header><p>TLS support between agents and rabbitmq is optional, but strongly recommended.
If you want to use TLS, you need to import the PEM encoded client certificate,
client key and CA certificate that we created in the PKI step further up into
'mig-agent-conf.go'.</p><ol class="arabic"><li><p><strong>CACERT</strong> must contain the PEM encoded certificate of the Root CA.</p></li><li><p><strong>AGENTCERT</strong> must contain the PEM encoded client certificate of the agent.</p></li><li><p><strong>AGENTKEY</strong> must contain the PEM encoded client certificate of the agent.</p></li></ol><p>You also need to edit the <strong>AMQPBROKER</strong> variable to invoke <strong>amqps</strong> instead of
the regular amqp mode. You probably also want to change the port from 5672
(default amqp) to 5671 (default amqps).</p><p>In the AMQPBROKER parameter, we set the agent's RabbitMQ username and password
we generated in previous steps.</p><pre><code class="code go"><span class="keyword declaration">var</span> <span class="name other">AMQPBROKER</span> <span class="keyword type">string</span> <span class="punctuation">=</span> <span class="literal string">"amqps://agent:p1938oanvdjknxcbveufif@rabbitmq.mig.example.net:5671/mig"</span></code></pre></section><section id="id1"><header><h3><a href="#id17">8.2   API Configuration</a></h3></header><p>Agents need to know the location of the API as it is used to discover their
public IP during startup.</p><pre><code class="code go"><span class="keyword declaration">var</span> <span class="name other">APIURL</span> <span class="keyword type">string</span> <span class="punctuation">=</span> <span class="literal string">"https://api.mig.example.net/api/v1/"</span></code></pre></section><section id="proxy-support"><header><h3><a href="#id18">8.3   Proxy support</a></h3></header><p>The agent supports connecting to the relay via a CONNECT proxy. It will attempt
a direct connection first, and if this fails, will look for the environment
variable <cite>HTTP_PROXY</cite> to use as a proxy. A list of proxies can be manually
added to the configuration of the agent in the <cite>PROXIES</cite> parameters. These
proxies will be used if the two previous connections fail.</p><p>An agent using a proxy will reference the name of the proxy in the environment
fields of the heartbeat sent to the scheduler.</p></section><section id="stat-socket"><header><h3><a href="#id19">8.4   Stat socket</a></h3></header><p>The agent can establish a listening TCP socket on localhost for management
purpose. The list of supported operations can be obtained by sending the
keyword <cite>help</cite> to this socket.</p><pre><code class="code bash"><span class="name variable">$ </span>nc localhost <span class="literal number">51664</span> <span class="operator">&lt;&lt;&lt;</span> <span class="name builtin">help
</span>Welcome to the MIG agent socket. The commands are:
pid returns the PID of the running agent</code></pre><p>To obtain the PID of the running agent, use the following command:</p><pre><code class="code bash"><span class="name variable">$ </span>nc localhost <span class="literal number">51664</span> <span class="operator">&lt;&lt;&lt;</span> pid <span class="punctuation">;</span> <span class="name builtin">echo
</span>9792</code></pre><p>Leave the <cite>SOCKET</cite> configuration variable empty to disable the stat socket.</p></section><section id="logging"><header><h3><a href="#id20">8.5   Logging</a></h3></header><p>The agent can log to stdout, to a file or to the system logging. On Windows,
the system logging is the Event log. On POSIX systems, it's syslog.</p><p>The <cite>LOGGINGCONF</cite> parameter is used to configure the proper logging level.</p></section><section id="access-control-lists"><header><h3><a href="#id21">8.6   Access Control Lists</a></h3></header><p>The detail of how access control lists are created and managed is described in
<a class="reference external" href="concepts.rst">concepts: Access Control Lists</a>. In this documentation, we focus on a basic
setup that grant access of all modules to all investigators, and restricts
what the scheduler key can do.</p><p>ACL are declared in JSON hardcoded into the AGENTACL variable of the agent
configuration. For now, we only create two ACLs: a <cite>default</cite> one that grants
access to all modules to two investigators, and an <cite>agentdestroy</cite> one that
grants access to the <cite>agentdestroy</cite> module to the scheduler.</p><p>The ACLs only references the fingerprint of the public key of each investigator
and a weight that describes how much permission each investigator is granted with.</p><pre><code class="code go"><span class="comment single">// Control modules permissions by PGP keys
</span><span class="keyword declaration">var</span> <span class="name other">AGENTACL</span> <span class="punctuation">=</span> <span class="punctuation">[</span><span class="operator">...</span><span class="punctuation">]</span><span class="keyword type">string</span><span class="punctuation">{</span>
<span class="literal string">`{
"default": {
"minimumweight": 2,
"investigators": {
"Bob The Investigator": {
"fingerprint": "E60892BB9BD89A69F759A1A0A3D652173B763E8F",
"weight": 2
},
"Sam Axe": {
"fingerprint": "FA5D79F95F7AF7097C3E83DA26A86D5E5885AC11",
"weight": 2
}
}
}
}`</span><span class="punctuation">,</span>
<span class="literal string">`{
"agentdestroy": {
"minimumweight": 1,
"investigators": {
"MIG Scheduler": {
"fingerprint": "A8E1ED58512FCD9876DBEA4FEA513B95032D9932",
"weight": 1
}
}
}
}`</span><span class="punctuation">,</span>
<span class="punctuation">}</span></code></pre><p>Note that the PGP key of the scheduler was created automatically when we
started the scheduler service for the first time. You can access its
fingerprint via the mig-console, as follow:</p><pre><code class="code">$ mig-console
mig&gt; investigator 1
inv 1&gt; details
Investigator ID 1
name migscheduler
status active
key id A8E1ED58512FCD9876DBEA4FEA513B95032D9932
created 2015-09-09 00:25:47.225086 -0400 EDT
modified 2015-09-09 00:25:47.225086 -0400 EDT</code></pre><p>You can also view its public key by entering <cite>pubkey</cite> in the prompt.</p></section><section id="investigators-s-public-keys"><header><h3><a href="#id22">8.7   Investigators's public keys</a></h3></header><p>The public keys of all investigators must be listed in the <cite>PUBLICPGPKEYS</cite>
array. Each key is its own entry in the array. Since all investigators must
be created via the mig-console to have access to the API, the easiest way
to export their public keys is also via the mig-console.</p><pre><code class="code bash"><span class="name variable">$ </span>mig-console
mig&gt; investigator 2
inv 2&gt; pubkey
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQENBFF/69EBCADe79sqUKJHXTMW3tahbXPdQAnpFWXChjI9tOGbgxmse1eEGjPZ
QPFOPgu3O3iij6UOVh+LOkqccjJ8gZVLYMJzUQC+2RJ3jvXhti8xZ1hs2iEr65Rj
zUklHVZguf2Zv2X9Er8rnlW5xzplsVXNWnVvMDXyzx0ufC00dDbCwahLQnv6Vqq8
etc...</code></pre><p>Then insert the whole armored pubkey, with header and footer, into the array.
Each key must be present in the PUBLICPGPKEYS array, enclosed with backticks.
The order is irrelevant.</p><pre><code class="code go"><span class="comment single">// PGP public key that is authorized to sign actions
</span><span class="keyword declaration">var</span> <span class="name other">PUBLICPGPKEYS</span> <span class="punctuation">=</span> <span class="punctuation">[</span><span class="operator">...</span><span class="punctuation">]</span><span class="keyword type">string</span><span class="punctuation">{</span>
<span class="literal string">`-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1 - myinvestigator@example.net
mQENBFF/69EBCADe79sqUKJHXTMW3tahbXPdQAnpFWXChjI9tOGbgxmse1eEGjPZ
=3tGV
-----END PGP PUBLIC KEY BLOCK-----
`</span><span class="punctuation">,</span>
<span class="literal string">`
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1. Name: sam.axe@example.net
mQINBE5bjGABEACnT9K6MEbeDFyCty7KalsNnMjXH73kY4B8aJXbE6SSnRA3gWpa
-----END PGP PUBLIC KEY BLOCK-----`</span><span class="punctuation">}</span></code></pre></section><section id="customize-the-configuration"><header><h3><a href="#id23">8.8   Customize the configuration</a></h3></header><p>The agent has many other configuration parameters that you may want to
tweak before shipping it. Each of them is documented in the sample
configuration file.</p></section><section id="agent-build-instructions"><header><h3><a href="#id24">8.9   Agent build instructions</a></h3></header><p>Once the agent properly configured, you can build it using <cite>make</cite>. The
path to the customized configuration must be given in the <cite>AGTCONF</cite> make
variable. You can also set <cite>BUILDENV</cite> to the environment you're building
for, it is set to <cite>dev</cite> by default.</p><pre><code class="code bash"><span class="name variable">$ </span>make mig-agent <span class="name variable">AGTCONF</span><span class="operator">=</span>conf/example.net.agents-conf.go
mkdir -p bin/linux/amd64
<span class="name builtin">echo </span>building mig-agent <span class="keyword">for</span> linux/amd64
building mig-agent <span class="keyword">for</span> linux/amd64
<span class="keyword">if</span> <span class="operator">[</span> ! -r conf/linuxwall-mig-agent-conf.go <span class="operator">]</span><span class="punctuation">;</span> <span class="keyword">then</span> <span class="name builtin">echo</span> <span class="literal string double">"conf/linuxwall-mig-agent-conf.go configuration file does not exist"</span> <span class="punctuation">;</span> <span class="name builtin">exit </span>1<span class="punctuation">;</span> <span class="keyword">fi</span>
<span class="comment"># test if the agent configuration variable contains something different than the default value
# and if so, replace the link to the default configuration with the provided configuration
</span><span class="keyword">if</span> <span class="operator">[</span> conf/linuxwall-mig-agent-conf.go !<span class="operator">=</span> <span class="literal string double">"conf/mig-agent-conf.go.inc"</span> <span class="operator">]</span><span class="punctuation">;</span> <span class="keyword">then</span> rm mig-agent/configuration.go<span class="punctuation">;</span> cp conf/linuxwall-mig-agent-conf.go mig-agent/configuration.go<span class="punctuation">;</span> <span class="keyword">fi</span>
<span class="name variable">GOOS</span><span class="operator">=</span>linux <span class="name variable">GOARCH</span><span class="operator">=</span>amd64 <span class="name variable">GO15VENDOREXPERIMENT</span><span class="operator">=</span><span class="literal number">1</span> go build -o bin/linux/amd64/mig-agent-20150909+556e9c0.dev<span class="literal string double">""</span> -ldflags <span class="literal string double">"-X main.version=20150909+556e9c0.dev"</span> mig.ninja/mig/mig-agent
ln -fs <span class="literal string double">"</span><span class="keyword">$(</span><span class="name builtin">pwd</span><span class="keyword">)</span><span class="literal string double">/bin/linux/amd64/mig-agent-20150909+556e9c0.dev"""</span> <span class="literal string double">"</span><span class="keyword">$(</span><span class="name builtin">pwd</span><span class="keyword">)</span><span class="literal string double">/bin/linux/amd64/mig-agent-latest"</span>
<span class="operator">[</span> -x <span class="literal string double">"bin/linux/amd64/mig-agent-20150909+556e9c0.dev"""</span> <span class="operator">]</span> <span class="operator">&amp;&amp;</span> <span class="name builtin">echo </span>SUCCESS <span class="operator">&amp;&amp;</span> <span class="name builtin">exit </span>0
SUCCESS</code></pre><p>Built binaries will be placed in <strong>bin/linux/amd64/</strong> (or in a similar directory
if you are building on a different platform).</p><p>To cross-compile for a different platform, use the <cite>ARCH</cite> and <cite>OS</cite> make
variables:</p><pre><code class="code bash"><span class="name variable">$ </span>make mig-agent <span class="name variable">AGTCONF</span><span class="operator">=</span>conf/example.net.agents-conf.go <span class="name variable">BUILDENV</span><span class="operator">=</span>prod <span class="name variable">OS</span><span class="operator">=</span>windows <span class="name variable">ARCH</span><span class="operator">=</span>amd64</code></pre><p>You can test the agent on the command line using the debug flag <cite>-d</cite>. When run
with <cite>-d</cite>, the agent will stay in foreground and print its activity to stdout.</p><pre><code class="code bash"><span class="name variable">$ </span>sudo ./bin/linux/amd64/mig-agent-20150909+556e9c0.dev -d
<span class="operator">[</span>info<span class="operator">]</span> using <span class="name builtin">builtin </span>conf
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initChannels<span class="operator">()</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Logging routine initialized.
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving findHostname<span class="operator">()</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Ident is Debian testing-updates sid
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Init is upstart
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving findOSInfo<span class="operator">()</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Found <span class="name builtin">local </span>address 172.21.0.3/20
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Found <span class="name builtin">local </span>address fe80::3602:86ff:fe2b:6fdd/64
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Found public ip 172.21.0.3
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initAgentID<span class="operator">()</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Loading permission named <span class="literal string single">'default'</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Loading permission named <span class="literal string single">'agentdestroy'</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initACL<span class="operator">()</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> AMQP: <span class="name variable">host</span><span class="operator">=</span>rabbitmq.mig.example.net, <span class="name variable">port</span><span class="operator">=</span>5671, <span class="name variable">vhost</span><span class="operator">=</span>mig
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Loading AMQPS TLS parameters
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Establishing connection to relay
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initMQ<span class="operator">()</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initAgent<span class="operator">()</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>info<span class="operator">]</span> Mozilla InvestiGator version 20150909+556e9c0.dev: started agent gator1
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> heartbeat <span class="literal string single">'{"name":"gator1","queueloc":"linux.gator1.ft8dzivx8zxd1mu966li7fy4jx0v999cgfap4mxhdgj1v0zv","mode":"daemon","version":"20150909+556e9c0.dev","pid":2993,"starttime":"2015-09-09T10:43:30.871448608-04:00","destructiontime":"0001-01-01T00:00:00Z","heartbeatts":"2015-09-09T10:43:30.871448821-04:00","environment":{"init":"upstart","ident":"Debian testing-updates sid","os":"linux","arch":"amd64","isproxied":false,"addresses":["172.21.0.3/20","fe80::3602:86ff:fe2b:6fdd/64"],"publicip":"172.21.0.3"},"tags":{"operator":"example.net"}}'</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> Message published to exchange <span class="literal string single">'toschedulers'</span> with routing key <span class="literal string single">'mig.agt.heartbeats'</span> and body <span class="literal string single">'{"name":"gator1","queueloc":"linux.gator1.ft8dzivx8zxd1mu966li7fy4jx0v999cgfap4mxhdgj1v0zv","mode":"daemon","version":"20150909+556e9c0.dev","pid":2993,"starttime":"2015-09-09T10:43:30.871448608-04:00","destructiontime":"0001-01-01T00:00:00Z","heartbeatts":"2015-09-09T10:43:30.871448821-04:00","environment":{"init":"upstart","ident":"Debian testing-updates sid","os":"linux","arch":"amd64","isproxied":false,"addresses":["172.21.0.3/20","fe80::3602:86ff:fe2b:6fdd/64"],"publicip":"172.21.0.3"},"tags":{"operator":"example.net"}}'</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving initSocket<span class="operator">()</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>debug<span class="operator">]</span> leaving publish<span class="operator">()</span>
2015/09/09 10:43:30 - - - <span class="operator">[</span>info<span class="operator">]</span> Stat socket connected successfully on 127.0.0.1:61664
^C2015/09/09 10:43:39 - - - <span class="operator">[</span>emergency<span class="operator">]</span> Shutting down agent: <span class="literal string single">'interrupt'</span>
2015/09/09 10:43:40 - - - <span class="operator">[</span>info<span class="operator">]</span> closing sendResults channel
2015/09/09 10:43:40 - - - <span class="operator">[</span>info<span class="operator">]</span> closing parseCommands goroutine
2015/09/09 10:43:40 - - - <span class="operator">[</span>info<span class="operator">]</span> closing runModule goroutine</code></pre><p>The output above indicates that the agent successfully connected to Rabbitmq
and sent a heartbeat message. The scheduler will receive this heartbeat and
process it, but in order to mark the agent offline, the scheduler must whitelist
its queueloc value.</p><p>To do so, go back to the scheduler server and add the queueloc into
<cite>/var/cache/mig/agents_whitelist.txt</cite>. No need to restart the scheduler, it
is automatically taken into account.</p><pre><code class="code">$ echo 'linux.gator1.ft8dzivx8zxd1mu966li7fy4jx0v999cgfap4mxhdgj1v0zv' &gt;&gt; /var/cache/mig/agents_whitelist.txt</code></pre><p>At the next run of the scheduler periodic routine, the agent will be marked
as <cite>online</cite> and show up in the dashboard counters. You can browse these counters
using the <cite>mig-console</cite>.</p><pre><code class="code">mig&gt; status
+------
| Agents &amp; Endpoints summary:
| * 1 online agents on 1 endpoints
+------</code></pre></section><section id="run-your-first-investigation"><header><h3><a href="#id25">8.10   Run your first investigation</a></h3></header><p>Get the <cite>mig</cite> command line from the upstream repository and run a simple
investigation that looks for a user in <cite>/etc/passwd</cite>.</p><pre><code class="code bash"><span class="name variable">$ </span>go get mig.ninja/mig/client/mig
<span class="name variable">$ $GOPATH</span>/bin/mig file -path /etc -name <span class="literal string double">"^passwd</span><span class="name variable">$"</span><span class="literal string double"> -content "</span>^root<span class="literal string double">"
1 agents will be targeted. ctrl+c to cancel. launching in 5 4 3 2 1 GO
Following action ID 4885615083564.status=inflight.
- 100.0% done in -2m17.141481302s
1 sent, 1 done, 1 succeeded
gator1 /etc/passwd [lastmodified:2015-08-31 16:15:05.547605529 +0000 UTC, mode:-rw-r--r--, size:2251] in search 's1'
1 agent has found results</span></code></pre><p>A single file is found, as expected.</p></section></section><section id="appendix-a-manual-rabbitmq-configuration"><header><h2><a href="#id26">9   Appendix A: Manual RabbitMQ Configuration</a></h2></header><p>All communications between schedulers and agents rely on RabbitMQ's AMQP
protocol. While MIG does not rely on the security of RabbitMQ to pass orders to
agents, an attacker that gains control to the message broker would be able to
listen to all messages passed between the various components. To prevent this,
RabbitMQ must provide a reasonable amount of protection, at several levels:</p><ul><li><p>All communications on the public internet are authenticated using client and
server certificates. Since all agents share a single client certificate, this
provides minimal security, and should only be used to make it harder for
attackers to establish an AMQP connection with rabbitmq.</p></li><li><p>Agents can only listen on their own queue. This is accomplished by randomizing
the name of the agent queue.</p></li><li><p>Agents can only publish to the <cite>toschedulers</cite> exchange. This is accomplished
using tight Access Control rules to RabbitMQ.</p></li></ul><p>Note that, even if a random agent manages to connect to the relay, the scheduler
will accept its registration only if it is present in the scheduler's whitelist.</p><ol class="arabic"><li><p>On the rabbitmq server, create users:</p><blockquote><ul><li><p><strong>admin</strong>, with the tag 'administrator'</p></li><li><p><strong>scheduler</strong> , <strong>agent</strong> and <strong>worker</strong> with no tag</p></li></ul></blockquote></li></ol><p>All users should have strong passwords. The scheduler password goes into the
configuration file <cite>conf/mig-scheduler.cfg</cite>, in <cite>[mq] password</cite>. The agent
password goes into <cite>conf/mig-agent-conf.go</cite>, in the agent <cite>AMQPBROKER</cite> dial
string. The admin password is, of course, for yourself.</p><pre><code class="code bash">sudo rabbitmqctl add_user admin SomeRandomPassword
sudo rabbitmqctl set_user_tags admin administrator
sudo rabbitmqctl add_user scheduler SomeRandomPassword
sudo rabbitmqctl add_user agent SomeRandomPassword
sudo rabbitmqctl add_user worker SomeRandomPassword</code></pre><p>You can list the users with the following command:</p><pre><code class="code bash">sudo rabbitmqctl list_users</code></pre><p>On fresh installation, rabbitmq comes with a <cite>guest</cite> user that as password
<cite>guest</cite> and admin privileges. You may you to delete that account.</p><pre><code class="code bash">sudo rabbitmqctl delete_user guest</code></pre><ol class="arabic" start="2"><li><p>Create a 'mig' virtual host.</p></li></ol><pre><code class="code bash">sudo rabbitmqctl add_vhost mig
sudo rabbitmqctl list_vhosts</code></pre><ol class="arabic" start="3"><li><dl><dt>Create permissions for the scheduler user. The scheduler is allowed to:</dt><dd><ul><li><dl><dt>CONFIGURE:</dt><dd><ul><li><p>declare the exchanges <cite>toagents</cite>, <cite>toschedulers</cite> and <cite>toworkers</cite></p></li><li><p>declare and delete queues under <cite>mig.agt.*</cite></p></li></ul></dd></dl></li><li><dl><dt>WRITE:</dt><dd><ul><li><p>publish into the exchanges <cite>toagents</cite> and <cite>toworkers</cite></p></li><li><p>consume from queues <cite>mig.agt.heartbeats</cite> and <cite>mig.agt.results</cite></p></li></ul></dd></dl></li><li><dl><dt>READ:</dt><dd><ul><li><p>declare the exchanges <cite>toagents</cite>, <cite>toschedulers</cite> and <cite>toworkers</cite></p></li><li><p>consume from queues <cite>mig.agt.heartbeats</cite> and <cite>mig.agt.results</cite> bound
to the <cite>toschedulers</cite> exchange</p></li></ul></dd></dl></li></ul></dd></dl></li></ol><pre><code class="code bash">sudo rabbitmqctl set_permissions -p mig scheduler <span class="literal string escape">\
</span> <span class="literal string single">'^(toagents|toschedulers|toworkers|mig\.agt\..*)$'</span> <span class="literal string escape">\
</span> <span class="literal string single">'^(toagents|toworkers|mig\.agt\.(heartbeats|results))$'</span> <span class="literal string escape">\
</span> <span class="literal string single">'^(toagents|toschedulers|toworkers|mig\.agt\.(heartbeats|results))$'</span></code></pre><ol class="arabic" start="4"><li><dl><dt>Create permissions for the agent use. The agent is allowed to:</dt><dd><ul><li><dl><dt>CONFIGURE:</dt><dd><ul><li><p>create any queue under <cite>mig.agt.*</cite></p></li></ul></dd></dl></li><li><dl><dt>WRITE:</dt><dd><ul><li><p>publish to the <cite>toschedulers</cite> exchange</p></li><li><p>consume from queues under <cite>mig.agt.*</cite></p></li></ul></dd></dl></li><li><dl><dt>READ:</dt><dd><ul><li><p>consume from queues under <cite>mig.agt.*</cite> bound to the <cite>toagents</cite>
exchange</p></li></ul></dd></dl></li></ul></dd></dl></li></ol><pre><code class="code bash">sudo rabbitmqctl set_permissions -p mig agent <span class="literal string escape">\
</span> <span class="literal string single">'^mig\.agt\..*$'</span> <span class="literal string escape">\
</span> <span class="literal string single">'^(toschedulers|mig\.agt\..*)$'</span> <span class="literal string escape">\
</span> <span class="literal string single">'^(toagents|mig\.agt\..*)$'</span></code></pre><ol class="arabic" start="5"><li><dl><dt>Create permissions for the event workers. The workers are allowed to:</dt><dd><ul><li><dl><dt>CONFIGURE:</dt><dd><ul><li><p>declare queues under <cite>migevent.*</cite></p></li></ul></dd></dl></li><li><dl><dt>WRITE:</dt><dd><ul><li><p>consume from queues under <cite>migevent.*</cite></p></li></ul></dd></dl></li><li><dl><dt>READ:</dt><dd><ul><li><dl><dt>consume from queues under <cite>migevent.*</cite> bound to the <cite>toworkers</cite></dt><dd><p>exchange</p></dd></dl></li></ul></dd></dl></li></ul></dd></dl></li></ol><pre><code class="code bash">sudo rabbitmqctl set_permissions -p mig worker <span class="literal string escape">\
</span><span class="literal string single">'^migevent\..*$'</span> <span class="literal string escape">\
</span><span class="literal string single">'^migevent(|\..*)$'</span> <span class="literal string escape">\
</span><span class="literal string single">'^(toworkers|migevent\..*)$'</span></code></pre><ol class="arabic" start="6"><li><p>Start the scheduler, it shouldn't return any ACCESS error. You can also list
the permissions with the command:</p></li></ol><pre><code class="code bash"><span class="name variable">$ </span>sudo rabbitmqctl list_permissions -p mig <span class="punctuation">|</span> column -t
Listing permissions in vhost <span class="literal string double">"mig"</span> ...
agent ^mig<span class="literal string escape">\\</span>.agt<span class="literal string escape">\\</span>..*<span class="name variable">$ </span> ^<span class="operator">(</span>toschedulers<span class="punctuation">|</span>mig<span class="literal string escape">\\</span>.agt<span class="literal string escape">\\</span>..*<span class="operator">)</span><span class="name variable">$ </span> ^<span class="operator">(</span>toagents<span class="punctuation">|</span>mig<span class="literal string escape">\\</span>.agt<span class="literal string escape">\\</span>..*<span class="operator">)</span><span class="error">$</span>
scheduler ^<span class="operator">(</span>toagents<span class="punctuation">|</span>toschedulers<span class="punctuation">|</span>toworkers<span class="punctuation">|</span>mig<span class="literal string escape">\\</span>.agt<span class="literal string escape">\\</span>..*<span class="operator">)</span><span class="name variable">$ </span> ^<span class="operator">(</span>toagents<span class="punctuation">|</span>toworkers<span class="punctuation">|</span>mig<span class="literal string escape">\\</span>.agt<span class="literal string escape">\\</span>.<span class="operator">(</span>heartbeats<span class="punctuation">|</span>results<span class="operator">))</span><span class="name variable">$ </span> ^<span class="operator">(</span>toagents<span class="punctuation">|</span>toschedulers<span class="punctuation">|</span>toworkers<span class="punctuation">|</span>mig<span class="literal string escape">\\</span>.agt<span class="literal string escape">\\</span>.<span class="operator">(</span>heartbeats<span class="punctuation">|</span>results<span class="operator">))</span><span class="error">$</span>
worker ^migevent<span class="literal string escape">\\</span>..*<span class="name variable">$ </span> ^migevent<span class="operator">(</span><span class="punctuation">|</span><span class="literal string escape">\\</span>..*<span class="operator">)</span><span class="name variable">$ </span> ^<span class="operator">(</span>toworkers<span class="punctuation">|</span>migevent<span class="literal string escape">\\</span>..*<span class="operator">)</span><span class="error">$</span></code></pre><section id="rabbitmq-tls-configuration"><header><h3><a href="#id27">9.1   RabbitMQ TLS configuration</a></h3></header><p>The documentation from rabbitmq has a thorough explanation of SSL support in
rabbit at <a class="reference external" href="http://www.rabbitmq.com/ssl.html">http://www.rabbitmq.com/ssl.html</a> . Without going into too much
details, we need three things:</p><ol class="arabic"><li><p>a PKI (and its public cert)</p></li><li><p>a server certificate and private key for rabbitmq itself</p></li><li><p>a client certificate and private key for the agents</p></li></ol><p>You can obtain these three things on you own, or follow the openssl tutorial
from the rabbitmq documentation. Come back here when you have all three.</p><p>On the rabbitmq server, place the certificates under <strong>/etc/rabbitmq/certs/</strong>.</p><blockquote><pre>/etc/rabbitmq/certs/
├── cacert.pem
├── migrelay1.example.net.key
└── migrelay1.example.net.pem</pre></blockquote><p>Edit (or create) the configuration file of rabbitmq to reference the
certificates.</p><blockquote><pre>[
{rabbit, [
{ssl_listeners, [5671]},
{ssl_options, [{cacertfile,"/etc/rabbitmq/certs/cacert.pem"},
{certfile,"/etc/rabbitmq/certs/migrelay1.example.net.pem"},
{keyfile,"/etc/rabbitmq/certs/migrelay1.example.net.key"},
{verify,verify_peer},
{fail_if_no_peer_cert,true}
]}
]}
].</pre></blockquote></section><section id="queues-mirroring"><header><h3><a href="#id28">9.2   Queues mirroring</a></h3></header><p>By default, queues within a RabbitMQ cluster are located on a single node (the
node on which they were first declared). If that node goes down, the queue will
become unavailable. To mirror all MIG queues to all nodes of a rabbitmq cluster,
use the following policy:</p><pre><code class="code bash"><span class="comment"># rabbitmqctl -p mig set_policy mig-mirror-all "^mig\." '{"ha-mode":"all"}'
</span>Setting policy <span class="literal string double">"mig-mirror-all"</span> <span class="keyword">for</span> pattern <span class="literal string double">"^mig\\."</span> to <span class="literal string double">"{\"ha-mode\":\"all\"}"</span> with priority <span class="literal string double">"0"</span> ...
...done.</code></pre></section><section id="cluster-management"><header><h3><a href="#id29">9.3   Cluster management</a></h3></header><p>To create a cluster, all rabbitmq nodes must share a secret called erlang
cookie. The erlang cookie is located in <cite>/var/lib/rabbitmq/.erlang.cookie</cite>.
Make sure the value of the cookie is identical on all members of the cluster,
then tell one node to join another one:</p><pre><code class="code bash"><span class="comment"># rabbitmqctl stop_app
</span>Stopping node <span class="literal string single">'rabbit@ip-172-30-200-73'</span> ...
...done.
<span class="comment"># rabbitmqctl join_cluster rabbit@ip-172-30-200-42
</span>Clustering node <span class="literal string single">'rabbit@ip-172-30-200-73'</span> with <span class="literal string single">'rabbit@ip-172-30-200-42'</span> ...
...done.
<span class="comment"># rabbitmqctl start_app
</span>Starting node <span class="literal string single">'rabbit@ip-172-30-200-73'</span> ...
...done.</code></pre><p>To remove a dead node from the cluster, use the following command from any
active node of the running cluster.</p><pre><code class="code bash"><span class="comment"># rabbitmqctl forget_cluster_node rabbit@ip-172-30-200-84</span></code></pre><p>If one node of the cluster goes down, and the agents have trouble reconnecting,
they may throw the error <cite>NOT_FOUND - no binding mig.agt....</cite>. That happens when
the binding in question exists but the 'home' node of the (durable) queue is not
alive. In case of a mirrored queue that would imply that all mirrors are down.
Essentially both the queue and associated bindings are in a limbo state at that
point - they neither exist nor do they not exist. <a class="reference external" href="http://rabbitmq.1065348.n5.nabble.com/Can-t-Bind-After-Upgrading-from-3-1-1-to-3-1-5-td29793.html">source</a></p><p>The safest thing to do is to delete all the queues on the cluster, and restart
the scheduler. The agents will restart themselves.</p><pre><code class="code bash"><span class="comment"># for queue in $(rabbitmqctl list_queues -p mig|grep ^mig|awk '{print $1}')
</span><span class="keyword">do</span>
<span class="name builtin">echo </span>curl -i -u admin:adminpassword -H <span class="literal string double">"content-type:application/json"</span> <span class="literal string escape">\
</span> -XDELETE http://localhost:15672/api/queues/mig/<span class="name variable">$queue</span><span class="punctuation">;</span>
<span class="keyword">done</span></code></pre><p>(remove the <cite>echo</cite> in the command above, it's there as a safety for copy/paste
people).</p></section><section id="supporting-more-than-1024-connections"><header><h3><a href="#id30">9.4   Supporting more than 1024 connections</a></h3></header><p>If you want more than 1024 clients, you may have to increase the max number of
file descriptors that rabbitmq is allowed to hold. On linux, increase <cite>nofile</cite>
in <cite>/etc/security/limits.conf</cite> as follow:</p><pre><code class="code bash">rabbitmq - nofile 102400</code></pre><p>Then, make sure than <cite>pam_limits.so</cite> is included in <cite>/etc/pam.d/common-session</cite>:</p><pre><code class="code bash">session required pam_limits.so</code></pre></section><section id="serving-amqps-on-port-443"><header><h3><a href="#id31">9.5   Serving AMQPS on port 443</a></h3></header><p>To prevent yours agents from getting blocked by firewalls, it may be a good idea
to use port 443 for connections between agents and rabbitmq. However, rabbitmq
is not designed to run on a privileged port. The solution, then, is to use
iptables to redirect the port on the rabbitmq server.</p><pre><code class="code bash">iptables -t nat -A PREROUTING -i eth0 -p tcp --dport <span class="literal number">443</span> -j REDIRECT --to-port <span class="literal number">5671</span> -m comment --comment <span class="literal string double">"Serve RabbitMQ on HTTPS port"</span></code></pre></section></section><section id="appendix-b-scheduler-configuration-reference"><header><h2><a href="#id32">10   Appendix B: Scheduler configuration reference</a></h2></header><section id="spool-directories"><header><h3><a href="#id33">10.1   Spool directories</a></h3></header><p>The scheduler keeps copies of work in progress in a set of spool directories.
It will take of creating the spool if it doesn't exist. The spool shouldn't grow
in size beyond a few megabytes as the scheduler tries to do regular housekeeping,
but it is still preferable to put it in a large enough location.</p><pre><code class="code bash">sudo chown mig-user /var/cache/mig -R</code></pre></section><section id="whitelist"><header><h3><a href="#id34">10.2   Whitelist</a></h3></header><p>Agents's queuelocs must be listed in a whitelist file for the scheduler to accept
their registrations. The location of the whitelist is configurable, but a good
place for it is in <cite>/var/cache/mig/agents_whitelist.txt</cite>. The file contains one
queueloc string on each line. The agent queueloc is taken from the hostname of the
endpoint the agent runs on, plus a random value only known to the endpoint and
the MIG platform.</p><pre><code class="code">linux.agent123.example.net.58b3mndjmbb00
windows.db4.sub.example.com.56b2andxmyb00</code></pre><p>If the scheduler receives a heartbeat from an agent that is not present in the
whitelist, it will log an error message. An operator can process the logs and
add agents to the whitelist manually.</p><pre><code class="code">Dec 17 23:39:10 ip-172-30-200-53 mig-scheduler[9181]: - - - [warning] getHeartbeats(): Agent 'linux.somehost.example.net.4vjs8ubqo0100' is not authorized</code></pre><p>For environments that are particularly dynamic, it is possible to use regexes
in the whitelist. This is done by prepending <cite>re:</cite> to the whitelist entry.</p><pre><code class="code">re:linux.server[0-9]{1,4}.example.net.[a-z0-9]{13}</code></pre><p>Keep the list of regexes short. Until MIG implements a better agent validation
mechanisms, the whitelist is reread for every registration, and regexes are
recompiled every time. On a busy platform, this can be done hundreds of times
per second and induce heavy cpu usage.</p></section><section id="database-tuning"><header><h3><a href="#id35">10.3   Database tuning</a></h3></header><p><strong>sslmode</strong></p><p><cite>sslmode</cite> can take the values <cite>disable</cite>, <cite>require</cite> (no cert verification)
and <cite>verify-full</cite> (requires cert verification). A proper installation should
use <cite>verify-full</cite>.</p><pre><code class="code">[postgres]
sslmode = "verify-full"</code></pre><p><strong>macconn</strong></p><p>The scheduler has an extra parameter to control the max number of database
connections it can use at once. It's important to keep that number relatively
low, and increase it with the size of your infrastructure. The default value is
set to <cite>10</cite>, and a good production value is <cite>100</cite>.</p><pre><code class="code">[postgres]
maxconn = 10</code></pre><p>If the DB insertion rate is lower than the agent heartbeats rate, the scheduler
will receive more heartbeats per seconds than it can insert in the database.
When that happens, you will see the insertion lag increase in the query below:</p><pre><code class="code sql"><span class="name">mig</span><span class="operator">=&gt;</span> <span class="keyword">select</span> <span class="name">NOW</span><span class="punctuation">()</span> <span class="operator">-</span> <span class="name">heartbeattime</span> <span class="keyword">as</span> <span class="literal string symbol">"insertion lag"</span>
<span class="name">mig</span><span class="operator">-&gt;</span> <span class="keyword">from</span> <span class="name">agents</span> <span class="keyword">order</span> <span class="keyword">by</span> <span class="name">heartbeattime</span> <span class="keyword">desc</span> <span class="keyword">limit</span> <span class="literal number integer">1</span><span class="punctuation">;</span>
<span class="name">insertion</span> <span class="name">lag</span>
<span class="comment single">-----------------
</span> <span class="literal number integer">00</span><span class="punctuation">:</span><span class="literal number integer">00</span><span class="punctuation">:</span><span class="literal number integer">00</span><span class="punctuation">.</span><span class="literal number integer">212257</span>
<span class="punctuation">(</span><span class="literal number integer">1</span> <span class="keyword">row</span><span class="punctuation">)</span></code></pre><p>A healthy insertion lag should be below one second. If the lag increases, and
your DB server still isn't stuck at 100% CPU, try increasing the value of
<cite>maxconn</cite>. It will cause the scheduler to use more insertion threads.</p></section><section id="id2"><header><h3><a href="#id36">10.4   Logging</a></h3></header><p>The scheduler can log to stdout, syslog, or a target file. It will run in
foreground if the logging mode is set to 'stdout'.
For the scheduler to run as a daemon, set the mode to 'file' or 'syslog'.</p><blockquote><pre>[logging]
; select a mode between 'stdout', 'file' and 'syslog
; for syslog, logs go into local3
mode = "syslog"
level = "debug"
host = "localhost"
port = 514
protocol = "udp"</pre></blockquote></section><section id="id3"><header><h3><a href="#id37">10.5   AMQPS configuration</a></h3></header><p>TLS support between the scheduler and rabbitmq is optional but strongly
recommended. To enable it, generate a client certificate and set the
[mq] configuration section of the scheduler as follow:</p><blockquote><pre>[mq]
host = "relay1.mig.example.net"
port = 5671
user = "scheduler"
pass = "secretrabbitmqpassword"
vhost = "mig"
; TLS options
usetls = true
cacert = "/etc/mig/scheduler/cacert.pem"
tlscert = "/etc/mig/scheduler/scheduler-amqps.pem"
tlskey = "/etc/mig/scheduler/scheduler-amqps-key.pem"</pre></blockquote><p>Make sure to use <strong>fully qualified paths</strong> otherwise the scheduler will fail to
load them after going in the background.</p></section><section id="collector"><header><h3><a href="#id38">10.6   Collector</a></h3></header><p>The Collector is a routine ran periodically by the scheduler to inspect the
content of its spool. It will load files that may have been missed by the file
notification routine, and delete old files after a grace period.</p><blockquote><pre>[collector]
; frequency at which the collector runs
freq = "60s"</pre></blockquote></section><section id="periodic"><header><h3><a href="#id39">10.7   Periodic</a></h3></header><p>Periodic routines are run at <cite>freq</cite> interval to do housekeeping and accounting,
cleaning up the spool, marking agents that stopped sending hearbeats idle or
offline, computing agents stats or detecting hosts running multiple agents.</p><pre><code class="code">; the periodic runs less often that
; the collector and does cleanup and DB updates
[periodic]
; frequency at which the periodic jobs run
freq = "87s"
; delete finished actions, commands and invalids after
; this period has passed
deleteafter = "360h"
; run a rabbitmq unused queues cleanup job at this frequency
; this is DB &amp; amqp intensive so don't run it too often
queuescleanupfreq = "24h"</code></pre></section><section id="pgp"><header><h3><a href="#id40">10.8   PGP</a></h3></header><p>The scheduler uses a PGP key to issue termination order on hosts that run
multiple agents. Due to the limited scope of that key, it is stored in the
database to facilitate deployment and provisioning of multiple schedulers.</p><p>Upon startup, the scheduler will look for an investigator named <cite>migscheduler</cite>
and retrieve its private key to use it in action signing. If no investigator is
found, it generates one and inserts it into the database, such that other
schedulers can use it as well.</p><p>At the time, the scheduler public key must be manually added into the agent
configuration. This will be changed in the future when ACLs and investigators
can be dynamically distributed to agents.</p><p>In the ACL of the agent configuration file <cite>conf/mig-agent-conf.go</cite>:</p><blockquote><pre>var AGENTACL = [...]string{
`{
"agentdestroy": {
"minimumweight": 1,
"investigators": {
"MIG Scheduler": {
"fingerprint": "1E644752FB76B77245B1694E556CDD7B07E9D5D6",
"weight": 1
}
}
}
}`,
}</pre></blockquote><p>And add the public PGP key of the scheduler as well:</p><blockquote><pre>// PGP public keys that are authorized to sign actions
var PUBLICPGPKEYS = [...]string{
`
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1. Name: MIG Scheduler
mQENBFF/69EBCADe79sqUKJHXTMW3tahbXPdQAnpFWXChjI9tOGbgxmse1eEGjPZ
QPFOPgu3O3iij6UOVh+LOkqccjJ8gZVLYMJzUQC+2RJ3jvXhti8xZ1hs2iEr65Rj
zUklHVZguf2Zv2X9Er8rnlW5xzplsVXNWnVvMDXyzx0ufC00dDbCwahLQnv6Vqq8
BdUCSrvo/r7oAims8SyWE+ZObC+rw7u01Sut0ctnYrvklaM10+zkwGNOTszrduUy
.....
`
}</pre></blockquote></section></section><section id="appendix-c-advanced-agent-configuration"><header><h2><a href="#id41">11   Appendix C: Advanced agent configuration</a></h2></header><section id="agent-external-configuration-file"><header><h3><a href="#id42">11.1   Agent external configuration file</a></h3></header><p>It is possible to use a configuration file with the agent. The location of the
file can be specified using the <cite>-c</cite> flag of the agent's binary. If no flag is
specific, the agent will look for a configuration file at
<cite>/etc/mig/mig-agent.cfg</cite>. If no file is found at this location, the builtin
parameters are used.</p><p>The following parameters are <strong>not</strong> controlable by the configuration file:</p><ul><li><p>list of investigators public keys in <cite>PUBLICPGPKEYS</cite></p></li><li><p>list of access control lists in <cite>AGENTACL</cite></p></li><li><p>list of proxies in <cite>PROXIES</cite></p></li></ul><p>All other parameters can be overriden in the configuration file. Check out the
sample file <cite>mig-agent.cfg.inc</cite> in the <strong>conf</strong> folder.</p></section><section id="building-agents-packages"><header><h3><a href="#id43">11.2   Building agents packages</a></h3></header><p>The Makefile in the MIG repository contains targets that build RPM, DEB, DMG
and MSI files to facilitate the distribution of MIG Agents. These targets rely
on FPM to build packages, so make sure you have ruby and fpm installed before
proceeding.</p><p>Note that due to various packaging requirements, it is easier to build a package
on the environment it is targeted for: rhel for RPMs, debian for DEBs, macos
for DMGs and windows for MSIs.</p><p>The make targets are:</p><ul><li><p><cite>deb-agent</cite> to build debian packages</p></li><li><p><cite>rpm-agent</cite> to build rpm packages</p></li><li><p><cite>dmg-agent</cite> to build dmg packages</p></li><li><p><cite>msi-agent</cite> to build msi packages (experimental)</p></li></ul><pre><code class="code bash"><span class="name variable">$ </span>make deb-agent <span class="name variable">AGTCONF</span><span class="operator">=</span>conf/linuxwall-mig-agent-conf.go
mkdir -p bin/linux/amd64
<span class="name builtin">echo </span>building mig-agent <span class="keyword">for</span> linux/amd64
<span class="operator">[</span>...<span class="operator">]</span>
fpm -C tmp -n mig-agent --license GPL --vendor mozilla --description <span class="literal string double">"Mozilla InvestiGator Agent"</span> <span class="literal string escape">\
</span> -m <span class="literal string double">"Mozilla OpSec"</span> --url http://mig.mozilla.org --architecture x86_64 -v 20150909+556e9c0.dev <span class="literal string escape">\
</span> --after-remove tmp/agent_remove.sh --after-install tmp/agent_install.sh <span class="literal string escape">\
</span> -s dir -t deb .
Created package <span class="operator">{</span>:path<span class="operator">=</span>&gt;<span class="literal string double">"mig-agent_20150909+556e9c0.dev_amd64.deb"</span><span class="operator">}</span>
<span class="name variable">$ </span>ls -al mig-agent_20150909+556e9c0.dev_amd64.deb
-rw-r--r-- <span class="literal number">1</span> ulfr ulfr <span class="literal number">3454772</span> Sep <span class="literal number">9</span> 10:55 mig-agent_20150909+556e9c0.dev_amd64.deb</code></pre></section></section></body></html>