Skip to main content

2 posts tagged with "open-source"

View All Tags

ยท 6 min read

More than two months ago, we argued the decision to close MutableSecurity. We described how MutableSecurity's journey looked like and highlighted the plans for the following period: open-sourcing the codebase and archiving/deleting MutableSecurity's assets on the Internet (repositories, packages, etc.).

As a follow-up, the purpose of this post is to describe the software architecture that we wanted to achieve for our commercial product. In addition, it will list the steps executed for the project's retirement, which could represent a model for other closed-source software initiatives that reached this stage.

Desired Software Architectureโ€‹

The outcome of our commercial product was to deliver a way to remotely manage and monitor the security solutions installed on the organization's hosts. The following sections will describe each element of the architecture.

Desired Architecture

Cybersecurity Solutions' Automation with Target Agentsโ€‹

The target agents are Python 3 wrappers for the open-source package, mutablesecurity. To give visibility and control to the web dashboard, the administrator installs agents on each server that needs to be managed by MutableSecurity.

The functionality consists of the following steps:

  1. Parses the configuration file that contains information such as:
    • API key to authenticate to the orchestration agent;
    • The address and port of the orchestration agent; and
    • The reporting period, in seconds.
  2. Connects to the orchestration agent and authenticates itself using the provided API key.
  3. Sets a ticker depending on the reporting period and execute, at each tick, the following operations:
    1. Deduces what cybersecurity solutions are installed on the server.
    2. For each solution, extracts the specific information and executes the tests.
    3. Combines the resulting information into a single data structure.
    4. Sends the generated data to the orchestration agent via HTTPS.
๐Ÿ”—Open-source Reference
The source code of this component is available here.

Data Aggregation with Orchestration Agentsโ€‹

The orchestration agent is the aggregation service, built with Python 3. All target agents in the current network will connect to this type of agent. In this manner, it will be the single point in the reporting infrastructure with an Internet connection.

The operations that it executes are:

  1. Parses the configuration file that contains information such as:
    • Bind address and port, where it will listen; and
    • Credentials to authenticate to Firebase.
  2. Processes a host file, which contains, for each target agent which is allowed a connection, the following information:
    • An API key that needs to be presented by the agent on each connection;
    • A unique identifier; and
    • A description of the agent.
  3. Authenticates to Firebase using the credentials from the configuration.
  4. Sets up an HTTPS server to let the target agents connect.
  5. Whenever a legitimate agent connects, store the reported information in the user-specific section of the database.

The host files mentioned above could be modified either manually or with a standalone script.

๐Ÿ”—Open-source Reference
The source code of this component is available here.

Storage with Firebaseโ€‹

Firebase is used to store the reported data in a resilient cloud environment. Its non-structural aspect provides a malleability that is not present for structural (for example, SQL-backed) ones. This approach avoids issues imposed by fixed structures, but comes with an additional responsibility to ensure data's correctness.

In addition, we created access control lists in Firebase such that a user can write only to its allocated partition.

Data Visualization with Dashโ€‹

The visualization element in the distributed architecture is a web dashboard. Dash is built with React.js and Chakra UI. In the first iteration, it queries data from Firebase to:

  • Show overview statistics about the security architecture;
  • List the installed agents;
  • List the automated solutions; and
  • Monitor the details (configuration, metrics, and tests) of the automated solutions.

๐Ÿ”—Open-source Reference
The source code of this component is available here.

Alerting with Google Cloud Functionsโ€‹

Another functional requirement of the architecture was alerting the administrators when certain events occur:

  • Failed tests: Consider a scenario in which we've used MutableSecurity to install Suricata in the IDS mode. If the test checking the Suricata process fails, then the IDS no longer processes traffic and generates security alerts. This issue permits attackers to benefit from the lack of network analysis and visibility. Thereby, the administrator should be alerted as he needs to manually analyze why this happened and restore its functioning.
  • Configuration change: In the same scenario, an attacker with access to the IDS may disable the automatic updates. Although the community feeds will publish IOCs (hashes, IP addresses, etc.) describing the attacker's behavior, the IDS will not be able to retrieve them. Thereby, the administrator should be noticed of any configuration change of the security solutions, despite the cases in which he makes the changes.

