Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scheduler rate limit functionality #1611

Draft
wants to merge 51 commits into
base: main
Choose a base branch
from

Conversation

jpbruinsslot
Copy link
Contributor

@jpbruinsslot jpbruinsslot commented Aug 14, 2023

Changes

This PR adds rate-limiting capabilities to the scheduler for tasks. Boefjes that are subject to rate limiting (defined in the boefje manifest) are being tracked by an in-memory rate limiter leveraging the package limits. When a task is subject to a rate-limit it will get the DELAYED status and will be postponed until it is allowed again. A thread will check for delayed tasks and put them on the queue when they're ready.

This will expect some changes in the katalogus mainly exposing a grouping/namespacing on which to rate limit and the parseable rate limit.

Issue link

Closes #1317

Processess

For a boefje scheduler when a task gets created it will get check whether the boefje is rate limited or not:

flowchart TD
    A[Task Creation] --> B{is_task_rate_limited}
    B -->|Yes| C[set Task to status <br>DELAYED]
    B ---->|No| E[End]
Loading

Checking if a task is rate limited:

graph TD
    A[Start] --> B{rate_limit is None?}
    B -- Yes --> C[Return False]
    B -- No --> D{Try to parse rate_limit}
    D --> E{parsed_rate_limit is None?}
    E -- Yes --> F[Raise ValueError]
    E -- No --> G[Lock rate_limiter]
    G --> H[Get identifier_template]
    H --> I[Render identifier from template]
    I --> J[Test rate_limiter with identifier]
    J --> K{can_consume?}
    K -- No --> L[Return True]
    K -- Yes --> M{hit?}
    M -- Yes --> N[Hit rate_limiter]
    N --> O[Return False]
    M -- No --> O
    D --> P[Caught ValueError]
    P --> Q[Log warning]
    Q --> R[Raise exc]
Loading

Within the boefje scheduler a new process (push_tasks_for_delayed_tasks) is running next to:

  • check for scan profile changes
  • check for enabled boefjes
  • check for rescheduling (random ooi endpoint octopoes)

This push_tasks_for_delayed_tasks method gets all tasks that have the status of DELAYED. And will be checked whether or not task can be pushed onto the queue.

