Skip to content
This repository has been archived by the owner on Jul 16, 2019. It is now read-only.

Added Docker support #9

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:2.7

COPY . /securitybot

USER securitybot

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is going to throw an error, since the user will not exist.

Adding a new user up above is the way to go, something like this:
RUN adduser --disabled-password --gecos '' securitybot


env PYTHONPATH $PYTHONPATH:/securitybot

RUN apt-get update && \
apt-get install -y mysql-client && \
Copy link

@eastebry eastebry Feb 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps rather than installing mysql in this container we could link to a separate mysql container, and include a docker-compose file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not installing MySQL server in the container. Just installing client and libs as it's a prereq for the python MySQLDB lib. I'm also using the client to test for database connection and presence before starting the bot. I could probably change these test to a Python script rather than call the client directly, should seemed to be less trouble this way.

For deployment, i'm working on a docker-compose with MySQL and a Kubernetes deployment manifest in a separate repo. Can add them here when they're ready if you'd like,

Copy link

@eastebry eastebry Feb 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. I think a docker-compose file with a MySQL linked container would be useful in this repository - makes it quite simple to get everything up and running locally.

The kubernetes config files seem a little out of scope, and something that probably wouldn't be maintained here. Let's leave that in another repository :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, added docker-compose with DB, bot and frontend. Agreed kubernetes deployment is out of scope here, will keep it separate.

pip install -r /securitybot/requirements.txt

WORKDIR /securitybot

ENTRYPOINT ["/securitybot/docker_entrypoint.sh"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per docker best practices, we should avoid running securitybot as root in the container. How about adding a new user, then adding: USER securitybot

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, fixed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was dumb of me, didn't create the user properly, and hadn't tested rebuild properly. Fixed now and added docker test to travis.

38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,44 @@ If the following were all generated successfully, Securitybot should be up and r
To test it, message the bot user it's assigned to and say `hi`.
To test the process of dealing with an alert, message `test` to test the bot.

#### Environment variable
To prevent having to modify the scripts, you can set the following environment variables to configure the bot:

|Variable|Setting|
|--------|-------|
|SLACK_API_TOKEN|Slack API Token|
|REPORTING_CHANNEL|Slack Channel ID|
|DUO_INTEGRATION_KEY|Duo Integration Key|
|DUO_SECRET_KEY|Duo Secret Key|
|DUO_ENDPOINT|Duo Endpoint|
|DB_HOST|MySQL Hostname|
|DB_USER|MySQL Username|
|DB_PASS|MySQL Password|
|DB_NAME|MySQL Database name|

#### Docker

Dockerfile is included to generate a Docker Image to run the bot. Entrypoint script will wait for database startup and initialize database if it does not already exist. Entrypoint takes one of two arguments:

* bot: Starts the main bot
* frontend: starts the frontend and API server

Run configuration will be based on the environment variables above.

Example:

Bot:
```
docker build --tag securitybot
docker run -e DB_NAME=securitybot DB_NAME=securitybot -e DB_USER=root -e DB_HOST=127.0.0.1 -e DB_PASS=password -e SLACK_API_TOKEN=<your api token> -e DUO_INTEGRATION_KEY=<your integration key> -e DUO_SECRET_KEY=<your secret key> -e DUO_ENDPOINT=<your endpoint> securitybot bot
```

Frontend:
```
docker build --tag securitybot
docker run -p 8888:8888 -e DB_NAME=securitybot -e DB_USER=root -e DB_HOST=127.0.0.1 -e DB_PASS=password securitybot frontend
```

## Architecture
Securitybot was designed to be as modular as possible.
This means that it's possible to easily swap out chat systems, 2FA providers, and alerting data sources.
Expand Down
29 changes: 29 additions & 0 deletions docker_entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash
set -e


end=$((SECONDS + 120))

# Wait max of 2 minutes for database to come up
until mysql --user $DB_USER --password=$DB_PASS --host=$DB_HOST -e"quit" || [ $SECONDS -ge $end ]; do echo "Waiting for DB"; sleep 2; done;

# Check if database is initialized
if ! mysql --user $DB_USER --password=$DB_PASS --host=$DB_HOST -e"use $DB_NAME"; then
echo "Creating database"
mysql --user $DB_USER --password=$DB_PASS --host=$DB_HOST -e"create database $DB_NAME"
echo "Populating database"
python /securitybot/util/db_up.py
fi


if [ "$1" = 'bot' ]; then
echo "Starting bot"
shift
exec python /securitybot/main.py "$@"
elif [ "$1" = 'frontend' ]; then
echo "Starting frontend"
shift
exec python /securitybot/frontend/securitybot_frontend.py "$@"
fi

exec "$@"
12 changes: 7 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
from securitybot.tasker.sql_tasker import SQLTasker
from securitybot.auth.duo import DuoAuth
from securitybot.sql import init_sql
from os import getenv

import duo_client

CONFIG = {}
SLACK_KEY = 'slack_api_token'
DUO_INTEGRATION = 'duo_integration_key'
DUO_SECRET = 'duo_secret_key'
DUO_ENDPOINT = 'duo_endpoint'
REPORTING_CHANNEL = 'some_slack_channel_id'
SLACK_KEY = getenv('SLACK_API_TOKEN', 'slack_api_token')
DUO_INTEGRATION = getenv('DUO_INTEGRATION_KEY', 'duo_integration_key')
DUO_SECRET = getenv('DUO_SECRET_KEY', 'duo_secret_key')
DUO_ENDPOINT = getenv('DUO_ENDPOINT', 'duo_endpoint')
REPORTING_CHANNEL = getenv('REPORTING_CHANNEL', 'some_slack_channel_id')
ICON_URL = 'https://dl.dropboxusercontent.com/s/t01pwfrqzbz3gzu/securitybot.png'

def init():
Expand Down
9 changes: 8 additions & 1 deletion securitybot/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@
import MySQLdb
import logging

from os import getenv
from typing import Any, Sequence

DB_HOST = getenv('DB_HOST', 'localhost')
DB_USER = getenv('DB_USER', 'root')
DB_PASS = getenv('DB_PASS', '')
DB_NAME = getenv('DB_NAME', 'securitybot')


class SQLEngine(object):
# Whether the singleton has been instantiated
_host = None # type: str
Expand Down Expand Up @@ -90,4 +97,4 @@ class SQLEngineException(Exception):
def init_sql():
# type: () -> None
'''Initializes SQL.'''
SQLEngine('localhost', 'root', '', 'securitybot')
SQLEngine(DB_HOST, DB_USER, DB_PASS, DB_NAME)
10 changes: 6 additions & 4 deletions util/db_up.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#!/usr/bin/env python
import MySQLdb
import sys
from os import getenv

# DB CONFIG GOES HERE
host = 'localhost'
user = 'root'
passwd= ''
host = getenv('DB_HOST', 'localhost')
user = getenv('DB_USER', 'root')
passwd=getenv('DB_PASS', '')
dbname=getenv('DB_NAME', 'securitybot')

db = MySQLdb.connect(host=host,
user=user,
passwd=passwd,
db='securitybot')
db=dbname)

cur = db.cursor()

Expand Down