Skip to content

Commit

Permalink
Fix minors
Browse files Browse the repository at this point in the history
Signed-off-by: Jaehyun Nam <[email protected]>
  • Loading branch information
nam-jaehyun committed May 13, 2024
1 parent a3ef3d1 commit 77725de
Show file tree
Hide file tree
Showing 59 changed files with 621 additions and 1,258 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-test-py.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:

- name: Lint with Pylint
run: |
pylint ai_engine.py
pylint classifier.py
working-directory: ai-engine

py-pep8-ai-sentryflow:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: sentryflow-pr-checks
name: pr-checks

on:
pull_request:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: sentryflow-release-image
name: release

on:
push:
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
# SentryFlow

[![SentryFlow Docker Build](https://github.com/boanlab/numbat/actions/workflows/sentryflow-release-image.yml/badge.svg)](https://github.com/boanlab/numbat/actions/workflows/sentryflow-release-image.yml) [![CI for SentryFlow](https://github.com/boanlab/numbat/actions/workflows/ci-test-go.yml/badge.svg)](https://github.com/boanlab/numbat/actions/workflows/ci-test-go.yml) [![CI for AI](https://github.com/boanlab/sentryflow/actions/workflows/ci-test-py.yml/badge.svg)](https://github.com/boanlab/sentryflow/actions/workflows/ci-test-py.yml)
[![SentryFlow Docker Build](https://github.com/boanlab/sentryflow/actions/workflows/release.yml/badge.svg)](https://github.com/boanlab/sentryflow/actions/workflows/release.yml) [![CI for SentryFlow](https://github.com/boanlab/sentryflow/actions/workflows/ci-test-go.yml/badge.svg)](https://github.com/boanlab/sentryflow/actions/workflows/ci-test-go.yml) [![CI for AI Engine](https://github.com/boanlab/sentryflow/actions/workflows/ci-test-py.yml/badge.svg)](https://github.com/boanlab/sentryflow/actions/workflows/ci-test-py.yml)

SentryFlow is a cloud-native system for API observability and security, specializing in log collection, metric production, and data exportation.

## Architecture Overview

![Numbat_Overview](docs/sentryflow_overview.png)
![SentryFlow_Overview](docs/sentryflow_overview.png)

### Features

- Generation of API Access Logs
- Proudction of API Metrics and Statistics
- Inference of API Specifications
- Production of API Metrics
- AI-driven API Classification (Inference)

## Documentation

### Basic Information

- [Getting Started](docs/getting_started.md)
- [Use Cases](examples/README.md)

### Contribution

- [Contribution Guide](contribution/README.md)
19 changes: 9 additions & 10 deletions ai-engine/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
# SPDX-License-Identifier: Apache-2.0

# Dockerfile
FROM ubuntu:22.04

RUN apt-get update
RUN apt-get -y install git wget python3 python3-pip
RUN pip3 install grpcio grpcio-tools
FROM python:3.10-bookworm

RUN mkdir -p /ai-engine/protobuf

RUN pip3 --no-cache-dir install grpcio grpcio-tools

WORKDIR /ai-engine

COPY /ai-engine .
COPY /protobuf ./protobuf

WORKDIR /ai-engine/stringlifier
RUN pip3 install .

RUN pip3 --no-cache-dir install .

WORKDIR /ai-engine
RUN python3 -m grpc_tools.protoc --python_out=. --pyi_out=. --grpc_python_out=. -I=. protobuf/sentryflow_metrics.proto

RUN pip install -r requirements.txt
RUN pip3 --no-cache-dir install -r requirements.txt
RUN python3 -m grpc_tools.protoc --python_out=. --pyi_out=. --grpc_python_out=. -I=. protobuf/sentryflow_metrics.proto

CMD ["python3", "./ai_engine.py"]
CMD ["python3", "/ai-engine/classifier.py"]
2 changes: 1 addition & 1 deletion ai-engine/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: Apache-2.0

ENGINE_NAME = sentryflow-ai-engine
IMAGE_NAME = 5gsec/$(ENGINE_NAME)
IMAGE_NAME = boanlab/$(ENGINE_NAME)
TAG = v0.1

.PHONY: build-image
Expand Down
29 changes: 14 additions & 15 deletions ai-engine/ai_engine.py → ai-engine/classifier.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# SPDX-License-Identifier: Apache-2.0

"""SentryFlow AI API Classification Engine"""
"""SentryFlow AI Engine for API Classification"""

from concurrent import futures
from collections import Counter

import os
import grpc

from protobuf import sentryflow_metrics_pb2_grpc
from protobuf import sentryflow_metrics_pb2
from protobuf import sentryflow_metrics_pb2_grpc

from stringlifier.api import Stringlifier


Expand All @@ -18,34 +19,35 @@ class HandlerServer:
Class for gRPC Servers
"""
def __init__(self):
self.server = None
self.grpc_servers = []

try:
self.listen_addr = os.environ["AI_ENGINE_ADDRESS"]
self.listen_addr = os.environ["AI_ENGINE"]
except KeyError:
self.listen_addr = "0.0.0.0:5000"

self.server = None
self.grpc_servers = []

def init_grpc_servers(self):
"""
init_grpc_servers method that initializes and registers gRPC servers
:return: None
"""
self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
self.grpc_servers.append(APIClassificationServer()) # @todo: make this configurable
self.grpc_servers.append(APIClassifierServer())

grpc_server: GRPCServer
for grpc_server in self.grpc_servers:
grpc_server.register(self.server)

def serve(self):
"""
serve method that starts serving gRPC servers, this is blocking function.
serve method that starts serving the gRPC servers (blocking function)
:return: None
"""
self.server.add_insecure_port(self.listen_addr)

print(f"[INFO] Starting to serve on {self.listen_addr}")

self.server.start()
self.server.wait_for_termination()

Expand All @@ -69,35 +71,32 @@ def unregister(self, server):
"""


class APIClassificationServer(sentryflow_metrics_pb2_grpc.APIClassificationServicer, GRPCServer):
class APIClassifierServer(sentryflow_metrics_pb2_grpc.APIClassifierServicer, GRPCServer):
"""
Class for API Classification Server using Stringlifier
"""

def __init__(self):
self.stringlifier = Stringlifier()
print("[Init] Successfully initialized APIClassificationServer")

def register(self, server):
sentryflow_metrics_pb2_grpc.add_APIClassificationServicer_to_server(self, server)
sentryflow_metrics_pb2_grpc.add_APIClassifierServicer_to_server(self, server)

def ClassifyAPIs(self, request_iterator, _): # pylint: disable=C0103
"""
GetAPIClassification method that runs multiple API ML Classification at once
ClassifyAPIs method that runs multiple MLs for API Classification at once
:param request_iterator: The requests
:param context: The context
:return: The results
"""

for req in request_iterator:
all_paths = req.API
# for paths in all_paths:
ml_results = self.stringlifier(all_paths)

ml_counts = Counter(ml_results)
print(f"{all_paths} -> {ml_counts}")

yield sentryflow_metrics_pb2.APIClassificationResponse(APIs=ml_counts)
yield sentryflow_metrics_pb2.APIClassifierResponse(APIs=ml_counts)


if __name__ == '__main__':
Expand Down
Binary file modified ai-engine/requirements.txt
Binary file not shown.
2 changes: 1 addition & 1 deletion clients/log-client/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: Apache-2.0

CLIENT_NAME = sentryflow-log-client
IMAGE_NAME = 5gsec/$(CLIENT_NAME)
IMAGE_NAME = boanlab/$(CLIENT_NAME)
TAG = v0.1

.PHONY: build
Expand Down
27 changes: 14 additions & 13 deletions clients/log-client/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func NewClient(client pb.SentryFlowClient, clientInfo *pb.ClientInfo, logCfg str
// Contact the server and print out its response
logStream, err := client.GetAPILog(context.Background(), clientInfo)
if err != nil {
log.Fatalf("[Client] Could not get log: %v", err)
log.Fatalf("[Client] Could not get API log: %v", err)
}

fd.logStream = logStream
Expand All @@ -77,7 +77,7 @@ func NewClient(client pb.SentryFlowClient, clientInfo *pb.ClientInfo, logCfg str
if metricCfg != "none" && (metricFilter == "all" || metricFilter == "api") {
amStream, err := client.GetAPIMetrics(context.Background(), clientInfo)
if err != nil {
log.Fatalf("[Client] Could not get log: %v", err)
log.Fatalf("[Client] Could not get API metrics: %v", err)
}

fd.apiMetricStream = amStream
Expand All @@ -86,7 +86,7 @@ func NewClient(client pb.SentryFlowClient, clientInfo *pb.ClientInfo, logCfg str
if metricCfg != "none" && (metricFilter == "all" || metricFilter == "envoy") {
emStream, err := client.GetEnvoyMetrics(context.Background(), clientInfo)
if err != nil {
log.Fatalf("[Client] Could not get log: %v", err)
log.Fatalf("[Client] Could not get Enovy metrics: %v", err)
}

fd.envoyMetricStream = emStream
Expand All @@ -95,18 +95,19 @@ func NewClient(client pb.SentryFlowClient, clientInfo *pb.ClientInfo, logCfg str
return fd
}

// LogRoutine Function
func (fd *Feeder) LogRoutine(logCfg string) {
// APILogRoutine Function
func (fd *Feeder) APILogRoutine(logCfg string) {
for fd.Running {
select {
default:
data, err := fd.logStream.Recv()
if err != nil {
log.Fatalf("[Client] Failed to receive a log: %v", err)
log.Fatalf("[Client] Failed to receive an API log: %v", err)
break
}

str := ""
str = str + "== Access Log ==\n"
str = str + "== API Log ==\n"
str = str + fmt.Sprintf("%v\n", data)

if logCfg == "stdout" {
Expand All @@ -120,14 +121,14 @@ func (fd *Feeder) LogRoutine(logCfg string) {
}
}

// APIMetricRoutine Function
func (fd *Feeder) APIMetricRoutine(metricCfg string) {
// APIMetricsRoutine Function
func (fd *Feeder) APIMetricsRoutine(metricCfg string) {
for fd.Running {
select {
default:
data, err := fd.apiMetricStream.Recv()
if err != nil {
log.Fatalf("[Client] Failed to receive metrics: %v", err)
log.Fatalf("[Client] Failed to receive API metrics: %v", err)
break
}

Expand All @@ -146,15 +147,15 @@ func (fd *Feeder) APIMetricRoutine(metricCfg string) {
}
}

// EnvoyMetricRoutine Function
func (fd *Feeder) EnvoyMetricRoutine(metricCfg string) {
// EnvoyMetricsRoutine Function
func (fd *Feeder) EnvoyMetricsRoutine(metricCfg string) {
metricKeys := []string{"GAUGE", "COUNTER", "HISTOGRAM", "SUMMARY"}
for fd.Running {
select {
default:
data, err := fd.envoyMetricStream.Recv()
if err != nil {
log.Fatalf("[Client] Failed to receive metrics: %v", err)
log.Fatalf("[Client] Failed to receive Envoy metrics: %v", err)
break
}

Expand Down
6 changes: 3 additions & 3 deletions clients/log-client/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ require (
)

require (
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/protobuf v1.34.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
)
12 changes: 6 additions & 6 deletions clients/log-client/go.sum
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4=
google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
14 changes: 7 additions & 7 deletions clients/log-client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ func main() {
}

// Get arguments
logCfgPtr := flag.String("logCfg", "stdout", "Output location for logs, {stdout|file|none}")
metricCfgPtr := flag.String("metricCfg", "stdout", "Output location for envoy metrics and api metrics, {stdout|file|none}")
metricFilterPtr := flag.String("metricFilter", "envoy", "Filter for what kinds of envoy and api metric to receive, {api|policy|envoy}")
logCfgPtr := flag.String("logCfg", "stdout", "Output location for API logs, {stdout|file|none}")
metricCfgPtr := flag.String("metricCfg", "stdout", "Output location for API and Envoy metrics, {stdout|file|none}")
metricFilterPtr := flag.String("metricFilter", "envoy", "Filter to select specific API or Envoy metrics to receive, {api|envoy}")
flag.Parse()

if *logCfgPtr == "none" && *metricCfgPtr == "none" {
Expand Down Expand Up @@ -67,7 +67,7 @@ func main() {
defer conn.Close()

// Connected to the gRPC server
log.Printf("[gRPC] Started to collect Access Logs from %s", addr)
log.Printf("[gRPC] Started to collect Logs from %s", addr)

// Define clientInfo
clientInfo := &protobuf.ClientInfo{
Expand All @@ -81,18 +81,18 @@ func main() {
logClient := client.NewClient(sfClient, clientInfo, *logCfgPtr, *metricCfgPtr, *metricFilterPtr)

if *logCfgPtr != "none" {
go logClient.LogRoutine(*logCfgPtr)
go logClient.APILogRoutine(*logCfgPtr)
fmt.Printf("[APILog] Started to watch API logs\n")
}

if *metricCfgPtr != "none" {
if *metricFilterPtr == "all" || *metricFilterPtr == "api" {
go logClient.APIMetricRoutine(*metricCfgPtr)
go logClient.APIMetricsRoutine(*metricCfgPtr)
fmt.Printf("[Metric] Started to watch API Metrics\n")
}

if *metricFilterPtr == "all" || *metricFilterPtr == "envoy" {
go logClient.EnvoyMetricRoutine(*metricCfgPtr)
go logClient.EnvoyMetricsRoutine(*metricCfgPtr)
fmt.Printf("[Metric] Started to watch Envoy Metrics\n")
}
}
Expand Down
2 changes: 1 addition & 1 deletion clients/mongo-client/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: Apache-2.0

CLIENT_NAME = sentryflow-mongo-client
IMAGE_NAME = 5gsec/$(CLIENT_NAME)
IMAGE_NAME = boanlab/$(CLIENT_NAME)
TAG = v0.1

.PHONY: build
Expand Down
Loading

0 comments on commit 77725de

Please sign in to comment.