* main:
  Fix robot test (#1420)
  Use the correct clearance level variable in organization member list template (#1427)
  Fix translation in Debian package (#1432)
  Reschedule tasks when no results in bytes are found after grace period (#1410)
  Don't scan hostname nmap in nmap boefje (#1415)
  Add and use our own CVE API (#1383)
  Add `task_id` as a query parameter to the `GET /origins` endpoint (#1414)
  Remove member group checks and check for permission instead (#1275)
  Bump cryptography from 41.0.0 to 41.0.2 in /boefjes/boefjes/plugins/kat_ssl_certificates (#1396)
  Bump cryptography from 41.0.1 to 41.0.2 in /bytes (#1397)
  Build the Debian build image on the main branch (#1387)
  Add explicit `black` config to all modules (#1395)
  Fix <no title> in the user guide docs (#1391)
  Add configurable octpoes request timeout (#1382)
  Remove hardcoded clearance level in member list for superusers (#1390)
  Add Debian build depends for CVE API package (#1384)
  Add buttons to manual rerun tasks, both boefjes or normalizers (#1339)
  Use fix multiprocessing bug on macOS where `qsize()` is not implemented (#1374)
* main:
  Create new filters for findings  (#1293)
  Add Question OOI form rendering on the object detail page (#1408)
  Upgrade certifi (#1462)
  Default scan level filter to 0 (#1463)
  Remove some unused config options, and set better defaults for others (#1428)
  Remove unnecessary dependency on ipaddress package (#1448)
  Translations for release 1.11 - EN -> NL, PAP (#1439)
* main:
  Add sectxt dependency (#1610)
  Refactor environment settings, names, and documentation (#1517)
  Add pipeline to check if there are new translation strings (#1606)
  Translations update from Hosted Weblate (#1604)
  Update scheduler documentation (#1476)
  Add community install/update scripts (#1309)
  Bump actions/checkout from 1 to 3 (#1598)
  Run docker-compose pull in make pull (#1585)
  Configure github actions in dependabot (#1594)
  fix many ports open normalizer (#1592)
  Fix human-readable name for ImageMetadata (#1558)
  Upgrade FastAPI (#1576)
  OOI Detail page: Remember page position after clicking the "show inheritance" link (#1590)
  Fix `rstcheck` hook (#1584)
@jpbruinsslot jpbruinsslot self-assigned this Aug 14, 2023
@jpbruinsslot jpbruinsslot added the mula Issues related to the scheduler label Aug 14, 2023
@jpbruinsslot jpbruinsslot marked this pull request as ready for review August 15, 2023 08:02
@jpbruinsslot jpbruinsslot requested a review from a team as a code owner August 15, 2023 08:02
@jpbruinsslot
Copy link
Contributor Author

jpbruinsslot commented Aug 15, 2023

@ammar92 I've implemented cross-organisational support would you mind taking a look?

@praseodym
Copy link
Contributor

Originally posted at #1413 (review), but still valid:

As far as I understand, the rate limiter is a property of the BoefjeScheduler class. This class has a separate rate_limiter instance per organisation, which means that rate limiting only works per organisation.

In larger deployments, API keys such as for Shodan will likely be shared by multiple KAT organisations. How do we implement rate limiting for that scenario?

@jpbruinsslot
Copy link
Contributor Author

Originally posted at #1413 (review), but still valid:

As far as I understand, the rate limiter is a property of the BoefjeScheduler class. This class has a separate rate_limiter instance per organisation, which means that rate limiting only works per organisation.

In larger deployments, API keys such as for Shodan will likely be shared by multiple KAT organisations. How do we implement rate limiting for that scenario?

I've updated the code so that the rate limiter memory is now on the application level. The identifier of the rate limiter can then be formatted with a key for instance so that it will be shared across multiple organisations.

* main:
  Use 127.0.0.1 for RabbitMQ in install script (#1644)
  Remove environment variables from container docs (#1645)
  Feature/report generation timeout (#1640)
  Add reverse DNS boefje (#1579)
  Add first version of new normalisers runner design (#1538)
  Fix `poetry-dependencies` target in Makefile (#1627)
  Upgrade OpenTelemetry (#1626)
  Remove finding types from rocky/OOI_database_seed.json (#1619)
  Feature: Add task detail pages and show objects yielded by normalizer (#1506)
  Update django-admin-auto-tests (#1617)
  Update GitHub Actions (#1618)
  Updated cryptography (#1615)
  Improve filter by muted findings on findings page (#1595)
  Redteamer can now acknowledge clearance level during onboarding (#1549)
  Do not add line information in `.po` files (#1616)
  Add TLS Cipher checks (#1381)
@jpbruinsslot jpbruinsslot marked this pull request as draft September 11, 2023 07:27
@underdarknl
Copy link
Contributor

In larger deployments, API keys such as for Shodan will likely be shared by multiple KAT organisations. How do we implement rate limiting for that scenario?

This also means that we should probably include both 'shodan' and the actual key in the 'group' to make sure we don't limit shodan requests across the whole install even though we might have multiple keys available.

# Get the identifier for the rate limiter
identifier_template = rate_limit.identifier
environment = Environment(loader=BaseLoader())
identifier = environment.from_string(identifier_template).render(task=task)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like using Jinja here is probably too much of a good thing. Woudn't fstring be more than capable enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the main reason was to give more flexibility to the user to construct a rate limit identifier that can use the information embedded in the task.

@ammar92 am I correct in that assumption?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mula Issues related to the scheduler
Projects
Status: Incoming features / Need assessment
Development

Successfully merging this pull request may close these issues.

Create rate limiting functionality [mula] Rate limiting by interval and grouper as set in boefje manifest.
4 participants