Failed Test Email

Configuration Change Email

The alerting infrastructure consists of a Google Cloud function that is executed every time data is reported by an agent. If failed tests or configuration changes are detected, then an email is sent via SendGrid, having the above dynamic templates.

๐Ÿ”—Open-source Reference
The source code of this component is available here.

Periodically Deleting Data with Google Cloud Functionsโ€‹

The last element of the architecture is a Google Cloud function, whose sole purpose is to periodically delete old data from Firebase. The configuration provides the retention period.

๐Ÿ”—Open-source Reference
The source code of this component is available here.

Retirement Checklistโ€‹

  • Closing the issues and pull requests
  • Deleting the accounts related to the project
  • Revoking the access of third-party apps to the organization
  • Checking the repositories with Gitleaks such that no active API key is disclosed
  • Adding LICENSE.md and README.md files to all repositories
  • Archiving all repositories
  • Adding a banner to the website to mark the project as discontinued

Account Deletionโ€‹

The second step in the previous checklist involved, in our case, the deletion of:

  • PyPi;
  • DeepSource;
  • Google Cloud Platform, including Firebase; and
  • SendGrid accounts.

This automatically ensures that:

  • The API keys will be destroyed. Even though they will become public in the open-source code, they cannot be used anymore.
  • The packages cannot be downloaded anymore with pip install mutablesecurity.

Conclusionโ€‹

This wrap-up blog post described, from a technical perspective, how the retirement process looked like for MutableSecurity. This involved the publishing in the open-source of multiple repositories that were previously accessible only by the team members.

With this information in mind, the blog post is the last one in MutableSecurity's lifespan. With the previous thanks in mind, we want to end by hoping the information presented in this post and blog was helpful.

See you next time!

ยท 7 min read

This blog post will explain the approach we used in MutableSecurity to add minimal, non-intrusive application monitoring, for both crash reporting and usage monitoring. Despite the examples from our codebase, that is mostly Python-based, the principles used may be applied with ease to other programming languages.

Why Metrics are Importantโ€‹

The quote โ€œWhat gets measured gets improvedโ€ is mostly used to highlight the importance of having quantitative measures of performance about a system. Whether it was said by the influential management consultant Peter Drunker back in the previous century, there are some situations in which these numeric metrics help us to better understand a system's functioning. In the software field, examples may be finding out how many users you have, how they use your program and how the product behaves regarding performance.

In addition, there may be another piece of the puzzle left: the survivorship bias. Simply said, history is written by the victorious. Applied to the software industry, we can say that we tend to judge the overall experience of our products by interacting with the users or customers (via feedback forms, interviews, etc.) that are active today, not those who abandoned the journey due to encountered issues (for example, bad UX practices, bugs and errors). But we may learn about the latter category by implementing passive feedback loops.

Feedback Loopsโ€‹

For open source projects, we can have multiple places from which we can learn from and about our users.

There are active forms, in which the user can deliberately contact the project's developers to share an impression, request a feature, or report a security problem. They can create GitHub issues or, more privately, contact us through in-app forms or emailing to our addresses.

On the other hand, we have passive data collection. The user interacts as normal with the application, but he deliberately allows the collection of usage data: which UI elements he interacted with, difficulty of finding out a desired page and so on.

