Skip to content

Commit

Permalink
docker-compose QA + docker swarm support
Browse files Browse the repository at this point in the history
  • Loading branch information
ajinabraham committed Nov 7, 2024
1 parent 5c1e7ee commit 8e57a78
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 178 deletions.
2 changes: 1 addition & 1 deletion .sonarcloud.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
sonar.sources=.
sonar.exclusions=mobsf/static/**/*,mobsf/templates/**/*
sonar.sourceEncoding=UTF-8
sonar.python.version=3.10, 3.11
sonar.python.version=3.10, 3.11, 3.12
42 changes: 26 additions & 16 deletions docker-compose.yml → docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
services:

postgres:
image: "postgres:latest"
image: "postgres:13"
restart: always
volumes:
- $HOME/MobSF/postgresql_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mobsf
networks:
- mobsf_network

nginx:
image: nginx:latest
restart: always
ports:
- "5432:5432"
- "80:4000"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- mobsf
networks:
- mobsf
- mobsf_network

mobsf:
environment:
image: opensecurity/mobile-security-framework-mobsf:latest
restart: always
volumes:
- $HOME/MobSF/mobsf_data:/home/mobsf/.MobSF
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mobsf
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
build:
context: .
dockerfile: Dockerfile
volumes:
- $HOME/MobSF/mobsf_data:/home/mobsf/.MobSF
ports:
- "8000:8000"
networks:
- mobsf
healthcheck:
test: curl -f http://localhost:8000/login/ || exit 1
depends_on:
- postgres
links:
- "postgres"
networks:
- mobsf_network

networks:
mobsf:
mobsf_network:
driver: bridge
28 changes: 15 additions & 13 deletions docker-compose_swarm.yml → docker/docker-compose_swarm.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
version: '3.8'
services:

postgres:
image: "postgres:${POSTGRES_VERSION:-17.0-bookworm}"
restart: always
Expand All @@ -10,37 +10,39 @@ services:
- POSTGRES_PASSWORD_FILE=/run/secrets/mobsfDB_password
- POSTGRES_DB=mobsf
networks:
- mobsf
- mobsf_network
secrets:
- mobsfDB_password

mobsf:
image: ${MOBSF_IMAGE:-opensecurity/mobile-security-framework-mobsf:latest}
restart: always
ports:
- "8000:8000"
volumes:
- $HOME/MobSF/mobsf_data:/home/mobsf/.MobSF
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD_FILE=/run/secrets/mobsfDB_password
- POSTGRES_DB=mobsf
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- MOBSF_API_KEY_FILE=/run/secrets/mobsf_api_key
image: ${MOBSF_IMAGE:-opensecurity/mobile-security-framework-mobsf:v4.0.7}
volumes:
- $HOME/MobSF/mobsf_data:/home/mobsf/.MobSF
ports:
- "8000:8000"
networks:
- mobsf
healthcheck:
test: curl -f http://localhost:8000/login/ || exit 1
depends_on:
- postgres
links:
- "postgres"
networks:
- mobsf_network
secrets:
- mobsfDB_password
- mobsf_api_key

networks:
mobsf:
mobsf_network:

