Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build Prototype Monkey Island AppImage #1069

Merged
merged 52 commits into from
Apr 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
12c40c3
build: scripts for building MonkeyIsland as an appimage
mssalvatore Feb 8, 2021
0230c26
cc: allow server_config.json to be specified at runtime
mssalvatore Feb 8, 2021
1d73f6e
cc: move DEFAULT_SERVER_CONFIG_PATH to consts.py
mssalvatore Feb 8, 2021
986219b
cc: rework EnvironmentConfig test
mssalvatore Feb 8, 2021
4b5415a
cc: fix server_config_generator behavior
mssalvatore Feb 8, 2021
98b64da
cc: simplify constructor/factory interface for EnvironmentConfig
mssalvatore Feb 9, 2021
a057dec
cc: use DEFAULT_SERVER_CONFIG_PATH in set_server_config
mssalvatore Feb 10, 2021
dd9e4bd
cc: address flake8 issues
mssalvatore Feb 10, 2021
ea14bcc
cc: rename DEFAULT_STANDARD_SERVER_CONFIG -> DEFAULT_STANDARD_SERVER_…
mssalvatore Feb 10, 2021
fc2f8ec
cc: remove unnecessary private constants in consts.py
mssalvatore Feb 10, 2021
fef44bc
cc: deploy "develop" environment by default
mssalvatore Feb 17, 2021
4cb28db
cc: reformat island_logger.py for readability
mssalvatore Feb 10, 2021
e8bb2e6
cc: allow logger config to be specified at runtime
mssalvatore Feb 10, 2021
8b37038
run black to format monkey_island.py
mssalvatore Feb 10, 2021
74e0dfd
cc: expand "~" in log file configuration
mssalvatore Feb 10, 2021
5b781c5
cc: rename DEFAULT_LOGGING_CONFIG_PATH -> DEFAULT_LOGGER_CONFIG_PATH
mssalvatore Feb 10, 2021
e6bf085
address some flake8 errors
mssalvatore Feb 10, 2021
1f57610
monkey_island.py: Add TODO to refactor argument handling
mssalvatore Feb 12, 2021
21e0b51
cc: explicitly cast tmpdir to str in test_island_logger.py
mssalvatore Feb 12, 2021
ef1ef34
Extracted island argument parsing into a separate file
VakarisZ Feb 24, 2021
64018eb
Extracted home environment mocking into a reusable fixture and added …
VakarisZ Feb 24, 2021
2d971d9
build: select server and logger config at runtime in appimage
mssalvatore Feb 11, 2021
438a270
cc: add `data_dir` property to EnvironmentConfig
mssalvatore Feb 11, 2021
3f6c268
cc: allow encryptor to store key file in variable locations
mssalvatore Feb 12, 2021
d265238
cc: format encryptor.py with black
mssalvatore Feb 12, 2021
a09cd8f
cc: expanduser in data_dir path in Encryptor
mssalvatore Feb 16, 2021
044c656
cc: rename encryptor() -> get_encryptor()
mssalvatore Feb 25, 2021
115368f
cc: rename DATA_DIR constant in test to WITH_DATA_DIR
mssalvatore Feb 25, 2021
fdeec3a
cc: rename data_dir parameter in encryptor to password_file_dir
mssalvatore Feb 25, 2021
45367bb
cc: add encrypt/decrypt test
mssalvatore Feb 25, 2021
29c9c72
cc: rename server_config_data_dir.json -> server_config_with_data_dir…
mssalvatore Feb 25, 2021
20a3d31
build: add data_dir to standard server config in appimage build
mssalvatore Feb 16, 2021
e1209dc
cc: add data_dir_abs_path property to EnvironmentConfig
mssalvatore Feb 16, 2021
b5e8d89
cc: use data_dir when running monkey agent locally from island
mssalvatore Feb 16, 2021
1fad6b4
cc: remove unnecessary `config` property from environment_singleton
mssalvatore Feb 16, 2021
921c4d0
cc: resolve some flake8 warnings
mssalvatore Mar 24, 2021
1ac67cf
build: create ~/.monkey_island with 0700 permissions
mssalvatore Feb 17, 2021
eae5881
build: prevent PyInstaller from being installed into the appimage
mssalvatore Feb 17, 2021
3c113f7
build: work around limitations in appimage-builder
mssalvatore Feb 18, 2021
a97bd19
build: remove unnecessary comments from appimage build
mssalvatore Feb 18, 2021
7910d9b
build: install nodejs 12 in appimage
mssalvatore Feb 18, 2021
5e56257
build: do not pull agent helper binaries during appimage build
mssalvatore Feb 18, 2021
412aa2b
build: remove unnecessary includes from monkey_island_builder.yml
mssalvatore Feb 19, 2021
b0af8b1
build: create appimage-comaptible server_config.json on start
mssalvatore Mar 25, 2021
2c75eab
build: remove separate pyjwt `pip install`
mssalvatore Mar 31, 2021
3d938f2
cc: Fix come incorrect import paths
mssalvatore Mar 31, 2021
05a368e
Update CHANGELOG.md to include AppImage changes
mssalvatore Mar 31, 2021
8278e0e
build: improve appimage build script quality by addressing review com…
mssalvatore Apr 1, 2021
5b1296e
build: Add README with instructions for appimage builder
mssalvatore Apr 1, 2021
bbe075b
build: remove unused monkey_island.desktop
mssalvatore Apr 1, 2021
ed3d55c
build: run `apt upgrade` in appimage script
mssalvatore Apr 5, 2021
f7cc018
build: address shellcheck findings in build_appimage.sh
mssalvatore Apr 5, 2021
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
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ os: linux

