UPDATE
This commit is contained in:
@@ -8,6 +8,15 @@ This service runs OPA as a standalone authorization engine for `backend/access_c
|
|||||||
docker compose -f accsess/docker-compose.yaml up -d
|
docker compose -f accsess/docker-compose.yaml up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you want request logging only on development, start the stack with
|
||||||
|
`APP_ENV=DEVELOP` and enable the `develop` profile. In that mode, OPA sends
|
||||||
|
decision logs to a sidecar service, and the log file is written to
|
||||||
|
`accsess/logs/opa.log` on the host through a Docker volume.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
APP_ENV=DEVELOP COMPOSE_PROFILES=develop docker compose -f accsess/docker-compose.yaml up -d
|
||||||
|
```
|
||||||
|
|
||||||
## Decision endpoints
|
## Decision endpoints
|
||||||
|
|
||||||
- Single feature: `POST /v1/data/croplogic/authz/decision`
|
- Single feature: `POST /v1/data/croplogic/authz/decision`
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
services:
|
||||||
|
requestlog:
|
||||||
|
url: http://opa-log-receiver:8282/logs
|
||||||
|
labels:
|
||||||
|
app: croplogic-authz
|
||||||
|
plugins: {}
|
||||||
|
decision_logs:
|
||||||
|
service: requestlog
|
||||||
|
reporting:
|
||||||
|
min_delay_seconds: 1
|
||||||
|
max_delay_seconds: 5
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
services: {}
|
||||||
|
labels:
|
||||||
|
app: croplogic-authz
|
||||||
|
plugins: {}
|
||||||
+24
-2
@@ -6,16 +6,38 @@ services:
|
|||||||
- run
|
- run
|
||||||
- --server
|
- --server
|
||||||
- --addr=0.0.0.0:8181
|
- --addr=0.0.0.0:8181
|
||||||
|
- --config-file=/config/opa-config.${APP_ENV:-default}.yaml
|
||||||
- /policies
|
- /policies
|
||||||
|
environment:
|
||||||
|
APP_ENV: ${APP_ENV:-}
|
||||||
ports:
|
ports:
|
||||||
- "8181:8181"
|
- "8181:8181"
|
||||||
volumes:
|
volumes:
|
||||||
- ./policies:/policies:ro
|
- ./policies:/policies:ro
|
||||||
- ./config/opa-config.yaml:/config/opa-config.yaml:ro
|
- ./config/opa-config.default.yaml:/config/opa-config.default.yaml:ro
|
||||||
|
- ./config/opa-config.DEVELOP.yaml:/config/opa-config.DEVELOP.yaml:ro
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
- crop_network
|
- crop_network
|
||||||
|
|
||||||
|
opa-log-receiver:
|
||||||
|
image: docker.iranserver.com/python:3.10
|
||||||
|
container_name: croplogic-accsess-opa-log-receiver
|
||||||
|
profiles:
|
||||||
|
- develop
|
||||||
|
command:
|
||||||
|
- python
|
||||||
|
- /app/scripts/opa_log_receiver.py
|
||||||
|
environment:
|
||||||
|
OPA_REQUEST_LOG_FILE: /logs/opa.log
|
||||||
|
OPA_REQUEST_LOG_PORT: "8282"
|
||||||
|
volumes:
|
||||||
|
- ./scripts/opa_log_receiver.py:/app/scripts/opa_log_receiver.py:ro
|
||||||
|
- ./logs:/logs
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- crop_network
|
||||||
networks:
|
networks:
|
||||||
crop_network:
|
crop_network:
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{"timestamp": "2026-04-09T20:07:30.617741+00:00", "path": "/logs/logs", "headers": {"Host": "opa-log-receiver:8282", "User-Agent": "Open Policy Agent/1.15.2 (linux, amd64)", "Content-Length": "401", "Content-Encoding": "gzip", "Content-Type": "application/json", "Accept-Encoding": "gzip"}, "body": [{"labels": {"app": "croplogic-authz", "id": "c211530e-d6bb-4067-abed-57fe193b6e5b", "version": "1.15.2"}, "decision_id": "3ee2fa07-ce00-4c79-9782-76edae020652", "path": "croplogic/authz/batch_decision", "input": {"action": "view", "features": ["feature1", "feature2", "feature3"]}, "result": {"features": {"feature1": {"allow": true, "allow_rules": [], "deny_rules": [], "matched_rules": []}, "feature2": {"allow": true, "allow_rules": [], "deny_rules": [], "matched_rules": []}, "feature3": {"allow": true, "allow_rules": [], "deny_rules": [], "matched_rules": []}}}, "requested_by": "172.29.0.1:59682", "timestamp": "2026-04-09T20:07:29.762128957Z", "metrics": {"counter_server_query_cache_hit": 0, "timer_rego_input_parse_ns": 57527, "timer_rego_query_compile_ns": 93329, "timer_rego_query_eval_ns": 199196, "timer_server_handler_ns": 471175}, "req_id": 1}]}
|
||||||
|
{"timestamp": "2026-04-09T20:08:21.624001+00:00", "path": "/logs/logs", "headers": {"Host": "opa-log-receiver:8282", "User-Agent": "Open Policy Agent/1.15.2 (linux, amd64)", "Content-Length": "544", "Content-Encoding": "gzip", "Content-Type": "application/json", "Accept-Encoding": "gzip"}, "body": [{"labels": {"app": "croplogic-authz", "id": "c211530e-d6bb-4067-abed-57fe193b6e5b", "version": "1.15.2"}, "decision_id": "b6ca9264-4576-4826-ac70-067ad6850019", "path": "croplogic/authz/batch_decision", "input": {"action": "view", "features": ["farm_management"], "resource": {"crop_types": [], "cultivation_types": [], "customization": [], "farm_id": null, "farm_types": [], "power_sensor": [], "sensor_codes": [], "subscription_plan_codes": []}, "route": "/api/farm-hub/", "user": {"email": "admin@example.com", "id": 1, "is_staff": true, "is_superuser": true, "phone_number": "0912345678", "role": "farmer", "username": "admin"}}, "result": {"features": {"farm_management": {"allow": true, "allow_rules": [], "deny_rules": [], "matched_rules": []}}}, "requested_by": "172.29.0.6:35524", "timestamp": "2026-04-09T20:08:19.762624801Z", "metrics": {"counter_server_query_cache_hit": 1, "timer_rego_input_parse_ns": 71833, "timer_rego_query_eval_ns": 127252, "timer_server_handler_ns": 231704}, "req_id": 2}]}
|
||||||
|
{"timestamp": "2026-04-09T20:08:43.385941+00:00", "path": "/logs/logs", "headers": {"Host": "opa-log-receiver:8282", "User-Agent": "Open Policy Agent/1.15.2 (linux, amd64)", "Content-Length": "621", "Content-Encoding": "gzip", "Content-Type": "application/json", "Accept-Encoding": "gzip"}, "body": [{"labels": {"app": "croplogic-authz", "id": "c211530e-d6bb-4067-abed-57fe193b6e5b", "version": "1.15.2"}, "decision_id": "b52a1754-aaf8-4c7d-9bfb-1d25d803f007", "path": "croplogic/authz/batch_decision", "input": {"action": "view", "features": ["farm_dashboard"], "resource": {"crop_types": ["\u0630\u0631\u062a", "\u06af\u0646\u062f\u0645"], "cultivation_types": [], "customization": [], "farm_id": "11111111-1111-1111-1111-111111111111", "farm_types": ["\u0632\u0631\u0627\u0639\u06cc"], "power_sensor": ["solar"], "sensor_codes": ["sensor_7_soil_moisture_sensor_v1_2"], "subscription_plan_codes": []}, "route": "/api/farm-dashboard/", "user": {"email": "admin@example.com", "id": 1, "is_staff": true, "is_superuser": true, "phone_number": "0912345678", "role": "farmer", "username": "admin"}}, "result": {"features": {"farm_dashboard": {"allow": true, "allow_rules": [], "deny_rules": [], "matched_rules": []}}}, "requested_by": "172.29.0.6:41130", "timestamp": "2026-04-09T20:08:43.104063998Z", "metrics": {"counter_server_query_cache_hit": 1, "timer_rego_input_parse_ns": 83718, "timer_rego_query_eval_ns": 141627, "timer_server_handler_ns": 263982}, "req_id": 3}]}
|
||||||
|
{"timestamp": "2026-04-09T20:12:48.961473+00:00", "path": "/logs/logs", "headers": {"Host": "opa-log-receiver:8282", "User-Agent": "Open Policy Agent/1.15.2 (linux, amd64)", "Content-Length": "625", "Content-Encoding": "gzip", "Content-Type": "application/json", "Accept-Encoding": "gzip"}, "body": [{"labels": {"app": "croplogic-authz", "id": "c211530e-d6bb-4067-abed-57fe193b6e5b", "version": "1.15.2"}, "decision_id": "98adca8f-68fb-47d6-8162-59c2cb83d18b", "path": "croplogic/authz/batch_decision", "input": {"action": "view", "features": ["farm_management"], "resource": {"crop_types": ["\u0630\u0631\u062a", "\u06af\u0646\u062f\u0645"], "cultivation_types": [], "customization": [], "farm_id": "11111111-1111-1111-1111-111111111111", "farm_types": ["\u0632\u0631\u0627\u0639\u06cc"], "power_sensor": ["solar"], "sensor_codes": ["sensor_7_soil_moisture_sensor_v1_2"], "subscription_plan_codes": []}, "route": "/api/farm-hub/11111111-1111-1111-1111-111111111111/", "user": {"email": "admin@example.com", "id": 1, "is_staff": true, "is_superuser": true, "phone_number": "0912345678", "role": "farmer", "username": "admin"}}, "result": {"features": {"farm_management": {"allow": true, "allow_rules": [], "deny_rules": [], "matched_rules": []}}}, "requested_by": "172.29.0.6:46450", "timestamp": "2026-04-09T20:12:47.941138139Z", "metrics": {"counter_server_query_cache_hit": 1, "timer_rego_input_parse_ns": 97369, "timer_rego_query_eval_ns": 181108, "timer_server_handler_ns": 317548}, "req_id": 4}]}
|
||||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
import gzip
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
|
|
||||||
|
|
||||||
|
LOG_FILE = os.environ.get("OPA_REQUEST_LOG_FILE", "/logs/opa.log")
|
||||||
|
PORT = int(os.environ.get("OPA_REQUEST_LOG_PORT", "8282"))
|
||||||
|
|
||||||
|
|
||||||
|
class DecisionLogHandler(BaseHTTPRequestHandler):
|
||||||
|
def do_POST(self):
|
||||||
|
content_length = int(self.headers.get("Content-Length", "0"))
|
||||||
|
raw_payload = self.rfile.read(content_length) if content_length else b""
|
||||||
|
content_encoding = self.headers.get("Content-Encoding", "").lower()
|
||||||
|
|
||||||
|
if content_encoding == "gzip" and raw_payload:
|
||||||
|
raw_payload = gzip.decompress(raw_payload)
|
||||||
|
|
||||||
|
payload = raw_payload.decode("utf-8") if raw_payload else ""
|
||||||
|
|
||||||
|
entry = {
|
||||||
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
||||||
|
"path": self.path,
|
||||||
|
"headers": dict(self.headers.items()),
|
||||||
|
"body": json.loads(payload) if payload else None,
|
||||||
|
}
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)
|
||||||
|
with open(LOG_FILE, "a", encoding="utf-8") as log_file:
|
||||||
|
log_file.write(json.dumps(entry, ensure_ascii=True) + "\n")
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"ok")
|
||||||
|
|
||||||
|
def log_message(self, format, *args):
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
server = ThreadingHTTPServer(("0.0.0.0", PORT), DecisionLogHandler)
|
||||||
|
server.serve_forever()
|
||||||
Reference in New Issue
Block a user