From e86fbcaef769f3d91c3077f2d8f8af9b84438488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Arroba?= <19954079+cesararroba@users.noreply.github.com> Date: Thu, 20 Feb 2025 18:23:01 +0100 Subject: [PATCH] feat(api): setup sentry for OSS API (#6874) --- .env | 5 ++ api/.env.example | 5 ++ api/CHANGELOG.md | 1 + api/poetry.lock | 58 ++++++++++++++++++++++- api/pyproject.toml | 1 + api/src/backend/config/django/base.py | 2 + api/src/backend/config/settings/sentry.py | 54 +++++++++++++++++++++ poetry.lock | 2 +- 8 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 api/src/backend/config/settings/sentry.py diff --git a/.env b/.env index b0f3dfd7f1..964bf4295a 100644 --- a/.env +++ b/.env @@ -92,3 +92,8 @@ jQIDAQAB # openssl rand -base64 32 DJANGO_SECRETS_ENCRYPTION_KEY="oE/ltOhp/n1TdbHjVmzcjDPLcLA41CVI/4Rk+UB5ESc=" DJANGO_BROKER_VISIBILITY_TIMEOUT=86400 +DJANGO_SENTRY_DSN= + +# Sentry settings +SENTRY_ENVIRONMENT=local +SENTRY_RELEASE=local diff --git a/api/.env.example b/api/.env.example index 192317fa02..cf347b93c3 100644 --- a/api/.env.example +++ b/api/.env.example @@ -23,6 +23,7 @@ DJANGO_SECRETS_ENCRYPTION_KEY="" DJANGO_MANAGE_DB_PARTITIONS=[True|False] DJANGO_CELERY_DEADLOCK_ATTEMPTS=5 DJANGO_BROKER_VISIBILITY_TIMEOUT=86400 +DJANGO_SENTRY_DSN= # PostgreSQL settings # If running django and celery on host, use 'localhost', else use 'postgres-db' @@ -40,6 +41,10 @@ VALKEY_HOST=[localhost|valkey] VALKEY_PORT=6379 VALKEY_DB=0 +# Sentry settings +SENTRY_ENVIRONMENT=local +SENTRY_RELEASE=local + # Social login credentials DJANGO_GOOGLE_OAUTH_CLIENT_ID="" DJANGO_GOOGLE_OAUTH_CLIENT_SECRET="" diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 34f19eb29a..c317b425b6 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the **Prowler API** are documented in this file. ### Added - Social login integration with Google and GitHub [(#6906)](https://github.com/prowler-cloud/prowler/pull/6906) +- Configurable Sentry integration [(#6874)](https://github.com/prowler-cloud/prowler/pull/6874) --- diff --git a/api/poetry.lock b/api/poetry.lock index e82273ad48..ef5e4ad27c 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -4550,6 +4550,62 @@ files = [ {file = "schema-0.7.7.tar.gz", hash = "sha256:7da553abd2958a19dc2547c388cde53398b39196175a9be59ea1caf5ab0a1807"}, ] +[[package]] +name = "sentry-sdk" +version = "2.20.0" +description = "Python client for Sentry (https://sentry.io)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "sentry_sdk-2.20.0-py2.py3-none-any.whl", hash = "sha256:c359a1edf950eb5e80cffd7d9111f3dbeef57994cb4415df37d39fda2cf22364"}, + {file = "sentry_sdk-2.20.0.tar.gz", hash = "sha256:afa82713a92facf847df3c6f63cec71eb488d826a50965def3d7722aa6f0fdab"}, +] + +[package.dependencies] +certifi = "*" +django = {version = ">=1.8", optional = true, markers = "extra == \"django\""} +urllib3 = ">=1.26.11" + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +anthropic = ["anthropic (>=0.16)"] +arq = ["arq (>=0.23)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] +http2 = ["httpcore[http2] (==1.*)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +huggingface-hub = ["huggingface_hub (>=0.22)"] +langchain = ["langchain (>=0.0.210)"] +launchdarkly = ["launchdarkly-server-sdk (>=9.8.0)"] +litestar = ["litestar (>=2.0.0)"] +loguru = ["loguru (>=0.5)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] +openfeature = ["openfeature-sdk (>=0.7.1)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro"] +pure-eval = ["asttokens", "executing", "pure_eval"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +tornado = ["tornado (>=6)"] +unleash = ["UnleashClient (>=6.0.1)"] + [[package]] name = "setuptools" version = "75.8.0" @@ -5114,4 +5170,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.13" -content-hash = "d762c984b70da32828fc0b2c8b9d4849a9342b8a9ac7060c47d6e82071b740f1" +content-hash = "a8927a21c9e3006f5378b4bdf72108e0d45c2d803d59733f9824b3eaf12ff5e1" diff --git a/api/pyproject.toml b/api/pyproject.toml index 2a219106cc..90e8291101 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -33,6 +33,7 @@ psycopg2-binary = "2.9.9" pytest-celery = {extras = ["redis"], version = "^1.0.1"} # Needed for prowler compatibility python = ">=3.11,<3.13" +sentry-sdk = {extras = ["django"], version = "^2.20.0"} uuid6 = "2024.7.10" [tool.poetry.group.dev.dependencies] diff --git a/api/src/backend/config/django/base.py b/api/src/backend/config/django/base.py index 7820e9126c..bf3fbbc34c 100644 --- a/api/src/backend/config/django/base.py +++ b/api/src/backend/config/django/base.py @@ -4,6 +4,7 @@ from config.custom_logging import LOGGING # noqa from config.env import BASE_DIR, env # noqa from config.settings.celery import * # noqa from config.settings.partitions import * # noqa +from config.settings.sentry import * # noqa from config.settings.social_login import * # noqa SECRET_KEY = env("SECRET_KEY", default="secret") @@ -218,4 +219,5 @@ CACHE_STALE_WHILE_REVALIDATE = env.int("DJANGO_STALE_WHILE_REVALIDATE", 60) TESTING = False + FINDINGS_MAX_DAYS_IN_RANGE = env.int("DJANGO_FINDINGS_MAX_DAYS_IN_RANGE", 7) diff --git a/api/src/backend/config/settings/sentry.py b/api/src/backend/config/settings/sentry.py new file mode 100644 index 0000000000..c971afe836 --- /dev/null +++ b/api/src/backend/config/settings/sentry.py @@ -0,0 +1,54 @@ +import sentry_sdk +from config.env import env + +IGNORED_EXCEPTIONS = [ + # Authentication Errors from AWS + "InvalidToken", + "AccessDeniedException", + "AuthorizationErrorException", + "UnrecognizedClientException", + "UnauthorizedOperation", + "AuthFailure", + "InvalidClientTokenId", + "AccessDenied", + # Shodan Check + "No Shodan API Key", + # For now we don't want to log the RequestLimitExceeded errors + "RequestLimitExceeded", + "ThrottlingException", + "Rate exceeded", + # The following comes from urllib3 + # eu-west-1 -- HTTPClientError[126]: An HTTP Client raised an unhandled exception: AWSHTTPSConnectionPool(host='hostname.s3.eu-west-1.amazonaws.com', port=443): Pool is closed. + "Pool is closed", +] + + +def before_send(event, hint): + """ + before_send handles the Sentry events in order to sent them or not + """ + # Ignore logs with the ignored_exceptions + # https://docs.python.org/3/library/logging.html#logrecord-objects + if "log_record" in hint: + log_msg = hint["log_record"].msg + log_lvl = hint["log_record"].levelno + + # Handle Error events and discard the rest + if log_lvl == 40 and any(ignored in log_msg for ignored in IGNORED_EXCEPTIONS): + return + return event + + +sentry_sdk.init( + dsn=env.str("DJANGO_SENTRY_DSN", ""), + # Add data like request headers and IP for users, + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info + before_send=before_send, + send_default_pii=True, + _experiments={ + # Set continuous_profiling_auto_start to True + # to automatically start the profiler on when + # possible. + "continuous_profiling_auto_start": True, + }, +) diff --git a/poetry.lock b/poetry.lock index 45fdfc9ef0..f730ca2d8d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.0 and should not be changed by hand. [[package]] name = "about-time"