before_install:
# Init server_config.json to default
- cp monkey/monkey_island/cc/server_config.json.default monkey/monkey_island/cc/server_config.json
- cp monkey/monkey_island/cc/server_config.json.develop monkey/monkey_island/cc/server_config.json

install:
# Python
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]
### Added
- A runtime-configurable option to specify a data directory where runtime
configuration and other artifacts can be stored. #994
- Scripts to build a prototype AppImage for Monkey Island. #1069
VakarisZ marked this conversation as resolved.
Show resolved Hide resolved

### Changed
- server_config.json can be selected at runtime. #963
- Logger configuration can be selected at runtime. #971
- `mongo_key.bin` file location can be selected at runtime. #994
- Monkey agents are stored in the configurable data_dir when monkey is "run
from the island". #997
36 changes: 36 additions & 0 deletions deployment_scripts/appimage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Monkey Island AppImage

## About

This directory contains the necessary artifacts for building a prototype
monkey_island AppImage using appimage-builder.

## Building an AppImage

1. Create a clean VM or LXC (not docker!) based on Ubuntu 18.04.
1. Copy the `deployment_scripts/appimage` directory to `$HOME/` in the VM.
1. Run `sudo -v`.
1. On the VM, `cd $HOME/appimage`
1. Execute `./build_appimage.sh`. This will pull all necessary dependencies
and build the AppImage.

NOTE: This script is intended to be run from a clean VM. You can also manually
Copy link
Contributor

Choose a reason for hiding this comment

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

Woulnd't it be easier in terms of integration testing, to NOT require a new machine each time?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

LXCs are very quick to spin up. So are VMs in the right environment. Regardless, the README contains instructions on how to clean up after the script runs so that you don't need to use a fresh environment each time.

remove build artifacts by removing the following files and directories.

- $HOME/.monkey_island (optional)
- $HOME/monkey-appdir
- $HOME/git/monkey
- $HOME/appimage/appimage-builder-cache
- $HOME/appimage/"Monkey\ Island-\*-x86-64.Appimage"

After removing the above files and directories, you can again execute `bash
build_appimage.sh`.

## Running the AppImage

The build script will produce an AppImage executible named something like
`Monkey Island-VERSION-x86-64.AppImage`. Simply execute this file and you're
off to the races.

A new directory, `$HOME/.monkey_island` will be created to store runtime
artifacts.
233 changes: 233 additions & 0 deletions deployment_scripts/appimage/build_appimage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
#!/bin/bash

python_cmd="python3.7"
APPDIR="$HOME/monkey-appdir"
INSTALL_DIR="$APPDIR/usr/src"
VakarisZ marked this conversation as resolved.
Show resolved Hide resolved

GIT=$HOME/git

REPO_MONKEY_HOME=$GIT/monkey
REPO_MONKEY_SRC=$REPO_MONKEY_HOME/monkey

ISLAND_PATH="$INSTALL_DIR/monkey_island"
MONGO_PATH="$ISLAND_PATH/bin/mongodb"
ISLAND_BINARIES_PATH="$ISLAND_PATH/cc/binaries"
VakarisZ marked this conversation as resolved.
Show resolved Hide resolved

is_root() {
return "$(id -u)"
}

has_sudo() {
# 0 true, 1 false
sudo -nv > /dev/null 2>&1
return $?
}

handle_error() {
echo "Fix the errors above and rerun the script"
exit 1
}

log_message() {
VakarisZ marked this conversation as resolved.
Show resolved Hide resolved
echo -e "\n\n"
echo -e "DEPLOYMENT SCRIPT: $1"
}

setup_appdir() {
rm -rf "$APPDIR" || true
mkdir -p "$INSTALL_DIR"
}

install_pip_37() {
pip_url=https://bootstrap.pypa.io/get-pip.py
curl $pip_url -o get-pip.py
${python_cmd} get-pip.py
rm get-pip.py
}