secrets:
mobsfDB_password:
external: true
mobsf_api_key:
external: true
external: true
20 changes: 20 additions & 0 deletions docker/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
user nginx;
events {
worker_connections 1000;
}
http {
server {
listen 4000;
location / {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_pass http://mobsf:8000;
proxy_redirect off;
proxy_read_timeout 900;
proxy_buffering on;
}
client_max_body_size 256M;
}
}
44 changes: 44 additions & 0 deletions mobsf/MobSF/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import sys
import shutil
import threading
from hashlib import sha256
from pathlib import Path
from importlib import (
machinery,
Expand Down Expand Up @@ -168,3 +169,46 @@ def load_source(modname, filename):
module = util.module_from_spec(spec)
loader.exec_module(module)
return module


def get_docker_secret_by_file(secret_key):
try:
secret_path = os.environ.get(secret_key)
path = Path(secret_path)
if path.exists() and path.is_file():
return path.read_text().strip()
except Exception:
logger.exception('Cannot read secret from %s', secret_path)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (secret)
as clear text.
raise Exception('Cannot read secret from file')


def get_secret_from_file_or_env(env_secret_key):
docker_secret_key = f'{env_secret_key}_FILE'
if os.environ.get(docker_secret_key):
return get_docker_secret_by_file(docker_secret_key)
else:
return os.environ[env_secret_key]


def api_key(home_dir):
"""Print REST API Key."""
# Form Docker Secrets
if os.environ.get('MOBSF_API_KEY_FILE'):
logger.info('\nAPI Key read from docker secrets')
try:
return get_docker_secret_by_file('MOBSF_API_KEY_FILE')
except Exception:
logger.exception('Cannot read API Key from docker secrets')
# From Environment Variable
if os.environ.get('MOBSF_API_KEY'):
logger.info('\nAPI Key read from environment variable')
return os.environ['MOBSF_API_KEY']
home_dir = Path(home_dir)
secret_file = home_dir / 'secret'
if secret_file.exists() and secret_file.is_file():
try:
_api_key = secret_file.read_bytes().strip()
return sha256(_api_key).hexdigest()
except Exception:
logger.exception('Cannot Read API Key')
return None
13 changes: 2 additions & 11 deletions mobsf/MobSF/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,11 @@
first_run,
get_mobsf_home,
get_mobsf_version,
get_secret_from_file_or_env,
load_source,
)

logger = logging.getLogger(__name__)
# Util functions to get docker secrets
def get_docker_secret(secret_key):
secret_path = os.environ.get(secret_key)
with open(secret_path) as f:
return f.read().strip()

