Skip to content

Commit

Permalink
uwsgi maybe
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaMahany committed Jan 24, 2024
1 parent ec504ed commit 4f9c770
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 110 deletions.
1 change: 1 addition & 0 deletions tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__
144 changes: 50 additions & 94 deletions tests/k2server.py
Original file line number Diff line number Diff line change
@@ -1,98 +1,54 @@
#!/usr/bin/env python3
import json
import sys

from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse
from flask import Flask, jsonify, request, Response

application = Flask(__name__)
agent_flags_hash = "8c3503bd-c9f7-4503-ba8e-a51215e3e565"

class K2MockServer(BaseHTTPRequestHandler):

def do_POST(self):
req_path = str(self.path)
req_path_parsed = urlparse(req_path)

# Device server: JSONRPC endpoint
if req_path_parsed.path == "/":
# Check `method` param: RequestEnrollment and RequestConfig require specific responses
req_body = json.loads(self.rfile.read(int(self.headers.get('Content-Length'))))

self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()

if req_body["method"] == "RequestEnrollment":
self.wfile.write(json.dumps({
"node_key": "abd",
"node_invalid": False
}).encode())
elif req_body["method"] == "RequestConfig":
self.wfile.write(json.dumps({
"config": "{}",
"node_invalid": False
}).encode())
else:
self.wfile.write(json.dumps({
"node_invalid": False
}).encode())

return

# Control server: get subsystems and hashes
elif req_path_parsed.path == "/api/agent/config":
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({
"token": "4223b8d9-3d29-4ec9-ba18-957650cbeff0",
"config": {
"agent_flags": agent_flags_hash
}
}).encode())
return

# Not a supported endpoint
else:
self.send_response(404)
self.end_headers()
return

def do_GET(self):
req_path = str(self.path)
req_path_parsed = urlparse(req_path)

# Control server: get challenge
if req_path_parsed.path == "/api/agent/config":
self.send_response(200)
self.send_header('Content-type', 'application/octet-stream')
self.end_headers()
self.wfile.write(b'1676065364')
return

# Control server: get agent flags
elif req_path_parsed.path == "/api/agent/object/" + agent_flags_hash:
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({"desktop_enabled": "1"}).encode())
return

# Version endpoint
elif req_path_parsed.path == "/version":
self.send_response(200)
self.send_header('Content-type', 'text/html; charset=utf-8')
self.end_headers()
self.wfile.write(b'1')
return

# Not a supported endpoint
else:
self.send_response(404)
self.end_headers()
return


if __name__ == '__main__':
s = HTTPServer(('0.0.0.0', 8080), K2MockServer)
s.serve_forever()
# Device Server: JSONRPC endpoint
@application.route("/", methods=['POST'])
def jsonrpc():
# Check `method` param: RequestEnrollment and RequestConfig require specific responses
req_body = request.get_json()
if req_body["method"] == "RequestEnrollment":
return jsonify({
"node_key": "abd",
"node_invalid": False
})
elif req_body["method"] == "RequestConfig":
return jsonify({
"config": "{}",
"node_invalid": False
})
else:
return jsonify({
"node_invalid": False
})

# Control server: get challenge
@application.route("/api/agent/config", methods=['GET'])
def challenge():
return Response(response='1676065364', status=200, mimetype='application/octet-stream')

# Control server: get subsystems and hashes
@application.route("/api/agent/config", methods=['POST'])
def subsystems():
return jsonify({
"token": "4223b8d9-3d29-4ec9-ba18-957650cbeff0",
"config": {
"agent_flags": agent_flags_hash
}
})

# Control server: get subsystem
@application.route("/api/agent/object/<hash>", methods=['GET'])
def get_subsystem():
if hash != agent_flags_hash:
return '', 404
return jsonify({"desktop_enabled": "1"})

# Version endpoint
@application.route("/version", methods=['GET'])
def version():
r = Response(response='1', status=200, mimetype='text/html')
r.headers['Content-Type'] = 'text/html; charset=utf-8'
return r
31 changes: 15 additions & 16 deletions tests/kolide-launcher.nix
Original file line number Diff line number Diff line change
Expand Up @@ -54,19 +54,20 @@ pkgs.nixosTest {
networking.interfaces.eth1.ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ];
networking.extraHosts = "127.0.0.1 app.kolide.test";

services.nginx = {
services.uwsgi = {
enable = true;
virtualHosts."app.kolide.test" = {};
};

systemd.services.mock-k2-server = {
description = "Mock K2 server (device and control)";
serviceConfig.Type = "simple";
serviceConfig.ExecStart = "${pkgs.python3}/bin/python ${./k2server.py}";
serviceConfig.Restart = "on-failure";
serviceConfig.RestartSec = 1;
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
plugins = [ "python3" ];
capabilities = [ "CAP_NET_BIND_SERVICE" ];
instance.type = "emperor";

instance.vassals.k2server = {
type = "normal";
module = "wsgi:application";
http = ":80";
cap = "net_bind_service";
pythonPackages = self: [ self.flask ];
chdir = pkgs.writeTextDir "wsgi.py" (builtins.readFile ./k2server.py);
};
};
};
};
Expand All @@ -86,14 +87,12 @@ pkgs.nixosTest {
# Wait for mock k2 server to be online
k2server.wait_for_unit("network-online.target")
k2server.wait_for_unit("mock-k2-server.service")
k2server.wait_for_unit("nginx.service")
k2server.wait_for_unit("uwsgi.service")
k2server.wait_for_open_port(80)
k2server.succeed("curl --fail http://app.kolide.test:8080/version")
k2server.succeed("curl --fail http://app.kolide.test/version")
# Ensure machine can reach mock k2 server
machine.wait_for_unit("network-online.target")
machine.succeed("curl http://app.kolide.test/")
machine.succeed("nc -v -z 192.168.1.2 80")
machine.wait_until_succeeds("curl --fail http://app.kolide.test/version", timeout=60)
Expand Down

0 comments on commit 4f9c770

Please sign in to comment.