install_nodejs() {
NODE_SRC=https://deb.nodesource.com/setup_12.x
Copy link
Contributor

Choose a reason for hiding this comment

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

If you move links like these to the top of the file, it will be easier to fix once they get broken, since you won't have to scroll the whole file. Not worth holding up the PR though

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I like having it localized, as that function is the only place it's used, but I see your point. I'll leave it for now, as this may get reworked anyway in version 2.


log_message "Installing nodejs"

curl -sL $NODE_SRC | sudo -E bash -
sudo apt-get install -y nodejs
}

install_build_prereqs() {
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe add sudo apt update as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The VM should be upgraded before building. I'll add details in a readme.

Copy link
Contributor

Choose a reason for hiding this comment

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

Even if it's docker or something, how do you know that the repositories will be updated? I'd rather we have sudo apt update in scripts than specify in the readme that "you need to run sudo apt update".

sudo apt update
sudo apt upgrade

# appimage-builder prereqs
sudo apt install -y python3 python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace

#monkey island prereqs
sudo apt install -y curl libcurl4 python3.7 python3.7-dev openssl git build-essential moreutils
VakarisZ marked this conversation as resolved.
Show resolved Hide resolved
install_pip_37
install_nodejs
}

install_appimage_builder() {
sudo pip3 install appimage-builder

install_appimage_tool
}

install_appimage_tool() {
APP_TOOL_BIN=$HOME/bin/appimagetool
APP_TOOL_URL=https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage

mkdir "$HOME"/bin
curl -L -o "$APP_TOOL_BIN" "$APP_TOOL_URL"
chmod u+x "$APP_TOOL_BIN"

PATH=$PATH:$HOME/bin
}

load_monkey_binary_config() {
tmpfile=$(mktemp)

log_message "downloading configuration"
curl -L -s -o "$tmpfile" "$config_url"

log_message "loading configuration"
source "$tmpfile"
}

clone_monkey_repo() {
if [[ ! -d ${GIT} ]]; then
mkdir -p "${GIT}"
fi

log_message "Cloning files from git"
branch=${2:-"develop"}
git clone --single-branch --recurse-submodules -b "$branch" "${MONKEY_GIT_URL}" "${REPO_MONKEY_HOME}" 2>&1 || handle_error

chmod 774 -R "${MONKEY_HOME}"
}

copy_monkey_island_to_appdir() {
cp "$REPO_MONKEY_SRC"/__init__.py "$INSTALL_DIR"
cp "$REPO_MONKEY_SRC"/monkey_island.py "$INSTALL_DIR"
cp -r "$REPO_MONKEY_SRC"/common "$INSTALL_DIR"
cp -r "$REPO_MONKEY_SRC"/monkey_island "$INSTALL_DIR"
cp ./run_appimage.sh "$INSTALL_DIR"/monkey_island/linux/
cp ./island_logger_config.json "$INSTALL_DIR"/
cp ./server_config.json.standard "$INSTALL_DIR"/monkey_island/cc/

# TODO: This is a workaround that may be able to be removed after PR #848 is
# merged. See monkey_island/cc/environment_singleton.py for more information.
cp ./server_config.json.standard "$INSTALL_DIR"/monkey_island/cc/server_config.json
}

install_monkey_island_python_dependencies() {
log_message "Installing island requirements"

requirements_island="$ISLAND_PATH/requirements.txt"
# TODO: This is an ugly hack. PyInstaller and VirtualEnv are build-time
# dependencies and should not be installed as a runtime requirement.
cat "$requirements_island" | grep -Piv "virtualenv|pyinstaller" | sponge "$requirements_island"

${python_cmd} -m pip install -r "${requirements_island}" --ignore-installed --prefix /usr --root="$APPDIR" || handle_error
}

download_monkey_agent_binaries() {
log_message "Downloading monkey agent binaries to ${ISLAND_BINARIES_PATH}"
mkdir -p "${ISLAND_BINARIES_PATH}" || handle_error
curl -L -o "${ISLAND_BINARIES_PATH}/${LINUX_32_BINARY_NAME}" "${LINUX_32_BINARY_URL}"
curl -L -o "${ISLAND_BINARIES_PATH}/${LINUX_64_BINARY_NAME}" "${LINUX_64_BINARY_URL}"
curl -L -o "${ISLAND_BINARIES_PATH}/${WINDOWS_32_BINARY_NAME}" "${WINDOWS_32_BINARY_URL}"
curl -L -o "${ISLAND_BINARIES_PATH}/${WINDOWS_64_BINARY_NAME}" "${WINDOWS_64_BINARY_URL}"

# Allow them to be executed
chmod a+x "$ISLAND_BINARIES_PATH/$LINUX_32_BINARY_NAME"
chmod a+x "$ISLAND_BINARIES_PATH/$LINUX_64_BINARY_NAME"
}