def get_secret_from_file_or_env(env_secret_key):
docker_secret_key = f"{env_secret_key}_FILE"
return get_docker_secret(docker_secret_key) if os.environ.get(docker_secret_key) else os.environ[env_secret_key]

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# MOBSF CONFIGURATION
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Expand Down Expand Up @@ -160,7 +151,7 @@ def get_secret_from_file_or_env(env_secret_key):
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
if (os.environ.get('POSTGRES_USER')
and (os.environ.get('POSTGRES_PASSWORD')
or os.environ.get('POSTGRES_PASSWORD_FILE'))
or os.environ.get('POSTGRES_PASSWORD_FILE'))
and os.environ.get('POSTGRES_HOST')):
# Postgres support
default = {
Expand Down
27 changes: 4 additions & 23 deletions mobsf/MobSF/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from django.utils import timezone

from mobsf.StaticAnalyzer.models import RecentScansDB
from mobsf.MobSF. init import api_key

from . import settings

Expand Down Expand Up @@ -91,40 +92,20 @@ def upstream_proxy(flaw_type):
return proxies, verify


def api_key():
"""Print REST API Key."""
if os.environ.get('MOBSF_API_KEY_FILE'):
logger.info('\nAPI Key read from docker secret')
try:
return settings.get_docker_secret('MOBSF_API_KEY_FILE')
except Exception:
logger.exception('Cannot read API Key from docker secret')
if os.environ.get('MOBSF_API_KEY'):
logger.info('\nAPI Key read from environment variable')
return os.environ['MOBSF_API_KEY']

secret_file = os.path.join(settings.MobSF_HOME, 'secret')
if is_file_exists(secret_file):
try:
_api_key = open(secret_file).read().strip()
return gen_sha256_hash(_api_key)
except Exception:
logger.exception('Cannot Read API Key')


def print_version():
"""Print MobSF Version."""
logger.info(settings.BANNER)
ver = settings.MOBSF_VER
logger.info('Author: Ajin Abraham | opensecurity.in')
mobsf_api_key = api_key(settings.MobSF_HOME)
if platform.system() == 'Windows':
logger.info('Mobile Security Framework %s', ver)
print('REST API Key: ' + api_key())
print(f'REST API Key: {mobsf_api_key}')

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (secret)
as clear text.
print('Default Credentials: mobsf/mobsf')
else:
logger.info(
'%sMobile Security Framework %s%s', Color.GREY, ver, Color.END)
print(f'REST API Key: {Color.BOLD}{api_key()}{Color.END}')
print(f'REST API Key: {Color.BOLD}{mobsf_api_key}{Color.END}')

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (secret)
as clear text.
print(f'Default Credentials: {Color.BOLD}mobsf/mobsf{Color.END}')
os = platform.system()
pltfm = platform.platform()
Expand Down
10 changes: 7 additions & 3 deletions mobsf/MobSF/views/api/api_middleware.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# -*- coding: utf_8 -*-
"""REST API Middleware."""
from hmac import compare_digest

from django.http import JsonResponse
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings

from mobsf.MobSF.utils import api_key
from mobsf.MobSF.init import api_key

OK = 200

Expand All @@ -22,10 +25,11 @@ def make_api_response(data, status=OK):

def api_auth(meta):
"""Check if API Key Matches."""
mobsf_api_key = api_key(settings.MobSF_HOME)
if 'HTTP_X_MOBSF_API_KEY' in meta:
return bool(api_key() == meta['HTTP_X_MOBSF_API_KEY'])
return compare_digest(mobsf_api_key, meta['HTTP_X_MOBSF_API_KEY'])
elif 'HTTP_AUTHORIZATION' in meta:
return bool(api_key() == meta['HTTP_AUTHORIZATION'])
return compare_digest(mobsf_api_key, meta['HTTP_AUTHORIZATION'])
return False


Expand Down
4 changes: 2 additions & 2 deletions mobsf/MobSF/views/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from mobsf.MobSF.forms import FormUtil, UploadFileForm
from mobsf.MobSF.utils import (
MD5_REGEX,
api_key,
get_md5,
is_dir_exists,
is_file_exists,
Expand All @@ -33,6 +32,7 @@
print_n_send_error_response,
python_dict,
)
from mobsf.MobSF.init import api_key
from mobsf.MobSF.views.helpers import FileType
from mobsf.MobSF.views.scanning import Scanning
from mobsf.MobSF.views.apk_downloader import apk_download
Expand Down Expand Up @@ -195,7 +195,7 @@ def api_docs(request):
if (settings.DISABLE_AUTHENTICATION == '1'
or request.user.is_staff
or request.user.groups.filter(name=MAINTAINER_GROUP).exists()):
key = api_key()
key = api_key(settings.MOBSF_HOME)
except Exception:
logger.exception('[ERROR] Failed to get API key')
context = {
Expand Down
4 changes: 2 additions & 2 deletions mobsf/StaticAnalyzer/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from django.http import HttpResponse
from django.test import Client, TestCase

from mobsf.MobSF.utils import api_key
from mobsf.MobSF.init import api_key

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -175,7 +175,7 @@ def static_analysis_test():
def api_test():
"""View for Handling REST API Test."""
logger.info('\nRunning REST API Unit test')
auth = api_key()
auth = api_key(settings.MobSF_HOME)
try:
uploaded = []
logger.info('Running Test on Upload API')
Expand Down
4 changes: 2 additions & 2 deletions mobsf/StaticAnalyzer/views/android/views/source_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
render,
)

from mobsf.MobSF.init import api_key
from mobsf.MobSF.utils import (
api_key,
is_md5,
print_n_send_error_response,
)
Expand Down Expand Up @@ -71,7 +71,7 @@ def run(request):
'hash': md5,
'source_type': typ,
'version': settings.MOBSF_VER,
'api_key': api_key(),
'api_key': api_key(settings.MobSF_HOME),
}
template = 'static_analysis/source_tree.html'
return render(request, template, context)
Expand Down
Loading

0 comments on commit 8e57a78

Please sign in to comment.