We can consider the app stores downloads too, but they are too opaque. For example, we could not know if the software downloaded through GitHub or PyPi (a Python package repository) was actually run. Or if the user only downloaded it, but found it hard to understand the workflow. To consolidate this argument, think about the Python ecosystem: bots (like Snyk's ones) are scanning the published packages in order to find vulnerabilities.

The Privacy Dilemmaโ€‹

But there's the catch 22: as software developers, we need to think profoundly about the privacy of our users. We can't collect all possible data. In the past years, due to many privacy issues events such as keylogging social media platforms and huge data leaks, people got more conscious about what data are collected by companies and how they are used afterwards. It can be said, for sure, that the trust of users was damaged.

Our Approach for Application Monitoringโ€‹

To give a bit of context, we created a platform to automatically deploy and manage cybersecurity solutions. At the first step, we published on GitHub a CLI tool to achieve these goals. The hardest part, now, is to determine what happens next after the download from PyPi is complete. Does the user deploy a specific solution? Or does he encounter an error and uses the software only once?

We reached a solution to these issues. We implemented a minimal, non-intrusive application monitoring system for MutableSecurity:

  1. Collecting usage data with Firebase Realtime Database and a serverless function, deployed on Google's cloud (Google Cloud Platform or simply GCP)
  2. Integrating an error tracking platform, Sentry
  3. Giving the user a method to opt out
  4. Documenting the whole monitoring process.

The following sections will describe each of them with a bird's eye view. All of them are exemplified with Python snippets from our codebase and screenshots.

Usage Monitoringโ€‹

  1. Collect the data: We implemented a base abstract class named Metric. Each collected metric should inherit it and overwrite the IDENTIFIER member (that defines the key used to identify the information when placed in Firebase) and the _get method (that extracts the information from the current host). When a new metric is defined, the __init_subclass__ method is used to automatically register it (by storing a reference in a list) in the DataCollector class, that deals with collecting all the metrics values.
  1. Send the collected data: The Monitor class is then used to retrieve all the metric values and POST them to our serverless function.
  1. Retrieve the data and store it inside Firebase: The serverless function from Google Cloud Platform is configured to run in a Python environment, with a secret that is used to store the service account's private key. It only takes the data from the HTTP request and stores it inside Firebase Realtime Database with the pyrebase4 package.
  1. Check Firebase for the collected usage data: In our case, the data looks similar to the screenshot below.

    Data stored in Firebase

Crash Reportingโ€‹

  1. Add the SDK: After setting up an account, install the Sentry SDK for Python, sentry_sdk.
  2. Initialize the SDK: In the source code, call the init method of Sentry's SDK.
  1. Trigger a crash: Just place a division by zero (for example, 1/0) operation between some lines of code that are certainly executed. Be sure to remove it afterwards.

  2. Find the crash in Sentry's dashboard: Sentry should list the triggered error. Alongside it, there are further details such as stack traces and runtime information.

    Sentry crash

    Sentry stacktrace

Opting Outโ€‹

Implements a logic to let the user opt out of the monitoring data. This can be achieved by adding a new aspect in the configuration. In MutableSecurity, we skip the logic presented in the Usage Monitoring section if the user sets a field in the configuration file.

Be Transparent Regarding the Monitoringโ€‹

If you have read everything until this point, you are conscious about the benefits some data may have. Namely, to learn more about the users you want to help with your software. As the software user - developer relationship is one of a partnership, the main principle is trust, and it needs to be built and maintained. Also, it needs to be transparent about:

  1. Why you collect metrics at all?
  2. What metrics you collect?
  3. If a user wants to see the implementation, what files from your codebase are relevant?
  4. How can you opt out of sending any usage/crash data?

These questions may be answered with a page of your documentation or as a separate view inside your production software. You can see examples on Homebrew's and MutableSecurity's websites.

Conclusionsโ€‹

Having feedback loops is important for a software developer. The data may shift the focus from some functionality considered relevant to others that are actually used in the wild. This blog post explained the reasoning behind collecting data, some handy principles to keep in mind, and a Python implementation we developed for MutableSecurity. For further information about the development in the open source community (including metrics), I recommend following the GitHub's articles on opensource.guide.

Until next time!