install_mongodb() {
log_message "Installing MongoDB"

mkdir -p "$MONGO_PATH"
"${ISLAND_PATH}"/linux/install_mongo.sh "${MONGO_PATH}" || handle_error
}

generate_ssl_cert() {
log_message "Generating certificate"

chmod u+x "${ISLAND_PATH}"/linux/create_certificate.sh
"${ISLAND_PATH}"/linux/create_certificate.sh "${ISLAND_PATH}"/cc
}

build_frontend() {
pushd "$ISLAND_PATH/cc/ui" || handle_error
npm install sass-loader node-sass webpack --save-dev
npm update

log_message "Generating front end"
npm run dist
popd || handle_error
}

build_appimage() {
log_message "Building AppImage"
appimage-builder --recipe monkey_island_builder.yml --log DEBUG --skip-appimage

# There is a bug or unwanted behavior in appimage-builder that causes issues
# if 32-bit binaries are present in the appimage. To work around this, we:
# 1. Build the AppDir with appimage-builder and skip building the appimage
# 2. Add the 32-bit binaries to the AppDir
# 3. Build the AppImage with appimage-builder from the already-built AppDir
#
# Note that appimage-builder replaces the interpreter on the monkey agent binaries
# when building the AppDir. This is unwanted as the monkey agents may execute in
# environments where the AppImage isn't loaded.
#
# See https://github.com/AppImageCrafters/appimage-builder/issues/93 for more info.
download_monkey_agent_binaries

appimage-builder --recipe monkey_island_builder.yml --log DEBUG --skip-build
}

if is_root; then
log_message "Please don't run this script as root"
exit 1
fi

if ! has_sudo; then
log_message "You need root permissions for some of this script operations. \
Run \`sudo -v\`, enter your password, and then re-run this script."
VakarisZ marked this conversation as resolved.
Show resolved Hide resolved
exit 1
fi

config_url="https://raw.githubusercontent.com/mssalvatore/monkey/linux-deploy-binaries/deployment_scripts/config"
VakarisZ marked this conversation as resolved.
Show resolved Hide resolved

setup_appdir

install_build_prereqs
install_appimage_builder


load_monkey_binary_config
clone_monkey_repo "$@"

copy_monkey_island_to_appdir

# Create folders
log_message "Creating island dirs under $ISLAND_PATH"
mkdir -p "${MONGO_PATH}" || handle_error

install_monkey_island_python_dependencies

install_mongodb

generate_ssl_cert

build_frontend

mkdir -p "$APPDIR"/usr/share/icons
cp "$REPO_MONKEY_SRC"/monkey_island/cc/ui/src/images/monkey-icon.svg "$APPDIR"/usr/share/icons/monkey-icon.svg

build_appimage

log_message "Deployment script finished."
exit 0
33 changes: 33 additions & 0 deletions deployment_scripts/appimage/island_logger_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"version": 1,
"disable_existing_loggers": false,
"formatters": {
"simple": {
"format": "%(asctime)s - %(filename)s:%(lineno)s - %(funcName)10s() - %(levelname)s - %(message)s"
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "simple",
"stream": "ext://sys.stdout"
},
"info_file_handler": {
"class": "logging.handlers.RotatingFileHandler",
"level": "INFO",
"formatter": "simple",
"filename": "~/.monkey_island/info.log",
"maxBytes": 10485760,
"backupCount": 20,
"encoding": "utf8"
}
},
"root": {
"level": "DEBUG",
"handlers": [
"console",
"info_file_handler"
]
}
}
40 changes: 40 additions & 0 deletions deployment_scripts/appimage/monkey_island_builder.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
version: 1

AppDir:
path: '../monkey-appdir'

app_info:
id: org.guardicore.monkey-island
name: Monkey Island
icon: monkey-icon
version: 1.10.0
exec: bin/bash
exec_args: "$APPDIR/usr/src/monkey_island/linux/run_appimage.sh"


apt:
arch: amd64
sources:
- sourceline: deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic main restricted
key_url: http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3B4FE6ACC0B21F32
- sourceline: deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic universe
- sourceline: deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic-security main restricted
- sourceline: deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic-security universe
- sourceline: deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted
- sourceline: deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ bionic-updates universe


include:
- bash
- python3.7

runtime:
env:
PATH: '${APPDIR}/usr/bin:${PATH}'
PYTHONHOME: '${APPDIR}/usr'
PYTHONPATH: '${APPDIR}/usr/lib/python3.7/site-packages'

AppImage:
update-information: None
sign-key: None
arch: x86_64
Loading