Add lab-02-security-as-a-system
This commit is contained in:
1 parent
dcf58ecf2a
commit
3213ab1435
10 files changed
+652
No files matched your search
@@ -0,0 +1,11 @@
|
|||||||
|
# Lab 2 — Security as a System
|
||||||
|
|
||||||
|
Lab 2 extends the MiniCorp client-router-server environment introduced in Lab 1.
|
||||||
|
|
||||||
|
Students investigate the environment to determine what the system is actually doing and use observed evidence to support their conclusions.
|
||||||
|
|
||||||
|
## Scenario
|
||||||
|
|
||||||
|
The lab reuses the shared MiniCorp client-router-server topology.
|
||||||
|
|
||||||
|
Scenario-specific services and assessment behavior are defined within this lab directory.
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
|
|
||||||
|
from service_common import record_event
|
||||||
|
|
||||||
|
|
||||||
|
HOST = os.environ["MINICORP_SERVICE_HOST"]
|
||||||
|
PORT = int(os.environ["MINICORP_SERVICE_PORT"])
|
||||||
|
|
||||||
|
SERVICE_ID = os.environ["MINICORP_SERVICE_ID"]
|
||||||
|
SERVICE_TOKEN = os.environ["MINICORP_SERVICE_TOKEN"]
|
||||||
|
|
||||||
|
EVIDENCE_LOG = os.environ["MINICORP_EVIDENCE_LOG"]
|
||||||
|
|
||||||
|
|
||||||
|
class AdminHandler(BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path != "/":
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
|
source = self.client_address[0]
|
||||||
|
|
||||||
|
record_event(
|
||||||
|
EVIDENCE_LOG,
|
||||||
|
service="admin",
|
||||||
|
service_token=SERVICE_TOKEN,
|
||||||
|
source=source,
|
||||||
|
port=PORT,
|
||||||
|
)
|
||||||
|
|
||||||
|
body = (
|
||||||
|
"MiniCorp Administration Service\n"
|
||||||
|
f"service_id: {SERVICE_ID}\n"
|
||||||
|
"environment: production\n"
|
||||||
|
"debug: enabled\n"
|
||||||
|
"backend: inventory-api\n"
|
||||||
|
).encode("utf-8")
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header(
|
||||||
|
"Content-Type",
|
||||||
|
"text/plain; charset=utf-8",
|
||||||
|
)
|
||||||
|
self.send_header(
|
||||||
|
"Content-Length",
|
||||||
|
str(len(body)),
|
||||||
|
)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
server = ThreadingHTTPServer(
|
||||||
|
(HOST, PORT),
|
||||||
|
AdminHandler,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"MiniCorp admin service listening on {HOST}:{PORT}"
|
||||||
|
)
|
||||||
|
|
||||||
|
server.serve_forever()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Lab 2: Security as a System
|
||||||
|
# Scenario-specific configuration.
|
||||||
|
#
|
||||||
|
# Reusable network topology and addressing are provided by shared/minicorp.
|
||||||
|
|
||||||
|
LAB_ID="lab-02-security-as-a-system"
|
||||||
|
LAB_NAME="Security as a System"
|
||||||
|
|
||||||
|
# MiniCorp topology used by this scenario.
|
||||||
|
LAB_TOPOLOGY="client-router-server"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Persistent environment state
|
||||||
|
#
|
||||||
|
|
||||||
|
LAB_STATE_DIR="/var/lib/minicorp/$LAB_ID"
|
||||||
|
LAB_IDENTITY_FILE="$LAB_STATE_DIR/service-identities"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Investigation evidence
|
||||||
|
#
|
||||||
|
|
||||||
|
# Evidence must be available to Codio's secure assessment environment,
|
||||||
|
# which receives the student's workspace.
|
||||||
|
LAB_EVIDENCE_DIR="/home/codio/workspace/.minicorp-lab2"
|
||||||
|
LAB_EVIDENCE_LOG="$LAB_EVIDENCE_DIR/events.jsonl"
|
||||||
|
|
||||||
|
#
|
||||||
|
# MiniCorp services
|
||||||
|
#
|
||||||
|
|
||||||
|
LAB_WEB_PORT="8000"
|
||||||
|
LAB_STATUS_PORT="8081"
|
||||||
|
LAB_ADMIN_PORT="9090"
|
||||||
|
|
||||||
|
LAB_WEB_STDOUT="/tmp/minicorp-lab2-web.stdout"
|
||||||
|
LAB_STATUS_STDOUT="/tmp/minicorp-lab2-status.stdout"
|
||||||
|
LAB_ADMIN_STDOUT="/tmp/minicorp-lab2-admin.stdout"
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
MODULUS = 1 << 24
|
||||||
|
FACTOR = 5
|
||||||
|
BIAS = 0x456789
|
||||||
|
FACTOR_INVERSE = pow(FACTOR, -1, MODULUS)
|
||||||
|
|
||||||
|
|
||||||
|
def pack(value):
|
||||||
|
number = int(value, 16)
|
||||||
|
result = (number * FACTOR + BIAS) % MODULUS
|
||||||
|
return f"{result:06x}"
|
||||||
|
|
||||||
|
|
||||||
|
def unpack(value):
|
||||||
|
number = int(value, 16)
|
||||||
|
result = ((number - BIAS) * FACTOR_INVERSE) % MODULUS
|
||||||
|
return f"{result:06x}"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
raise SystemExit(2)
|
||||||
|
|
||||||
|
operation = sys.argv[1]
|
||||||
|
value = sys.argv[2].lower()
|
||||||
|
|
||||||
|
if len(value) != 6:
|
||||||
|
raise SystemExit(2)
|
||||||
|
|
||||||
|
if operation == "pack":
|
||||||
|
print(pack(value))
|
||||||
|
elif operation == "unpack":
|
||||||
|
print(unpack(value))
|
||||||
|
else:
|
||||||
|
raise SystemExit(2)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
source "$SCRIPT_DIR/config.sh"
|
||||||
|
|
||||||
|
if [[ "$EUID" -ne 0 ]]; then
|
||||||
|
printf 'ERROR: init_state.sh must run as root.\n' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Persistent environment identity
|
||||||
|
#
|
||||||
|
|
||||||
|
mkdir -p "$LAB_STATE_DIR"
|
||||||
|
chmod 700 "$LAB_STATE_DIR"
|
||||||
|
|
||||||
|
if [[ ! -f "$LAB_IDENTITY_FILE" ]]; then
|
||||||
|
web_value="$(openssl rand -hex 3)"
|
||||||
|
api_value="$(openssl rand -hex 3)"
|
||||||
|
admin_value="$(openssl rand -hex 3)"
|
||||||
|
|
||||||
|
web_token="$(
|
||||||
|
python3 "$SCRIPT_DIR/identity.py" pack "$web_value"
|
||||||
|
)"
|
||||||
|
|
||||||
|
api_token="$(
|
||||||
|
python3 "$SCRIPT_DIR/identity.py" pack "$api_value"
|
||||||
|
)"
|
||||||
|
|
||||||
|
admin_token="$(
|
||||||
|
python3 "$SCRIPT_DIR/identity.py" pack "$admin_value"
|
||||||
|
)"
|
||||||
|
|
||||||
|
cat > "$LAB_IDENTITY_FILE" <<STATE
|
||||||
|
LAB_WEB_SERVICE_TOKEN="web-$web_token"
|
||||||
|
LAB_API_SERVICE_TOKEN="api-$api_token"
|
||||||
|
LAB_ADMIN_SERVICE_TOKEN="adm-$admin_token"
|
||||||
|
STATE
|
||||||
|
|
||||||
|
chown root:root "$LAB_IDENTITY_FILE"
|
||||||
|
chmod 600 "$LAB_IDENTITY_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Investigation evidence
|
||||||
|
#
|
||||||
|
|
||||||
|
mkdir -p "$LAB_EVIDENCE_DIR"
|
||||||
|
|
||||||
|
if [[ ! -f "$LAB_EVIDENCE_LOG" ]]; then
|
||||||
|
touch "$LAB_EVIDENCE_LOG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Keep the evidence readable by the Codio user and secure grader.
|
||||||
|
chown codio:codio "$LAB_EVIDENCE_DIR"
|
||||||
|
chown codio:codio "$LAB_EVIDENCE_LOG"
|
||||||
|
|
||||||
|
chmod 700 "$LAB_EVIDENCE_DIR"
|
||||||
|
chmod 600 "$LAB_EVIDENCE_LOG"
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
LAB_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$LAB_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
source "$SCRIPT_DIR/config.sh"
|
||||||
|
source "$REPO_ROOT/shared/minicorp/lib/minicorp.sh"
|
||||||
|
source "$REPO_ROOT/shared/minicorp/topologies/client-router-server.sh"
|
||||||
|
|
||||||
|
printf '\n'
|
||||||
|
mc_log "Resetting $LAB_NAME"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Remove runtime
|
||||||
|
#
|
||||||
|
|
||||||
|
mc_topology_client_router_server_down
|
||||||
|
|
||||||
|
rm -f \
|
||||||
|
"$LAB_WEB_STDOUT" \
|
||||||
|
"$LAB_STATUS_STDOUT" \
|
||||||
|
"$LAB_ADMIN_STDOUT"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Clear investigation evidence
|
||||||
|
#
|
||||||
|
|
||||||
|
if [[ -f "$LAB_EVIDENCE_LOG" ]]; then
|
||||||
|
: > "$LAB_EVIDENCE_LOG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '\n'
|
||||||
|
mc_log "$LAB_NAME has been reset."
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
|
||||||
|
def record_event(
|
||||||
|
evidence_log,
|
||||||
|
*,
|
||||||
|
service,
|
||||||
|
service_token,
|
||||||
|
source,
|
||||||
|
port,
|
||||||
|
result="ok",
|
||||||
|
**extra,
|
||||||
|
):
|
||||||
|
entry = {
|
||||||
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
||||||
|
"service": service,
|
||||||
|
"service_token": service_token,
|
||||||
|
"source": source,
|
||||||
|
"port": port,
|
||||||
|
"result": result,
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.update(extra)
|
||||||
|
|
||||||
|
line = (
|
||||||
|
json.dumps(
|
||||||
|
entry,
|
||||||
|
sort_keys=True,
|
||||||
|
separators=(",", ":"),
|
||||||
|
)
|
||||||
|
+ "\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
fd = os.open(
|
||||||
|
evidence_log,
|
||||||
|
os.O_WRONLY | os.O_CREAT | os.O_APPEND,
|
||||||
|
0o600,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.write(fd, line.encode("utf-8"))
|
||||||
|
finally:
|
||||||
|
os.close(fd)
|
||||||
+162
@@ -0,0 +1,162 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
LAB_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$LAB_DIR/../.." && pwd)"
|
||||||
|
|
||||||
|
source "$SCRIPT_DIR/config.sh"
|
||||||
|
source "$REPO_ROOT/shared/minicorp/lib/minicorp.sh"
|
||||||
|
source "$REPO_ROOT/shared/minicorp/topologies/client-router-server.sh"
|
||||||
|
|
||||||
|
printf '\n'
|
||||||
|
mc_log "Setting up $LAB_NAME"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Configuration
|
||||||
|
#
|
||||||
|
|
||||||
|
if [[ "$LAB_TOPOLOGY" != "client-router-server" ]]; then
|
||||||
|
mc_error "Unsupported topology: $LAB_TOPOLOGY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Required tools
|
||||||
|
#
|
||||||
|
|
||||||
|
for command_name in \
|
||||||
|
ip \
|
||||||
|
sysctl \
|
||||||
|
openssl \
|
||||||
|
python3 \
|
||||||
|
ss
|
||||||
|
do
|
||||||
|
mc_require_command "$command_name"
|
||||||
|
done
|
||||||
|
|
||||||
|
#
|
||||||
|
# Persistent state
|
||||||
|
#
|
||||||
|
|
||||||
|
mc_log "Initializing MiniCorp lab state"
|
||||||
|
|
||||||
|
"$SCRIPT_DIR/init_state.sh"
|
||||||
|
|
||||||
|
source "$LAB_IDENTITY_FILE"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Runtime service identities
|
||||||
|
#
|
||||||
|
|
||||||
|
LAB_WEB_SERVICE_ID="web-$(
|
||||||
|
python3 "$SCRIPT_DIR/identity.py" \
|
||||||
|
unpack "${LAB_WEB_SERVICE_TOKEN#web-}"
|
||||||
|
)"
|
||||||
|
|
||||||
|
LAB_API_SERVICE_ID="api-$(
|
||||||
|
python3 "$SCRIPT_DIR/identity.py" \
|
||||||
|
unpack "${LAB_API_SERVICE_TOKEN#api-}"
|
||||||
|
)"
|
||||||
|
|
||||||
|
LAB_ADMIN_SERVICE_ID="adm-$(
|
||||||
|
python3 "$SCRIPT_DIR/identity.py" \
|
||||||
|
unpack "${LAB_ADMIN_SERVICE_TOKEN#adm-}"
|
||||||
|
)"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Clean stale runtime
|
||||||
|
#
|
||||||
|
|
||||||
|
mc_log "Clearing stale MiniCorp runtime"
|
||||||
|
|
||||||
|
mc_topology_client_router_server_down \
|
||||||
|
>/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
rm -f \
|
||||||
|
"$LAB_WEB_STDOUT" \
|
||||||
|
"$LAB_STATUS_STDOUT" \
|
||||||
|
"$LAB_ADMIN_STDOUT"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Build network
|
||||||
|
#
|
||||||
|
|
||||||
|
mc_log "Building MiniCorp virtual network"
|
||||||
|
|
||||||
|
mc_topology_client_router_server_up \
|
||||||
|
>/dev/null
|
||||||
|
|
||||||
|
if ! mc_topology_client_router_server_check \
|
||||||
|
>/dev/null
|
||||||
|
then
|
||||||
|
mc_error "MiniCorp topology validation failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Start services
|
||||||
|
#
|
||||||
|
|
||||||
|
mc_log "Starting MiniCorp services"
|
||||||
|
|
||||||
|
sudo ip netns exec "$MC_SERVER_NS" env \
|
||||||
|
MINICORP_SERVICE_HOST="$MC_SERVER_ADDR" \
|
||||||
|
MINICORP_SERVICE_PORT="$LAB_WEB_PORT" \
|
||||||
|
MINICORP_SERVICE_ID="$LAB_WEB_SERVICE_ID" \
|
||||||
|
MINICORP_SERVICE_TOKEN="$LAB_WEB_SERVICE_TOKEN" \
|
||||||
|
MINICORP_EVIDENCE_LOG="$LAB_EVIDENCE_LOG" \
|
||||||
|
python3 -u "$SCRIPT_DIR/web_service.py" \
|
||||||
|
>"$LAB_WEB_STDOUT" 2>&1 &
|
||||||
|
|
||||||
|
sudo ip netns exec "$MC_SERVER_NS" env \
|
||||||
|
MINICORP_SERVICE_HOST="$MC_SERVER_ADDR" \
|
||||||
|
MINICORP_SERVICE_PORT="$LAB_STATUS_PORT" \
|
||||||
|
MINICORP_SERVICE_ID="$LAB_API_SERVICE_ID" \
|
||||||
|
MINICORP_SERVICE_TOKEN="$LAB_API_SERVICE_TOKEN" \
|
||||||
|
MINICORP_EVIDENCE_LOG="$LAB_EVIDENCE_LOG" \
|
||||||
|
python3 -u "$SCRIPT_DIR/status_service.py" \
|
||||||
|
>"$LAB_STATUS_STDOUT" 2>&1 &
|
||||||
|
|
||||||
|
sudo ip netns exec "$MC_SERVER_NS" env \
|
||||||
|
MINICORP_SERVICE_HOST="$MC_SERVER_ADDR" \
|
||||||
|
MINICORP_SERVICE_PORT="$LAB_ADMIN_PORT" \
|
||||||
|
MINICORP_SERVICE_ID="$LAB_ADMIN_SERVICE_ID" \
|
||||||
|
MINICORP_SERVICE_TOKEN="$LAB_ADMIN_SERVICE_TOKEN" \
|
||||||
|
MINICORP_EVIDENCE_LOG="$LAB_EVIDENCE_LOG" \
|
||||||
|
python3 -u "$SCRIPT_DIR/admin_service.py" \
|
||||||
|
>"$LAB_ADMIN_STDOUT" 2>&1 &
|
||||||
|
|
||||||
|
#
|
||||||
|
# Verify listeners
|
||||||
|
#
|
||||||
|
|
||||||
|
for port in \
|
||||||
|
"$LAB_WEB_PORT" \
|
||||||
|
"$LAB_STATUS_PORT" \
|
||||||
|
"$LAB_ADMIN_PORT"
|
||||||
|
do
|
||||||
|
ready=0
|
||||||
|
|
||||||
|
for attempt in {1..20}; do
|
||||||
|
if mc_exec "$MC_SERVER_NS" ss -ltn |
|
||||||
|
grep -F "$MC_SERVER_ADDR:$port" \
|
||||||
|
>/dev/null
|
||||||
|
then
|
||||||
|
ready=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$ready" -ne 1 ]]; then
|
||||||
|
mc_error \
|
||||||
|
"A required MiniCorp service failed to start."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
printf '\n'
|
||||||
|
mc_log "$LAB_NAME is ready."
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
|
|
||||||
|
from service_common import record_event
|
||||||
|
|
||||||
|
|
||||||
|
HOST = os.environ["MINICORP_SERVICE_HOST"]
|
||||||
|
PORT = int(os.environ["MINICORP_SERVICE_PORT"])
|
||||||
|
|
||||||
|
SERVICE_ID = os.environ["MINICORP_SERVICE_ID"]
|
||||||
|
SERVICE_TOKEN = os.environ["MINICORP_SERVICE_TOKEN"]
|
||||||
|
|
||||||
|
EVIDENCE_LOG = os.environ["MINICORP_EVIDENCE_LOG"]
|
||||||
|
|
||||||
|
SEQUENCE = (
|
||||||
|
"ok",
|
||||||
|
"ok",
|
||||||
|
"error",
|
||||||
|
"ok",
|
||||||
|
"error",
|
||||||
|
)
|
||||||
|
|
||||||
|
lock = threading.Lock()
|
||||||
|
request_count = 0
|
||||||
|
|
||||||
|
|
||||||
|
def next_result():
|
||||||
|
global request_count
|
||||||
|
|
||||||
|
with lock:
|
||||||
|
request_count += 1
|
||||||
|
number = request_count
|
||||||
|
|
||||||
|
result = SEQUENCE[
|
||||||
|
(number - 1) % len(SEQUENCE)
|
||||||
|
]
|
||||||
|
|
||||||
|
return number, result
|
||||||
|
|
||||||
|
|
||||||
|
class StatusHandler(BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path != "/":
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
|
number, result = next_result()
|
||||||
|
source = self.client_address[0]
|
||||||
|
|
||||||
|
record_event(
|
||||||
|
EVIDENCE_LOG,
|
||||||
|
service="status",
|
||||||
|
service_token=SERVICE_TOKEN,
|
||||||
|
source=source,
|
||||||
|
port=PORT,
|
||||||
|
result=result,
|
||||||
|
request=number,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = {
|
||||||
|
"status": result,
|
||||||
|
"service": "minicorp-api",
|
||||||
|
"service_id": SERVICE_ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
body = (
|
||||||
|
json.dumps(
|
||||||
|
response,
|
||||||
|
sort_keys=True,
|
||||||
|
)
|
||||||
|
+ "\n"
|
||||||
|
).encode("utf-8")
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header(
|
||||||
|
"Content-Type",
|
||||||
|
"application/json",
|
||||||
|
)
|
||||||
|
self.send_header(
|
||||||
|
"Content-Length",
|
||||||
|
str(len(body)),
|
||||||
|
)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
server = ThreadingHTTPServer(
|
||||||
|
(HOST, PORT),
|
||||||
|
StatusHandler,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"MiniCorp status service listening on {HOST}:{PORT}"
|
||||||
|
)
|
||||||
|
|
||||||
|
server.serve_forever()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
|
|
||||||
|
from service_common import record_event
|
||||||
|
|
||||||
|
|
||||||
|
HOST = os.environ["MINICORP_SERVICE_HOST"]
|
||||||
|
PORT = int(os.environ["MINICORP_SERVICE_PORT"])
|
||||||
|
|
||||||
|
SERVICE_ID = os.environ["MINICORP_SERVICE_ID"]
|
||||||
|
SERVICE_TOKEN = os.environ["MINICORP_SERVICE_TOKEN"]
|
||||||
|
|
||||||
|
EVIDENCE_LOG = os.environ["MINICORP_EVIDENCE_LOG"]
|
||||||
|
|
||||||
|
|
||||||
|
class WebHandler(BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path != "/":
|
||||||
|
self.send_error(404)
|
||||||
|
return
|
||||||
|
|
||||||
|
source = self.client_address[0]
|
||||||
|
|
||||||
|
record_event(
|
||||||
|
EVIDENCE_LOG,
|
||||||
|
service="web",
|
||||||
|
service_token=SERVICE_TOKEN,
|
||||||
|
source=source,
|
||||||
|
port=PORT,
|
||||||
|
)
|
||||||
|
|
||||||
|
body = (
|
||||||
|
"MiniCorp Employee Web Portal\n"
|
||||||
|
f"service_id: {SERVICE_ID}\n"
|
||||||
|
"environment: production\n"
|
||||||
|
"status: healthy\n"
|
||||||
|
).encode("utf-8")
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header(
|
||||||
|
"Content-Type",
|
||||||
|
"text/plain; charset=utf-8",
|
||||||
|
)
|
||||||
|
self.send_header(
|
||||||
|
"Content-Length",
|
||||||
|
str(len(body)),
|
||||||
|
)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
server = ThreadingHTTPServer(
|
||||||
|
(HOST, PORT),
|
||||||
|
WebHandler,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"MiniCorp web service listening on {HOST}:{PORT}"
|
||||||
|
)
|
||||||
|
|
||||||
|
server.serve_forever()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in new issue
Block a user