Cloudmarker¶
Cloudmarker is a cloud monitoring tool and framework.
Contents¶
Table of Contents:
What is Cloudmarker?¶
Cloudmarker is a cloud monitoring tool and framework. It can be used as a ready-made tool that audits your Azure or GCP cloud environments as well as a framework that allows you to develop your own cloud monitoring software to audit your clouds.
As a monitoring tool, it performs the following actions:
- Retrieves data about each configured cloud using the cloud APIs.
- Saves or indexes the retrieved data into each configured storage system or indexing engine.
- Analyzes the data for potential issues and generates events that represent the detected issues.
- Saves the events to configured storage or indexing engines as well as sends the events as alerts to alerting destinations.
Each of the above four aspects of the tool can be configured via a configuration file.
For example, the tool can be configured to pull data from Azure and index its data in Elasticsearch while it also pulls data from GCP and indexes the GCP data in MongoDB. Similarly, it is possible to configure the tool to check for unencrypted disks in Azure, generate events for it, and send them as alerts by email while it checks for insecure firewall rules in both Azure and GCP, generate events for them, and save those events in MongoDB.
This degree of flexibility to configure audits for different clouds in different ways comes from the fact that Cloudmarker is designed as a combination of lightweight framework and a bunch of plugins that do the heavylifting for retrieving cloud data, storing the data, analyzing the data, generating events, and sending alerts. These four types of plugins are formally known as cloud plugins, store plugins, event plugins, and alert plugins, respectively.
As a result of this plugin-based architecture, Cloudmarker can also be used as a framework to develop your own plugins that extend its capabilities by adding support for new types of clouds or data sources, storage or indexing engines, event generation, and alerting destinations.
Why Cloudmarker?¶
One might wonder why we need a new project like this when similar projects exist. When we began working on this project in 2017, we were aware of similar tools that supported AWS and GCP but none that supported Azure at that time. As a result, we wrote our own tool to support Azure. We later added support for GCP as well. What began as a tiny proof of concept gradually turned into a fair amount of code, so we thought, we might as well share this project online, so that others could use it and see if they find value in it.
So far, some of the highlights of this project are:
- It is simple. It is easy to understand how to use the four types of plugins (clouds, stores, events, and alerts) to perform an audit.
- It is excellent at creating an inventory of the cloud environment.
- The data inventory it creates is easy to query.
- It is good at detecting insecure firewall rules and unencrypted disks. New detection mechanisms are coming up.
We also realize that we can add a lot more functionality to this project to make it more powerful too. See the Wishlist section below to see new features we would like to see in this project. Our project is hosted on GitHub at https://github.com/cloudmarker/cloudmarker. Contributions and pull requests are welcome.
We hope that you would give this project a shot, see if it addresses your needs, and provide us some feedback by posting a comment in our feedback thread or by creating a new issue.
Features¶
Since Cloudmarker is not just a tool but also a framework, a lot of its functionality can be extended by writing plugins. However, Cloudmarker also comes bundled with a default set of plugins that can be used as is without writing a single line of code. Here is a brief overview of the features that come bundled with Cloudmarker:
- Perform scheduled or ad hoc audits of cloud environment.
- Retrieve data from Azure and GCP.
- Store or index retrieved data in Elasticsearch, MongoDB, Splunk, and the file system.
- Look for insecure firewall rules and generate firewall rule events.
- Look for unencrypted disks (Azure only) and generate events.
- Send alerts for events via email and Slack as well as save alerts in one of the supported storage or indexing engines (see the third point above).
- Normalize firewall rules from Azure and GCP which are in different
formats to a common object model (
"com"
) so that a single query or event rule can search for or detect issues in firewall rules from both clouds.
Wishlist¶
- Add more event plugins to detect different types of insecure configuration.
- Normalize other types of data into a common object model (
"com"
) just like we do right now for firewall rules.
Install¶
Perform the following steps to set up Cloudmarker.
Create a virtual Python environment and install Cloudmarker in it:
python3 -m venv venv . venv/bin/activate pip3 install cloudmarker
Run sanity test:
cloudmarker -n
The above command runs a mock audit with mock plugins that generate some mock data. The mock data generated can be found at
/tmp/cloudmarker/
. Logs from the tool are written to the standard output as well as to/tmp/cloudmarker.log
.The
-n
or--now
option tells Cloudmarker to run right now instead of waiting for a scheduled run.
To learn how to configure and use Cloudmarker with Azure or GCP clouds, see Cloudmarker Tutorial.
Develop¶
This section describes how to set up a development environment for Cloudmarker. This section is useful for those who would like to contribute to Cloudmarker or run Cloudmarker directly from its source.
We use primarily three tools to perform development on this project: Python 3, Git, and Make. Your system may already have these tools. But if not, here are some brief instructions on how they can be installed.
On macOS, if you have Homebrew installed, then these tools can be be installed easily with the following command:
brew install python git
On a Debian GNU/Linux system or in another Debian-based Linux distribution, they can be installed with the following commands:
apt-get update apt-get install python3 python3-venv git make
On a CentOS Linux distribution, they can be installed with these commands:
yum install centos-release-scl yum install git make rh-python36 scl enable rh-python36 bash
Note: The
scl enable
command starts a new shell for you to use Python 3.On any other system, we hope you can figure out how to install these tools yourself.
Clone the project repository and enter its top-level directory:
git clone https://github.com/cloudmarker/cloudmarker.git cd cloudmarker
Create a virtual Python environment for development purpose:
make venv deps
This creates a virtual Python environment at
~/.venv/cloudmarker
. Additionally, it also creates a convenience script namedvenv
in the current directory to easily activate the virtual Python environment which we will soon see in the next point.To undo this step at anytime in future, i.e., delete the virtual Python environment directory, either enter
rm -rf venv ~/.venv/cloudmarker
or entermake rmvenv
.Activate the virtual Python environment:
. ./venv
In the top-level directory of the project, enter this command:
python3 -m cloudmarker -n
This generates mock data at
/tmp/cloudmarker
. This step serves as a sanity check that ensures that the development environment is correctly set up and that the Cloudmarker audit framework is running properly.Now that the project is set up correctly, you can create a
cloudmarker.yaml
to configure Cloudmarker to scan/audit your cloud or you can perform more development on the Cloudmarker source code. See Cloudmarker Tutorial for more details.If you have set up a development environment to perform more development on Cloudmarker, please consider sending a pull request to us if you think your development work would be useful to the community.
Before sending a pull request, please run the unit tests, code coverage, linters, and document generator to ensure that no existing test has been broken and the pull request adheres to our coding conventions:
make test make coverage make lint make docs
To run these four targets in one shot, enter this “shortcut” target:
make checks
Open
htmlcov/index.html
with a web browser to view the code coverage report.Open
docs/_build/html/index.html
with a web browser to view the generated documentation.
Resources¶
Here is a list of useful links about this project:
Support¶
To report bugs, suggest improvements, or ask questions, please create a new issue at http://github.com/cloudmarker/cloudmarker/issues.
License¶
This is free software. You are permitted to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of it, under the terms of the MIT License. See LICENSE.rst for the complete license.
This software is provided WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.rst for the complete disclaimer.
Tutorial¶
Cloudmarker Tutorial¶
Cloudmarker is a cloud monitoring tool and framework.
Install¶
Create a virtual Python environment and install Cloudmarker in it:
python3 -m venv venv . venv/bin/activate pip3 install cloudmarker
Run sanity test:
cloudmarker -n
The above command runs a mock audit with mock plugins that generate some mock data. The mock data generated can be found at
/tmp/cloudmarker/
. Logs from the tool are written to the standard output as well as to/tmp/cloudmarker.log
.The
-n
or--now
option tells Cloudmarker to run right now instead of waiting for a scheduled run.
Get Started¶
Cloudmarker’s behaviour is driven by configuration files written in
YAML format. Cloudmarker comes
with two built-in mock plugins known as MockCloud
and MockEvent
.
These mock plugins are useful in generating some mock data to test out
the Cloudmarker framework and familiarize oneself with how Cloudmarker
can be configured.
We will first see how to configure the MockCloud
plugin, just so
that we can quickly get started with understanding the configuration
file format without having to work out how to provide Cloudmarker access
to real clouds. We will see how to work with real clouds later in this
document. Follow these steps to get started:
Create a config file named
cloudmarker.yaml
in the current directory with the following content:plugins: mymockcloud: plugin: cloudmarker.clouds.mockcloud.MockCloud params: record_count: 5 record_types: - apple - ball - cat audits: mymockaudit: clouds: - mymockcloud stores: - filestore events: - mockevent alerts: - filestore run: - mymockaudit
Enter this command to run Cloudmarker:
cloudmarker -n
Examine the output in
/tmp/cloudmarker/mymockaudit_mymockcloud.json
. It should contain a JSON array with 5 objects as defined in therecord_count
value in the config. There arerecord_type
fields in these objects that cycle between the values"apple"
,"ball"
, and"cat"
as defined in therecord_types
value in the config. The data we see in this output file is generated by thecloudmarker.clouds.mockcloud.MockCloud
plugin defined under themymockcloud
config key.Now examine the output in
/tmp/cloudmarker/mymockaudit_mockevent
. It should contain a JSON array with 2 objects. This data is generated by thecloudmarker.clouds.mockcloud.MockEvent
plugin referred to asmockevent
. Themockevent
config key is defined in the built-in base config.Note that the mock audit files written at
/tmp/cloudmarker/
have names that are composed of audit key name, underscore, and plugin key name. These files are written by thecloudmarker.clouds.filestore.FileStore
plugin which is specified in the config asfilestore
. Thefilestore
config key is defined in the built-in base config.
Configuration Format¶
Let us take a closer look at the config file format in the previous section:
plugins:
mymockcloud:
plugin: cloudmarker.clouds.mockcloud.MockCloud
params:
record_count: 5
record_types:
- apple
- ball
- cat
audits:
mymockaudit:
clouds:
- mymockcloud
stores:
- filestore
events:
- mockevent
alerts:
- filestore
run:
- mymockaudit
There are three top-level config keys: plugins
, audits
, and
run
. These top-level keys and their values are input to the
Cloudmarker framework. They tell the framework what to do. Let us see
each top-level key in more detail.
plugins¶
The plugins
key defines one or more plugin configs. In the above
example, we have defined only one plugin config for the
cloudmarker.clouds.mockcloud.MockCloud
plugin. A plugin is a
Python class that implements a few methods required by the Cloudmarker
framework. In this case, the MockCloud
plugin has the code to
generate some mock data for the purpose of testing other plugins.
Under the plugins
key, we have one or more user-defined keys that
name our plugin configs. In this example, we have defined one plugin
config and chosen that name mymockcloud
for it. We could name this
anything. This name appears in the logs, so it is good to name this
meaningfully.
Under the user-defined key for a plugin, there are at most two keys:
plugin
: Its value is the fully qualified class name of the plugin class.params
: Its value is a mapping of key-value pairs that specify the keyword arguments to pass to the plugin class constructor expression. For example, see the API documentation ofMockCloud
by clicking on this link:cloudmarker.clouds.mockcloud.MockCloud
. We can see that the config key namesrecord_count
andrecord_types
under the theparams
config key match the parameter names of theMockCloud
plugin.
audits¶
The audits
key defines one or more audit configs. In the above
example, we have defined only one audit config to generate mock data
using the plugin defined under the mymockcloud
config key earlier.
Under the audits
key, we have one or more user-defined keys that
name our audit configs. In this example, we have defined one audit
config named key mymockaudit
. This name appears in the logs, so it
is good to name this meaningfully.
Under the user-defined key for an audit, there are four keys:
clouds
: Its value is a list of config keys defined under theplugins
key. Each key should refer to a cloud plugin.stores
: Its value is a list of config keys defined under theplugins
key. Each key should refer to a store plugin.events
: Its value is a list of config keys defined under theplugins
key. Each key should refer to an event plugin.alerts
: Its value is a list of config keys defined under theplugins
key. Each key should refer to a store or alert plugin.
The Cloudmarker framework instantiates all the plugins in an audit and then lets the cloud plugins generate cloud records. Within an audit, records generated by each cloud plugin are then fed to each store and event plugin configured in the same audit.
Each cloud plugin generates data, typically, by connecting to a cloud and pulling cloud data related to resources configured in the cloud. Each cloud plugin emits this data in Python dictionary formats (appears as JSON when written to files or a storage/indexing system that can store JSON documents). We call each such dictionary object (or JSON document) as a record.
Each event plugin then receives the data generated by the cloud plugins configured within the same audit. An event plugin checks each record for security issues or some pattern. If a security issue is found in some record or if the pattern being checked for is found, then the event plugins generate one or more events for it. These events are fed to each alert plugin in the same audit.
Each store plugin takes the data fed to it and sends it to the store destination. A store destination is typically a storage or indexing engine such as Elasticsearch, Splunk, etc.
Each alert plugin takes events fed to it and sends the events to an
alerting destination. A store plugin can also function as an alert
plugin and vice-versa. From the framework’s perspective, there is no
difference between store and alert plugin classes because they
implemented the same methods. The only difference is that the store
plugins are mentioned under the stores
key in an audit config and
the alert plugins are mentioned under the alerts
key in an audit
config. However, some alert plugins such as the ones to send events as
email alerts or Slack messages make sense only as alert plugins and not
as store plugins. That’s because we wouldn’t want to email the entire
cloud data to email recipients or Slack users but we might want to email
just the events as notifications to email recipients or Slack users.
run¶
Finally, the run
key defines the audits we want to run. Its value is
a list of one or more user-defined audit keys.
Base Configuration¶
In the above examples, we defined mymockcloud
under the plugins
key but we did not define filestore
or mockevent
although we
used them under the audits
key. That’s because they are already
defined in the built-in base config. Enter this command to see the
built-in base config:
cloudmarker --print-base-config
Alternatively, see the complete built-in base config here:
cloudmarker.baseconfig
.
The config in cloudmarker.yaml
or any other user-specified config
files is merged with the built-in base config to arrive at the final
working config. The merging rules are described in the next section.
Cascading Configuration¶
By default, Cloudmarker looks for the following config files in the order specified:
/etc/cloudmarker.yaml
~/.cloudmarker.yaml
~/cloudmarker.yaml
cloudmarker.yaml
Note that the built-in base config is always used. If a config file in the list above is missing, it is ignored. If all config files in the list above are missing, then only the built-in base config is used.
If one or more config files are present, they are merged together with the built-in base config to arrive at the final working config. The built-in base config is loaded first. Then the config files are loaded and merged in the order specified in the list above. A config that is loaded later has higher precedence in case of conflicting values for the same key.
A custom list of config files to look for can be specified with the
-c
or --config
option. For example, the following command first
loads the built-in base config, then foo.yaml
from the current
directory, and then bar.yaml
from the current directory:
cloudmarker -n -c foo.yaml bar.yaml
It means that in case of conflicting values for the key, the
builtin-base config has the lowest priority and bar.yaml
has the
highest priority.
Here is a precise specification of how two configs are merged:
- If a key in the first config does not exist in the second config, then the final config contains this key with its value intact.
- If a key in the second config does not exist in the first config, then the final config contains this key with its value intact.
- If a key in the first config also exists in the second config, then the final config contains this key and its value is the value found in the second config.
This means, if a key with a list value exists in the first config and the same key with another list value exists in the second config, then the final config is the key with the list value in the second config. The final config does not contain the key with both lists merged together as its value.
For example, let us assume that foo.yaml
contains this key:
run:
- mockaudit
- fooaudit
And bar.yaml
contains this key:
run:
- baraudit
Then cloudmarker -n -c foo.yaml bar.yaml
leads to the following
value for this config key:
run:
- baraudit
Note how the list value of bar.yaml
replaced the list value of
foo.yaml
while merging. In other words, when we talk about merging
of configs, only keys are merged, i.e., keys from both configs are
picked for the final working config. Values are not merged.
When there are multiple config files to be merged, the first config file is merged with the base config file, then the second config file is merged with the result of the previous merge, and so on.
Cloud Plugins¶
AzCloud¶
To get started with a real audit, it is necessary to configure
Cloudmarker with an actual cloud such as Azure or GCP. In this section,
we see how to configure Cloudmarker for Azure with the AzCloud
plugin.
This plugin is offered by the
cloudmarker.clouds.azcloud.AzCloud
plugin class.
Perform the following steps to configure this plugin:
At first follow this how-to document at https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal to register an application in Azure Active Directory to allow Cloudmarker to access your Azure resources.
After completing the above step, create a config file named
cloudmarker.yaml
in the current directory with this content:plugins: myazcloud: plugin: cloudmarker.clouds.azcloud.AzCloud params: tenant: null client: null secret: null audits: myazaudit: clouds: - myazcloud stores: - filestore events: - firewallruleevent alerts: - filestore run: - myazaudit
Then replace the
null
values fortenant
,client
, andsecret
as described below:tenant
: This is the tenant ID obtained from following the “Get tenant ID” section of the how-to document. This is also known as the directory ID. To find this value, go to Azure Portal > Azure Active Directory > Properties > Directory ID. This value is also available in the newly created application at Azure Portal > Azure Active Directory > App Registrations > (the app) > Directory (tenant) ID.client
: This is the application ID created in the “Get application ID and authentication key” section of the how-to document. This value is also available at Azure Portal > Azure Active Directory > App Registrations > (the app) > Application (client) ID.secret
: This is the secret password created in the “Get application ID and authentication key” section of the how-to document. This valuable is available only while creating a new secret at Azure Portal > Azure Active Directory > App Registrations > (the app) > New client secret.
After setting these values, enter this command to run Cloudmarker:
cloudmarker -n
After Cloudmarker completes running, check these files in
/tmp/cloudmarker/
:myazaudit_myazcloud.json
: This file contains the data obtained from Azure cloud by thecloudmarker.clouds.azcloud.AzCloud
plugin configured under themyazaudit
config key.myazaudit_firewallruleevent.json
: This file contains insecure firewall rules detected by thecloudmarker.events.firewallruleevent.FirewallRuleEvent
referred to with the key namefirewallruleevent
in the config. Note thatfirewallruleevent
config key is defined in the built-in base config.
AzVM¶
This is another plugin for Azure that has a narrower but deeper scope
than the AzCloud
plugin described in the previous section. It pulls
only virtual machine (VM) data with more details about each VM.
This plugin is offered by the cloudmarker.clouds.azvm.AzVM
plugin class.
Perform the following steps to use the AzVM
plugin:
As mentioned in the previous section, register an application in Azure Active Directory to allow Cloudmarker to access your Azure resources.
After completing the above step, create a config file named
cloudmarker.yaml
in the current directory with this content:plugins: myazvm: plugin: cloudmarker.clouds.azvm.AzVM params: tenant: f3cfe067-d008-48f3-b026-cf0dd7409b25 client: 6c4980e2-2652-466d-8157-853f9d0a288f secret: 4FAU+gYAkl96zbnlXZqu25d5iZBlDhzj0EHD8fi6HR8= audits: myazaudit: clouds: - myazvm stores: - filestore events: - firewallruleevent - azvmosdiskencryptionevent - azvmdatadiskencryptionevent alerts: - filestore run: - myazaudit
Then replace the
null
values fortenant
,client
, andsecret
with actual values as described in the previous section.After setting these values, enter this command to run Cloudmarker:
cloudmarker -n
After Cloudmarker completes running, check the generated files in
/tmp/cloudmarker/
.
Let us discuss how AzCloud
and AzVM
are different.
AzCloud
pulls data at subscription level. It first connects to Azure
with the specified credentials, then queries for all subscriptions it
has access to, and then loops over each subscription and makes one API
call per subscription per resource type to pull all resources of that
type. It pulls data related to virtual machines (VMs), application
gateways, load balancers, network interface controllers (NICs), network
security groups (NSGs), etc.
AzVM
on the other hand pulls data at the virtual machine level. It
makes one API call per VM. Thus, it makes more number of API calls. It
retrieves only VM data but it gets more detailed VM data. For example,
this plugin also obtains the power state, the disk encryption status,
etc. of the VM. These detailed level of information cannot be obtained
by the AzCloud
plugin.
To understand the difference between the two plugins better, consider an
environment where there are 5 subscriptions such that each subscription
has exactly 20 VMs and 50 NSGs. So, there are a total of 100 VMs and 250
NSGs. AzCloud
would make only 5 API calls to pull data
for all 100 VMs and another 5 API calls to pull data for all NSGs. On
the other hand, AzVM
would make 100 API calls to pull data for all
VMs. AzVM
cannot pull data for NSGs or any other type of resources.
However, the VM data obtained by AzVM
contains power state, disk
encryption status, and other detailed information. AzCloud
data does
not pull such detailed information.
In general, AzCloud
runs faster due to less number of API calls and
is usually sufficient for most types of cloud monitoring use cases.
AzVM
is necessary only for advanced use cases such as monitoring
whether a particular VM is running or stopped, if its disks are
encrypted or not, etc.
Note in the config above that event plugins
cloudmarker.events.azvmosdiskencryptionevent.AzVMOSDiskEncryptionEvent
and
cloudmarker.events.azvmdatadiskencryptionevent.AzVMDataDiskEncryptionEvent
referred to with the built-in base config keys
azvmosdiskencryptionevent
and azvmdatadiskencryptionevent
can be
used with AzVM
. These plugins work only with AzVM
records and
generates events if OS disks and data disks are found. They ignore
records generated by any other cloud plugins.
GCPCloud¶
Follow these steps to get started with auditing a GCP cloud environment.
Follow the steps at https://cloud.google.com/iam/docs/creating-managing-service-account-keys to create a service account key using the GCP Console and download it as a file named
keyfile.json
.Then create a config file name
cloudmarker.yaml
with this content:plugins: mygcpcloud: plugin: cloudmarker.clouds.gcpcloud.GCPCloud params: key_file_path: keyfile.json audits: mygcpaudit: clouds: - mygcpcloud stores: - filestore events: - firewallruleevent alerts: - filestore run: - mygcpaudit
Now enter this command to run Cloudmarker:
cloudmarker -n
Now examine these files generated by Cloudmarker at
/tmp/cloudmarker/
:mygcpaudit_mygcpcloud.json
: This file contains the data obtained from GCP cloud by thecloudmarker.clouds.gcpcloud.GCPCloud
plugin configured under themygcpaudit
config key.mygcpaudit_firewallruleevent.json
: This file contains insecure firewall rules detected by thecloudmarker.events.firewallruleevent.FirewallRuleEvent
plugin referred to with the key namefirewallruleevent
in the built-in base config.
Note that the GCPCloud
plugin audits all the projects under the
service-account for the keyfile.json
provided and also discovers
resources in all zones automatically.
MockCloud¶
The MockCloud
plugin has already been discussed in the Get
Started section once. A config key named mockcloud
already
configures this plugin in the built-in base config as follows:
plugins:
mockcloud:
plugin: cloudmarker.clouds.mockcloud.MockCloud
There are no parameters specified for this plugin in the built-in base
config because this plugin class already has default keyword parameters.
See cloudmarker.clouds.mockcloud.MockCloud
for the keyword
parameters with default values. By default, it generates 10 mock records
such that record['ext']['record_type']
alternate between 'foo'
and 'bar'
where record
represents each JSON object generated by
this plugin.
To override the default behaviour to, say, generate 20 records with
record types that alternate between ‘foo’, ‘bar’, and ‘baz’, we
could override the mockcloud
config key defined in the built-in base
config. To do so, create a file named cloudmarker.yaml
with the
following content only:
plugins:
mockcloud:
params:
record_count: 20
record_types:
- foo
- bar
- baz
Then run Cloudmarker with this command:
cloudmarker -n
Note that we did not specify the plugin
key under mockcloud
here
because that is already available in the base config (see
cloudmarker.baseconfig
). Similarly, we did not define audits
or run
config keys here because they are also defined in the base
config. We only defined what we needed to override in the base config.
Event Plugins¶
The event plugins have been discussed in the sections for cloud plugins
above. Here is how the config keys for these plugins have been defined
in the base config (see cloudmarker.baseconfig
):
plugins:
...
firewallruleevent:
plugin: cloudmarker.events.firewallruleevent.FirewallRuleEvent
azvmosdiskencryptionevent:
plugin: cloudmarker.events.azvmosdiskencryptionevent.AzVMOSDiskEncryptionEvent
azvmdatadiskencryptionevent:
plugin: cloudmarker.events.azvmdatadiskencryptionevent.AzVMDataDiskEncryptionEvent
The ellipsis (...
) in this example denote content omitted in the
above example for the sake of brevity.
FirewallRuleEvent¶
The FirewallRuleEvent
plugin can be used with both AzCloud
and
GCPCloud
plugins. It looks for firewall rules that expose sensitive
ports to the entire Internet and generates events for them.
This plugin is offered by the
cloudmarker.events.firewallruleevent.FirewallRuleEvent
plugin
class.
By default, it monitors for insecure exposure of a fixed set of TCP
ports. If that’s okay for you, there is no need to define this plugin
explicitly in the config file. The built-in base config key
firewallruleevent
can be used as is. However, if there is a need for
monitoring a custom set of ports, then it can be overridden. Here is an
example configuration that monitors for insecure exposure of ports 22
and 3389 in Azure cloud:
plugins:
myazcloud:
plugin: cloudmarker.clouds.azcloud.AzCloud
params:
tenant: null
client: null
secret: null
firewallruleevent:
params:
ports:
- 22
- 3389
audits:
myazaudit:
clouds:
- myazcloud
stores:
- filestore
events:
- firewallruleevent
alerts:
- filestore
run:
- myazaudit
Remember to replace the null
values in the config above with actual
values before using this config.
AzVMOSDiskEncryptionEvent¶
The AzVMOSDiskEncryptionEvent
plugin can be used with AzVM
plugin. It looks for unencrypted OS disks attached to Azure virtual
machines.
This plugin is offered by the
cloudmarker.events.azvmosdiskencryptionevent.AzVMOSDiskEncryptionEvent
plugin class.
An example usage of this plugin is available in the AzVM section.
Since it only checks whether disks are encrypted or not (a binary
decision), it does not accept any parameters that can be configured in
config file. Therefore, it is recommended to use the built-in base
config key named azosdiskencryptionevent
for this plugin.
AzVMDataDiskEncryptionEvent¶
The AzVMDataDiskEncryptionEvent
plugin can be used with AzVM
plugin. It looks for unencrypted data disks attached to Azure virtual
machines.
This plugin is offered by the
cloudmarker.events.azvmdatadiskencryptionevent.AzVMDataDiskEncryptionEvent
plugin class.
An example usage of this plugin is available in the AzVM section.
Since it only checks whether disks are encrypted or not (a binary
decision), it does not accept any parameters that can be configured in
config file. Therefore, it is recommended to use the built-in base
config key named azdatadiskencryptionevent
for this plugin.
MockEvent¶
The MockEvent
plugin can be used with MockCloud
plugin. The
MockCloud
plugin generates data such that record['raw']['data']
has an integer value that increments in each record where record
here
represents each record generated by MockCloud
. The MockEvent
plugin when used checks the value of record['raw']['data']
in each
input record
and generates an event if this value is a multiple of
some number (3
by default).
This plugin is offered by the
cloudmarker.events.mockevent.MockEvent
plugin class.
We use MockCloud
and MockEvent
plugins together to test out the
store and alert plugins.
In case, we want the MockEvent
plugin to look for a multiple of some
other number, say, 5
, we can override the built-in base config as
follows:
plugins:
mockevent:
params:
n: 5
Store Plugins¶
FileStore¶
We have been using the FileStore
plugin already in the examples
above. This plugin is good for quick testing because we can see the
cloud data records and events written locally to a file that we can
easily inspect.
This plugin is offered by the
cloudmarker.stores.filestore.FileStore
plugin class.
By default, it writes the output files to the /tmp/cloudmarker/
directory. Here is how it can be configured to write the output files to
another directory, say, ~/cloudmarker
:
plugins:
filestore:
params:
path: ~/cloudmarker
On running Cloudmarker with this config, we would see that the output
files have been written to ~/cloudmarker
, i.e.,
$HOME/cloudmarker
or in other words, the cloudmarker
directory
under the home directory. Yes, FileStore
performs tilde expansion
to expand a path beginning with ~
to a user’s home directory as
mentioned here: os.path.expanduser()
.
EsStore¶
The EsStore
plugin can be used to send cloud data as well as
events to an Elasticsearch cluster.
This plugin is offered by the
cloudmarker.stores.esstore.EsStore
plugin class.
In this section, we will use a Docker image of Elasticsearch to quickly get started with configuring this plugin. Here are the steps to set up a Docker container for Elasticsearch:
Enter the following command to run a Docker container with Elasticsearch instance:
docker run -p 9200:9200 -p 9300:9300 \ -e 'discovery.type=single-node' \ docker.elastic.co/elasticsearch/elasticsearch:7.0.1
Ensure that Elasticsearch is able to index documents:
curl -H 'Content-Type: application/json' \ -X PUT http://localhost:9200/foo/foo/1?pretty \ -d '{"a": "apple", "b": "ball"}'
Double-check that the document was indexed:
curl http://localhost:9200/foo/_search?pretty
Now that Elasticsearch is running in a Docker container and indexing data, configure Cloudmarker to send data and events to it with the following steps:
Create
cloudmarker.yaml
with the following content to configure Cloudmarker to send mock cloud records and mock events to Elasticsearch:audits: mockaudit: stores: - filestore - esstore alerts: - filestore - esstore
The above example is a very minimal config. It works because the
esstore
plugin config key is defined in the built-in base config and it sends data to a locally running Elasticsearch by default. Here is what a more elaborate config would look like:plugins: esstore: host: localhost port: 9200 index: cloudmarker audits: mockaudit: stores: - filestore - esstore alerts: - filestore - esstore
Run Cloudmarker:
cloudmarker -n
Confirm that mock cloud records and mock events are indexed in Elasticsearch:
curl http://localhost:9200/cloudmarker/_search?pretty
MongoDBStore¶
The MongoDBStore
plugin can be used to send cloud data as well as
events to a MongoDB collection.
This plugin is offered by the
cloudmarker.stores.mongodbstore.MongoDBStore
plugin class.
In this section, we will use a Docker image of MongoDB to quickly get started with configuring this plugin. Here are the steps to set up a Docker container for MongoDB:
Enter the following commands to run a Docker container with MongoDB instance:
docker rm mongo; docker run --name mongo -p 27017:27017 mongo
Ensure that we can insert data into MongoDB:
docker exec -it mongo mongo foo --eval 'db.bar.insert({"a": "apple"})'
Double-check that the data was inserted:
docker exec -it mongo mongo foo --eval 'db.bar.find()'
Now that MongoDB is running in a Docker container, configure Cloudmarker to send data to it with these steps:
Create
cloudmarker.yaml
with the following content to configure Cloudmarker to send mock cloud records and mock events to MongoDB:audits: mockaudit: stores: - filestore - mongodbstore alerts: - filestore - mongodbstore
The above example is a very minimal config. It works because the
mongodbstore
plugin config key is defined in the built-in base config and it sends data to a locally running MongoDB by default. Here is what a more elaborate config would look like:plugins: mongodbstore: host: localhost port: 27017 db: cloudmarker collection: cloudmarker username: null password: null audits: mockaudit: stores: - filestore - mongodbstore alerts: - filestore - mongodbstore
If the MongoDB instance requires user authentication, then the
username
andpassword
config keys should be set to the appropriate values.Run Cloudmarker:
cloudmarker -n
Confirm that mock cloud records and mock events are indexed in Elasticsearch:
docker exec -it mongo mongo cloudmarker --eval 'db.cloudmarker.find()'
SplunkHECStore¶
The SplunkHECStore
plugin can be used to send cloud data as well as
events to a Splunk HTTP Event Collector (HEC).
This plugin is offered by the
cloudmarker.stores.splunkhecstore.SplunkHECStore
plugin class.
In this section, we will use a Docker image of Splunk to quickly get started with configuring this plugin. Here are the steps to set up a Docker container for Splunk:
Enter the following command to run a Docker container with Splunk instance with HTTP Event Collector (HEC):
docker run -e 'SPLUNK_START_ARGS=--accept-license' \ -e 'SPLUNK_PASSWORD=admin123' \ -e 'SPLUNK_HEC_TOKEN=token123' \ -p 8000:8000 -p 8088:8088 splunk/splunk
Ensure that Splunk HEC is able to receive events:
curl -k https://localhost:8088/services/collector/event \ -H 'Authorization: Splunk token123' \ -d '{"event": "hello, world"}'
To double-check that Splunk received the event, visit http://localhost:8000/ with a web browser.
Then log into Splunk with username as
admin
and password as the password specified in thedocker
command in step 1 above.Click on “Search & Reporting” on the left sidebar.
In the search box, enter * (asterisk) and click the search button. One event with the string
hello, world
should appear in the result.
Now that Splunk is running in a Docker container and accepting events via HEC, configure Cloudmarker to send data and events to it with the following steps:
Create
cloudmarker.yaml
with the following content to configure Cloudmarker to send mock cloud records and mock events to Splunk:plugins: splunkstore: plugin: cloudmarker.stores.splunkhecstore.SplunkHECStore params: uri: https://localhost:8088/services/collector token: token123 index: main ca_cert: false audits: mockaudit: stores: - filestore - splunkstore
Run Cloudmarker with this configuration:
cloudmarker -n
Visit http://localhost:8000/ with a web browser.
Then log into Splunk with username as
admin
and password as the password specified in thedocker
command in step 1 above.Click on “Search & Reporting” on the left sidebar.
In the search box, enter * (asterisk) and click the search button. There should be many new events now.
In the search box, enter the following query to see the mock cloud records:
index=main com.record_type=mock
There should 10 records in the results.
In the search box, enter the following query to see the mock events:
index=main com.record_type=mock_event
There should be 4 events in the results.
In the search box, enter the following query to see the event description fields in a table format:
index=main com.record_type=mock_event | table com.description
Alert Plugins¶
All of the store plugins discussed above can also be used as alert plugins. Additionally, there are a few plugins that are specialized as alert plugins only and do not serve very well as store plugins. Only these plugins are discussed in this section.
EmailAlert¶
The EmailAlert
plugin can be used to send events to email recipients
via SMTP.
This plugin is offered by the
cloudmarker.alerts.emailalert.EmailAlert
plugin class.
The EmailAlert
parameters are same as that of the
cloudmarker.util.send_email()
function, so read its API
documentation to learn about the parameters this plugin accepts.
Perform the following steps to configure Cloudmarker to send mock events as email alerts:
Create a config file named
cloudmarker.yaml
in the current directory with the following content:plugins: emailalert: plugin: cloudmarker.alerts.emailalert.EmailAlert params: from_addr: Cloudmarker <cloudmarker@example.com> to_addrs: - user1@example.com - user2@example.com subject: Cloudmarker Alert host: smtp.example.com audits: mockaudit: alerts: - filestore - emailalert
Set the values of
from_addr
andto_addrs
appropriately.If authentication is required, add
username
andpassword
parameters. Seecloudmarker.send_email()
documentation for details.If the SMTP host does not support
SSL
, then addssl_mode
parameter and set its value tostarttls
if the SMTP host supportsSTARTTLS
. If the SMTP host supports neitherSSL
norSTARTTLS
, set its value todisable
.If the SMTP host is listening on a non-standard port, then set the
port
parameter to an integer value representing the expected port number. If the SMTP host is listening on a standard port, then there is no need to set this parameter. It has a default value of0
which automatically selects the appropriate port based on the value ofssl_mode
parameter.Run Cloudmarker with this configuration:
cloudmarker -n
Check the configured recipients’ inboxes to confirm that the email alerts have been received.
SlackAlert¶
The SlackAlert
plugin can be used to send events to Slack users via
a Slack bot.
This plugin is offered by the
cloudmarker.alerts.slackalert.SlackAlert
plugin class.
Perform the following steps to configure Cloudmarker to send mock events as alerts via Slack:
Create a config file named
cloudmarker.yaml
in the current directory with the following content:plugins: slackalert: plugin: cloudmarker.alerts.slackalert.SlackAlert params: bot_user_token: null to: - user1@example.com - user2@example.com text: Attention - Cloudmarker Alert audits: mockaudit: alerts: - filestore - slackalert
Change the value of
bot_user_token
key fromnull
to actual token of the Slack bot in the config file.Change the vlaue of
to
key from example users to actual Slack users.Now, enter this command to run Cloudmarker:
cloudmarker -n
The mock events would be sent to the configured Slack users as a JSON snippet.
Framework¶
Schedule¶
In the built-in base config (see cloudmarker.baseconfig
),
there is a schedule
config key that specifies the local time (in
24-hour notation) at which Cloudmarker should start running audits every
day. This schedule is honoured when Cloudmarker is run without the
-n
or -now
option as follows:
cloudmarker
Logger¶
In the built-in base config (see cloudmarker.baseconfig
),
there is a logger
config key that specifies an elaborate logging
configuration. This can be overridden in a config file to customize the
logger. For example, by default, the log files are written to
/tmp/cloudmarker.log
. If we want to override this location to, say,
log/cloudmarker.log
, we can define a config file named
cloudmarker.yaml
like this:
logger:
handlers:
file:
filename: log/cloudmarker.log
To test this configuration, enter these commands:
mkdir -p log
cloudmarker -n
cat log/cloudmarker.log
To see the default logger
config, see cloudmarker.baseconfig
.
To understand more about what each of the config keys under logger
mean, see the Python standard library logging documentation:
Configuration dictionary schema.
Email¶
When Cloudmarker is made to run in scheduled mode, it could be useful to
get email notifications about when the audits start and the audits stop.
The email configuration for such audit emails can be specified under a
config key named email
. Note that this should be a top-level key in
the config file, i.e., it should be at the same level as the audits
and run
keys.
The value for the email
config key should be similar to the value of
params
key of an email alert. See EmailAlert section for more
details on this. Here is an example:
emailalert:
from_addr: Cloudmarker <cloudmarker@example.com>
to_addrs:
- user1@example.com
- user2@example.com
subject: Cloudmarker Alert
host: smtp.example.com
With this configuration, Cloudmarker sends four types of emails:
- An email when all configured audits begin.
- An email when all configured audits end.
- An email when each configured audit begins.
- An email when each configured audit ends.
Therefore, if there are 3 audits configured under the audits
config key, then a total of 8 emails are sent: 1 begin audits email, 1
end audits email, 3 begin audit emails (one for each audit), and 3 end
audit emails (one for each audit).
API¶
Cloudmarker API¶
cloudmarker package¶
Cloudmarker - Cloud security monitoring framework.
Subpackages¶
cloudmarker.alerts package¶
A package for alert plugins packaged with this project.
This package contains alert plugins that are packaged as part of this
project. The alert plugins implement a function named write()
that
accepts input records and typically sends them to an alerting
destination. The alert plugins also implement a function named done
that perform cleanup work when called.
Note that the alert plugins implement the exact same interface as the
store plugins in the cloudmarker.stores
package. So a store
plugin can usually serve equally well as an alert plugin, and vice
versa. In fact, some of the store plugins such as
cloudmarker.stores.esstore.EsStore
and
cloudmarker.stores.mongodbstore.MongoDBStore
are indeed used as
alert plugins too because security events can be alerted by storing them
in an Elasticsearch index or MongoDB collection.
If a plugin can serve as both a store plugin and an alert plugin, we
keep them in the cloudmarker.stores
package. If a plugin makes
sense only as an alert plugin, we keep them in this
cloudmarker.alerts
package.
Email alert plugin.
-
class
cloudmarker.alerts.emailalert.
EmailAlert
(**kwargs)¶ Bases:
object
A plugin to send email alerts.
Create an instance of
EmailAlert
plugin.This class accepts the same arguments as
cloudmarker.util.send_email()
.The
content
argument is not honoured. Even if acontent
argument is provided, it is ignored by this class because this class defines its own content from the event records it receives in itswrite()
method.-
done
()¶ Send the buffered events as an email alert.
-
Alerter to send Slack messages for identified anomalies.
-
class
cloudmarker.alerts.slackalert.
SlackAlert
(bot_user_token, to, text, temp_file='/tmp/cloudmarker/slackalert.json')¶ Bases:
object
Alert plugin to send Slack alerts.
Initialize the class:SlackAlert.
Parameters: - bot_user_token (string) – Token for Slack bot user.
- to (list) – List of recipients (string) to send Slack alert to.
- text (string) – Message body.
- temp_file (string) – Name of file to be used to save interim JSON record which will be used to attach as report to Slack message.
-
done
()¶ Write the JSON data to a file and send alert.
This function writes the JSON data to a file. The created JSON file will be used by self._post_message method to send the file as an attachment.
cloudmarker.clouds package¶
A package for cloud plugins packaged with this project.
This package contains cloud plugins that are packaged as part of this
project. The cloud plugins implement a function named read()
that
connects to remote data sources, typically cloud APIs, and yield
data records.
Microsoft Azure cloud plugin to read Azure infrastructure data.
This module defines the AzCloud
class that retrieves data
from Microsoft Azure.
-
class
cloudmarker.clouds.azcloud.
AzCloud
(tenant, client, secret, processes=4, threads=30, _max_subs=0, _max_recs=0)¶ Bases:
object
Azure cloud plugin.
Create an instance of
AzCloud
plugin.Note: The_max_subs
and_max_recs
arguments should be used only in the development-test-debug phase. They should not be used in production environment. This is why we use the convention of beginning their names with underscore.Parameters: - tenant (str) – Azure subscription tenant ID.
- client (str) – Azure service principal application ID.
- secret (str) – Azure service principal password.
- processes (int) – Number of processes to launch.
- threads (int) – Number of threads to launch in each process.
- _max_subs (int) – Maximum number of subscriptions to fetch data for if the value is greater than 0.
- _max_recs (int) – Maximum number of records of each type to fetch under each subscription.
-
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return an Azure cloud infrastructure configuration record.
Yields: dict – An Azure cloud infrastructure configuration record.
Microsoft Azure disk plugin to read Azure disk data.
This module defines the AzDisk
class that retrieves disk
from Microsoft Azure.
-
class
cloudmarker.clouds.azdisk.
AzDisk
(tenant, client, secret, processes=4, threads=30, _max_subs=0, _max_recs=0)¶ Bases:
object
Azure disk plugin.
Create an instance of
AzDisk
plugin.Note: The_max_subs
and_max_recs
arguments should be used only in the development-test-debug phase. They should not be used in production environment. This is why we use the convention of beginning their names with underscore.Parameters: - tenant (str) – Azure subscription tenant ID.
- client (str) – Azure service principal application ID.
- secret (str) – Azure service principal password.
- processes (int) – Number of worker processes to run.
- threads (int) – Number of worker threads to run.
- _max_subs (int) – Maximum number of subscriptions to fetch data for if the value is greater than 0.
- _max_recs (int) – Maximum number of Postgres records to fetch for each subscription.
-
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return an Azure disk record.
Yields: dict – An Azure disk record.
Microsoft Azure Key Vault plugin to read Key Vault and associated resources.
This module defines the AzKV
class that retrieves Key Vault
from Microsoft Azure. This module also retrieves the keys and secret
attributes stored within a Key Vault.
-
class
cloudmarker.clouds.azkv.
AzKV
(tenant, client, secret, processes=4, threads=30, _max_subs=0, _max_recs=0)¶ Bases:
object
Azure Key Vault plugin.
Create an instance of
AzKV
plugin.Note: The_max_subs
and_max_recs
arguments should be used only in the development-test-debug phase. They should not be used in production environment. This is why we use the convention of beginning their names with underscore.Parameters: - tenant (str) – Azure subscription tenant ID.
- client (str) – Azure service principal application ID.
- secret (str) – Azure service principal password.
- processes (int) – Number of worker processes to run.
- threads (int) – Number of worker threads to run.
- _max_subs (int) – Maximum number of subscriptions to fetch data for if the value is greater than 0.
- _max_recs (int) – Maximum number of Key Vault records to fetch for each subscription.
-
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return an Azure Key Vault record.
Yields: dict – An Azure Key Vault and associated resource record.
Microsoft Azure monitor plugin to read Azure monitoring data.
This module defines the AzMonitor
class that retrieves data
from Microsoft Azure.
-
class
cloudmarker.clouds.azmonitor.
AzMonitor
(tenant, client, secret, processes=4, threads=30, _max_subs=0, _max_recs=0)¶ Bases:
object
Azure monitor plugin.
Create an instance of
AzMonitor
plugin.Note: The_max_subs
and_max_recs
arguments should be used only in the development-test-debug phase. They should not be used in production environment. This is why we use the convention of beginning their names with underscore.Parameters: - tenant (str) – Azure subscription tenant ID.
- client (str) – Azure service principal application ID.
- secret (str) – Azure service principal password.
- processes (int) – Number of processes to launch.
- threads (int) – Number of threads to launch in each process.
- _max_subs (int) – Maximum number of subscriptions to fetch data for if the value is greater than 0.
- _max_recs (int) – Maximum number of records of each type to fetch under each subscription.
-
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return an Azure monitor record.
Yields: dict – An Azure monitor record.
Microsoft Azure Postgres plugin to read Azure Postgres data.
This module defines the AzPostgres
class that retrieves Postgre SQL
data from Microsoft Azure.
-
class
cloudmarker.clouds.azpostgres.
AzPostgres
(tenant, client, secret, processes=4, threads=30, _max_subs=0, _max_recs=0)¶ Bases:
object
Azure Postgres plugin.
Create an instance of
AzPostgres
plugin.Note: The_max_subs
and_max_recs
arguments should be used only in the development-test-debug phase. They should not be used in production environment. This is why we use the convention of beginning their names with underscore.Parameters: - tenant (str) – Azure subscription tenant ID.
- client (str) – Azure service principal application ID.
- secret (str) – Azure service principal password.
- processes (int) – Number of worker processes to run.
- threads (int) – Number of worker threads to run.
- _max_subs (int) – Maximum number of subscriptions to fetch data for if the value is greater than 0.
- _max_recs (int) – Maximum number of Postgres records to fetch for each subscription.
-
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return an Azure Postgres record.
Yields: dict – An Azure Postgres record.
Microsoft Azure SQL Database plugin to read Azure SQL DB data.
This module defines the AzSQL
class that retrieves SQL DB
from Microsoft Azure. This module also retrieves the Transparent
Data Encryption (TDE) configuration of the SQL database.
-
class
cloudmarker.clouds.azsql.
AzSQL
(tenant, client, secret, processes=4, threads=30, _max_subs=0, _max_recs=0)¶ Bases:
object
Azure SQL Database plugin.
Create an instance of
AzSQL
plugin.Note: The_max_subs
and_max_recs
arguments should be used only in the development-test-debug phase. They should not be used in production environment. This is why we use the convention of beginning their names with underscore.Parameters: - tenant (str) – Azure subscription tenant ID.
- client (str) – Azure service principal application ID.
- secret (str) – Azure service principal password.
- processes (int) – Number of worker processes to run.
- threads (int) – Number of worker threads to run.
- _max_subs (int) – Maximum number of subscriptions to fetch data for if the value is greater than 0.
- _max_recs (int) – Maximum number of SQL server records to fetch for each subscription.
-
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return an Azure SQL database record.
Yields: dict – An Azure SQL database record.
Microsoft Azure storage accounts plugin to read Azure storage accounts data.
This module defines the AzStorageAccount
class that retrieves storage
accounts data from Microsoft Azure.
-
class
cloudmarker.clouds.azstorageaccount.
AzStorageAccount
(tenant, client, secret, processes=4, threads=30, _max_subs=0, _max_recs=0)¶ Bases:
object
Azure storage account plugin.
Create an instance of
AzStorageAccount
plugin.Note: The_max_subs
and_max_recs
arguments should be used only in the development-test-debug phase. They should not be used in production environment. This is why we use the convention of beginning their names with underscore.Parameters: - tenant (str) – Azure subscription tenant ID.
- client (str) – Azure service principal application ID.
- secret (str) – Azure service principal password.
- processes (int) – Number of worker processes to run.
- threads (int) – Number of worker threads to run.
- _max_subs (int) – Maximum number of subscriptions to fetch data for if the value is greater than 0.
- _max_recs (int) – Maximum number of storage accounts records to fetch for each subscription.
-
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return an Azure storage account record.
Yields: dict – An Azure storage account record.
Microsoft Azure virtual machine plugin to read Azure virtual machine data.
This module defines the AzVM
class that retrieves virtula machine data
from Microsoft Azure.
-
class
cloudmarker.clouds.azvm.
AzVM
(tenant, client, secret, processes=4, threads=30, _max_subs=0, _max_recs=0)¶ Bases:
object
Azure Virtual Machine plugin.
Create an instance of
AzVM
plugin.Note: The_max_subs
and_max_recs
arguments should be used only in the development-test-debug phase. They should not be used in production environment. This is why we use the convention of beginning their names with underscore.Parameters: - tenant (str) – Azure subscription tenant ID.
- client (str) – Azure service principal application ID.
- secret (str) – Azure service principal password.
- processes (int) – Number of worker processes to run.
- threads (int) – Number of worker threads to run.
- _max_subs (int) – Maximum number of subscriptions to fetch data for if the value is greater than 0.
- _max_recs (int) – Maximum number of virtual machines records to fetch for each subscription.
-
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return an Azure virtual machine record.
Yields: dict – An Azure virtual machine record.
Microsoft Azure web apps plugin to read Azure web app data.
This module defines the AzWebApp
class that retrieves web apps
data from Microsoft Azure.
-
class
cloudmarker.clouds.azwebapp.
AzWebApp
(tenant, client, secret, processes=4, threads=30, _max_subs=0, _max_recs=0)¶ Bases:
object
Azure web app plugin.
Create an instance of
AzWebApp
plugin.Note: The_max_subs
and_max_recs
arguments should be used only in the development-test-debug phase. They should not be used in production environment. This is why we use the convention of beginning their names with underscore.Parameters: - tenant (str) – Azure subscription tenant ID.
- client (str) – Azure service principal application ID.
- secret (str) – Azure service principal password.
- processes (int) – Number of worker processes to run.
- threads (int) – Number of worker threads to run.
- _max_subs (int) – Maximum number of subscriptions to fetch data for if the value is greater than 0.
- _max_recs (int) – Maximum number of web apps records to fetch for each subscription.
-
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return an Azure web app record.
Yields: dict – An Azure web app record.
Google Cloud Platform (GCP) plugin to read GCP infrastructure data.
This module defines the GCPCloud
class that retrieves data from
Google Cloud Platform.
-
class
cloudmarker.clouds.gcpcloud.
GCPCloud
(key_file_path, processes=4, threads=30, _max_projects=0)¶ Bases:
object
GCP cloud plugin.
Create an instance of
GCPCloud
plugin.Note: The_max_projects
argument should be used only in the development-test-debug phase. It should not be used in production environment. This is why we use the convention of beginning it’s name with underscore.Parameters: -
done
()¶ Log a message that this plugin is done.
-
read
()¶ Return a GCP cloud infrastructure configuration record.
Yields: dict – A GCP cloud infrastructure configuration record.
-
Mock cloud plugin for testing purpose.
-
class
cloudmarker.clouds.mockcloud.
MockCloud
(record_count=10, record_types=('foo', 'bar'))¶ Bases:
object
Mock cloud plugin for testing purpose.
Create an instance of
MockCloud
plugin.This plugin generates mock records. The records generated contains three fields under three top-level keys that we also call “bucket keys”:
raw
,data
, andtype
, as shown in the example below:Example
Here is an example that shows that the records generated by this plugin with the default initialization parameters:
>>> from cloudmarker.clouds import mockcloud >>> cloud = mockcloud.MockCloud() >>> for record in cloud.read(): ... print(record['raw']['data'], ... record['ext']['record_type'], ... record['com']['record_type']) ... 0 foo mock 1 bar mock 2 foo mock 3 bar mock 4 foo mock 5 bar mock 6 foo mock 7 bar mock 8 foo mock 9 bar mock
The three top-level keys,
raw
,ext
, andcom
represent the names of the three buckets under which various data attributes are kept. While this is only a mock plugin, but in an actual cloud plugin implementation, the meaning of these buckets are as follows:raw
: The value for theraw
key is adict
object that represents the actual data object obtained from a cloud in its original form. No modifications should be done to the object obtained from the cloud.ext
: The value for theext
key is adict
object which contains key-value pairs for any additional cloud-specific metadata that need to be stored. The data in this bucket is also known as extended metadata.com
: The value for thecom
key is adict
object which contains key-value pairs for any metadata that is common to all clouds.
Parameters: -
done
()¶ Perform cleanup work.
Since this is a mock plugin, this method does nothing. However, a typical cloud plugin may or may not need to perform cleanup work in this method depending on its nature of work.
cloudmarker.events package¶
A package for event plugins packaged with this project.
This package contains event plugins that are packaged as part of this
project. The event plugins implement a function named eval
that
accepts one record as parameter, evaluates the record, and generates
zero or more event records for each input record. The event plugins also
implement and a function named done
that perform cleanup work when
called.
Microsoft Azure Key Vault key expiry event.
This module defines the AzKVKeyNoExpiryEvent
class that
identifies Key Vault active (enabled) keys without expiry set. This
plugin works on the Key Vault key properties found in the ext
bucket of key_vault_key
records.
-
class
cloudmarker.events.azkvkeynoexpiryevent.
AzKVKeyNoExpiryEvent
¶ Bases:
object
Azure Key Vault key expiry event plugin.
Create an instance of
AzKVKeyNoExpiryEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Key Vault non-recoverable event.
This module defines the AzKVNonRecoverableEvent
class
that identifies if a Key Vault is not recoverable. An Azure Key Vault
is recoverable if both soft delete
and purge protection
is
enabled. This plugin works on the Key Vault secret properties found
in the ext
bucket of key_vault
records.
-
class
cloudmarker.events.azkvnonrecoverableevent.
AzKVNonRecoverableEvent
¶ Bases:
object
Azure Key Vault non-recoverable event plugin.
Create an instance of
AzKVNonRecoverableEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Key Vault secret expiry event.
This module defines the AzKVSecretNoExpiryEvent
class that
identifies if a Key Vault active (enabled) secret without expiry set.
This plugin works on the Key Vault secret properties found in the
ext
bucket of key_vault_secret
records.
-
class
cloudmarker.events.azkvsecretnoexpiryevent.
AzKVSecretNoExpiryEvent
¶ Bases:
object
Azure Key Vault secret expiry event plugin.
Create an instance of
AzKVSecretNoExpiryEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure log profile event.
This module defines the AzLogProfileEvent
class that creates
events for Azure subscriptions with missing log profiles.
-
class
cloudmarker.events.azlogprofileevent.
AzLogProfileEvent
¶ Bases:
object
Azure log profile event plugin.
Create an instance of
AzLogProfileEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Log Profile Missing Category Type Event.
This module defines the AzLogProfileMissingCategoryEvent
class
that identifies if a log profile which is not enable for all the categories
i.e. Write, Delete and Action. This plugin works on the log profile
properties found in the raw
bucket of log_profile
records.
-
class
cloudmarker.events.azlogprofilemissingcategoryevent.
AzLogProfileMissingCategoryEvent
¶ Bases:
object
Azure log profile missing category event plugin.
Create an instance of the class.
Create an instance of the
AzLogProfileMissingCategoryEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Log Profile Missing Location Event.
This module defines the AzLogProfileMissingLocationEvent
class
that identifies if a log profile which is not enable for all the supported
locations/regions for that subscrition including global
. This plugin
works on the log profile properties found in the ext
bucket of
log_profile
records.
-
class
cloudmarker.events.azlogprofilemissinglocationevent.
AzLogProfileMissingLocationEvent
¶ Bases:
object
Azure log profile missing location event plugin.
Create an instance of the class.
Create an instance of the
AzLogProfileMissingLocationEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Log Profile Retention Event.
This module defines the AzLogProfileRetentionEvent
class that
identifies if an Azure log profile’s retention policy is configured for
less than the minimum number of days than required. This plugin works
properties found in the ext
bucket of log_profile
records.
-
class
cloudmarker.events.azlogprofileretentionevent.
AzLogProfileRetentionEvent
(_min_retention_days=365)¶ Bases:
object
Azure log profile retention event plugin.
Create an instance of
AzLogProfileRetentionEvent
.Parameters: _min_retention_days (int) – Minimum required retention days. -
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Postgres Connection Throttling event.
This module defines the AzPostgresConnectionThrottlingEvent
class
that identifies Postgre SQL servers which connection throttling configuration
disabled. This plugin works on the properties found in the com
bucket of postgresql_server
records.
-
class
cloudmarker.events.azpostgresconnectionthrottlingevent.
AzPostgresConnectionThrottlingEvent
¶ Bases:
object
Az Postgres connection throttling event plugin.
Create instance of
AzPostgresConnectionThrottlingEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Postgres Log Checkpoints event.
This module defines the AzPostgresLogCheckpointsEvent
class
that identifies Postgre SQL servers which log checkpoints configuration
disabled. This plugin works on the properties found in the com
bucket of postgresql_server
records.
-
class
cloudmarker.events.azpostgreslogcheckpointsevent.
AzPostgresLogCheckpointsEvent
¶ Bases:
object
Az Postgres log checkpoints event plugin.
Create an instance of
AzPostgresLogCheckpointsEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Postgres Log Connections event.
This module defines the AzPostgresLogConnectionsEvent
class
that identifies Postgre SQL servers which log connections configuration
disabled. This plugin works on the properties found in the com
bucket of postgresql_server
records.
-
class
cloudmarker.events.azpostgreslogconnectionsevent.
AzPostgresLogConnectionsEvent
¶ Bases:
object
Az Postgres log connections event plugin.
Create an instance of
AzPostgresLogConnectionsEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Postgres Log Disconnections event.
This module defines the AzPostgresLogDisconnectionsEvent
class
that identifies Postgre SQL servers which log disconnections configuration
disabled. This plugin works on the properties found in the com
bucket of postgresql_server
records.
-
class
cloudmarker.events.azpostgreslogdisconnectionsevent.
AzPostgresLogDisconnectionsEvent
¶ Bases:
object
Az Postgres log disconnections event plugin.
Create an instance of
AzPostgresLogDisconnectionsEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Postgres Log Duration event.
This module defines the AzPostgresLogDurationEvent
class
that identifies Postgre SQL servers which log duration configuration
disabled. This plugin works on the properties found in the com
bucket of postgresql_server
records.
-
class
cloudmarker.events.azpostgreslogdurationevent.
AzPostgresLogDurationEvent
¶ Bases:
object
Az Postgres log duration event plugin.
Create an instance of
AzPostgresLogDurationEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure Postgres Log Retention Days event.
This module defines the AzPostgresLogRetentionDaysEvent
class
that identifies Postgre SQL servers which have log retention days set
below the desired minimum value. This plugin works on the properties
found in the com
bucket of postgresql_server
records.
-
class
cloudmarker.events.azpostgreslogretentiondaysevent.
AzPostgresLogRetentionDaysEvent
(_min_log_retention_days=3)¶ Bases:
object
Az Postgres log retention days event plugin.
Create instance of
AzPostgresLogRetentionDaysEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure SQL DB Transparent Data Encryption (TDE) event.
This module defines the AzSQLDatabaseTDEEvent
class that
identifies if a SQL database has TDE disabled . This plugin works on the
SQL DB properties found in the ext
bucket of sql_db
records.
-
class
cloudmarker.events.azsqldatabasetdeevent.
AzSQLDatabaseTDEEvent
¶ Bases:
object
Azure SQL database TDE event plugin.
Create an instance of
AzSQLDatabaseTDEEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft storage account allow trusted services event.
This module defines the AzStorageAccountAllowTrustedServicesEvent
class that identifies a storage account with network access set to
denied to Microsoft Azure services. This plugin works on the storage
account properties record found in the ext
bucket of
storage_account_properties
records.
-
class
cloudmarker.events.azstorageaccountallowtrustedservicesevent.
AzStorageAccountAllowTrustedServicesEvent
¶ Bases:
object
Azure storage account allow trusted services event plugin.
Initialize
AzStorageAccountAllowTrustedServicesEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft storage account default network access event.
This module defines the AzStorageAccountDefaultNetworkAccessEvent
class that identifies a storage account with default network access set to
Allow. This plugin works on the storage account properties record
found in the ext
bucket of storage_account_properties
records.
-
class
cloudmarker.events.azstorageaccountdefaultnetworkaccessevent.
AzStorageAccountDefaultNetworkAccessEvent
¶ Bases:
object
Azure storage account default network access event plugin.
Initialize
AzStorageAccountDefaultNetworkAccessEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft storage account secure transfer event.
This module defines the AzStorageAccountSecureTransferEvent
class that identifies a storage account with secure transfer enabled not
set to true . This plugin works on the storage account properties record
found in the ext
bucket of storage_account_properties
records.
-
class
cloudmarker.events.azstorageaccountsecuretransferevent.
AzStorageAccountSecureTransferEvent
¶ Bases:
object
Azure storage account secure transfer enabled check event plugin.
Create instance of
AzStorageAccountSecureTransferEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure VM Data disk encryption event.
This module defines the AzVMDataDiskEncryptionEvent
class that
identifies an unencrypted Azure VM data disk. This plugin works on the
virtual machine properties found in the com
bucket of
virtual_machine
records.
-
class
cloudmarker.events.azvmdatadiskencryptionevent.
AzVMDataDiskEncryptionEvent
¶ Bases:
object
Az VM Data disk encryption event plugin.
Create an instance of
AzVMDataDiskEncryptionEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure VM extension event.
This module defines the AzVMExtensionEvent
class that
evaluates Azure VM extensions. This plugin works on the virtual
machine properties found in the ext
bucket of vm_instance_view
records.
-
class
cloudmarker.events.azvmextensionevent.
AzVMExtensionEvent
(whitelisted=None, blacklisted=None, required=None)¶ Bases:
object
Az VM Data extension event plugin.
Create an instance of
AzVMExtensionEvent
.Parameters: -
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft Azure VM OS disk encryption event.
This module defines the AzVMOSDiskEncryptionEvent
class that
identifies an unencrypted Azure OS disk. This plugin works on the
virtual machine properties found in the com
bucket of
virtual_machine
records.
-
class
cloudmarker.events.azvmosdiskencryptionevent.
AzVMOSDiskEncryptionEvent
¶ Bases:
object
Az VM OS disk encryption event plugin.
Create an instance of
AzVMOSDiskEncryptionEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft web app client certificate event.
This module defines the AzWebAppClientCertEvent
class that
identifies a web app with client certificate (mutual TLS) disabled.
This plugin works on the web apps config properties found in the
ext
bucket of web_app_config
records.
-
class
cloudmarker.events.azwebappclientcertevent.
AzWebAppClientCertEvent
¶ Bases:
object
Azure web app client certificate event plugin.
Create an instance of
AzWebAppClientCertEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft web app HTTP 2.0 event.
This module defines the AzWebAppHttp20Event
class that identifies
if a web app is not using HTTP version 2.0. This plugin works on the web
apps config properties found in the ext
bucket of web_app_config
records.
-
class
cloudmarker.events.azwebapphttp20event.
AzWebAppHttp20Event
¶ Bases:
object
Azure web app HTTP 2.0 event plugin.
Create an instance of
AzWebAppHttp20Event
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft web app HTTPS event.
This module defines the AzWebAppHttpsEvent
class that identifies
a web app with HTTPS only traffic disabled. This plugin works on the web
apps config properties found in the ext
bucket of web_app_config
records.
-
class
cloudmarker.events.azwebapphttpsevent.
AzWebAppHttpsEvent
¶ Bases:
object
Azure web app HTTPS event plugin.
Create an instance of
AzWebAppHttpsEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Microsoft web app minimum TLS version event.
This module defines the AzWebAppTLSEvent
class that identifies
a web app with minimum TLS version not equal to the required minimum TLS
version. This plugin works on the web apps config properties found in the
com
bucket of web_app
records.
-
class
cloudmarker.events.azwebapptlsevent.
AzWebAppTLSEvent
(_min_tls_version=1.2)¶ Bases:
object
Azure web app minimum TLS version check event plugin.
Create an instance of
AzWebAppTLSEvent
.Parameters: _min_tls_version (float) – Minimum required TLS version. -
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Firewall rule event.
This module defines the FirewallRuleEvent
class that identifies
weak firewall rules. This plugin works on the firewall properties found
in the com
bucket of firewall rule records.
-
class
cloudmarker.events.firewallruleevent.
FirewallRuleEvent
(ports=None)¶ Bases:
object
Firewall rule event plugin.
Create an instance of
FirewallRuleEvent
plugin.Parameters: ports (list) – A list of strings that represent the ports to be checked for insecure exposure to the Internet. If None
is specified or if unspecified, then this plugin defaults to checking ports 22, 3389, 1433, 1521, 3306, and 5432 for insecure exposure.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
Mock event plugin for testing purpose.
-
class
cloudmarker.events.mockevent.
MockEvent
(n=3)¶ Bases:
object
Mock event plugin for testing purpose.
Create an instance of
MockEvent
plugin.This plugin events if the
data
field of a mock record is a multiple ofn
.Parameters: n (int) – A number that the record data value in mock record must be a multiple of in order to generate an event record. -
done
()¶ Perform cleanup work.
Since this is a mock plugin, this method does nothing. However, a typical event plugin may or may not need to perform cleanup work in this method depending on its nature of work.
-
eval
(record)¶ Evaluate record to check for multiples of
n
.If
record['raw']['data']
is a multiple ofn
(the parameter with which this plugin was initialized with), then generate an event record. Otherwise, do nothing.If
record['raw']['data]
is missing, i.e., the key namedraw
ordata
does not exist, then its record number is assumed to be1
.This is a mock example of a event plugin. In actual event plugins, this method would typically check for security issues in the
record
.Parameters: record (dict) – Record to evaluate. Yields: dict – Event record if evaluation rule matches the input record.
-
RDBMS Enforce TLS/SSL Event.
This module defines the RDBMSEnforceTLSEvent
class that
identifies RDBMS servers which have TLS/SSL connection enforcement
disabled. This plugin works on the properties found in the com
bucket of rdbms
records.
-
class
cloudmarker.events.rdbmsenforcetlsevent.
RDBMSEnforceTLSEvent
¶ Bases:
object
Az RDBMS TLS/SSL enforcement event plugin.
Create an instance of
RDBMSEnforceTLSEvent
.-
done
()¶ Perform cleanup work.
Currently, this method does nothing. This may change in future.
-
cloudmarker.stores package¶
A package for store plugins packaged with this project.
This package contains store plugins that are packaged as part of this
project. The store plugins implement a function named write()
that
accepts input records and typically stores them into a persistent data
store. The event plugins also implement and a function named done
that perform cleanup work when called.
Elasticsearch store plugin.
-
class
cloudmarker.stores.esstore.
EsStore
(host='localhost', port=9200, index='cloudmarker', buffer_size=5000000)¶ Bases:
object
Elasticsearch adapter to index cloud data in Elasticsearch.
Create an instance of
EsStore
plugin.The plugin uses the default port for Elasticsearch if not specified.
The
buffer_size
for the plugin is the value for the maximum number of bytes of data to be sent in a bulk API request to Elasticsearch.Parameters: -
done
()¶ Flush pending records to Elasticsearch.
-
Filesystem store plugin.
-
class
cloudmarker.stores.filestore.
FileStore
(path='/tmp/cloudmarker')¶ Bases:
object
A plugin to store records on the filesystem.
Create an instance of
FileStore
plugin.Parameters: path (str) – Path of directory where files are written to. -
done
()¶ Perform final cleanup tasks.
This method is called after all records have been written. In this example implementation, we properly terminate the JSON array in the .tmp file. Then we rename the .tmp file to .json file.
Note that other implementations of a store may perform tasks like closing a connection to a remote store or flushing any remaining records in a buffer.
-
write
(record)¶ Write JSON records to the file system.
This method is called once for every
record
read from a cloud. In this example implementation of a store, we simply write therecord
in JSON format to a file. The list of records is maintained as JSON array in the file. The origin worker name inrecord['com']['origin_worker']
is used to determine the filename.The records are written to a
.tmp
file because we don’t want to delete the existing complete and useful.json
file prematurely.Note that other implementations of a store may choose to buffer the records in memory instead of writing each record to the store immediately. They may then flush the buffer to the store based on certain conditions such as buffer size, time interval, etc.
Parameters: record (dict) – Data to write to the file system.
-
MongoDB store plugin.
-
class
cloudmarker.stores.mongodbstore.
MongoDBStore
(host='localhost', port=27017, db='cloudmarker', collection='cloudmarker', username=None, password=None, buffer_size=1000)¶ Bases:
object
A plugin to store records on MongoDB.
Create an instance of
MongoDBStore
plugin.It will use the default port for mongodb 27017 if not specified. The Authentication scheme will be negotiated by MongoDB and the client for v4.0+ to SCRAM-SHA-1 or SCRAM-SHA-256 by default aftere negotiation.
Parameters: - host (str) – hostname for the DB server
- port (int) – port for mongoDB is listening
- db (str) – name of the database
- collection (str) – Name of MongoDB collection.
- username (str) – username for the database
- password (str) – password for username to authenticate with the db
- buffer_size (int) – maximum number of records to buffer
-
done
()¶ Flush pending records to MongoDB and close MongoDB client.
-
write
(record)¶ Write JSON records to the MongoDB collections.
This method is called once for every
record
read from a cloud. This method saves the records into in-memory buffers. A separate buffer is created and maintained for each record type found inrecord['record_type']
. When the number of records in a buffer equals or exceeds the buffer size specified while creating an instance ofMongoDBStore
plugin, the records in the buffer are flushed (saved into a MongoDB collection).The record type, i.e.,
record['record_type']
is used to determine the collection name in MongoDB.Parameters: record (dict) – Data to save in MongoDB.
SplunkStore plugin to index data in Splunk using HEC token.
-
class
cloudmarker.stores.splunkhecstore.
SplunkHECStore
(uri, token, index, ca_cert, buffer_size=1000)¶ Bases:
object
SplunkHECStore plugin to index cloud data in Splunk using HEC token.
Create an instance of
SplunkHECStore
plugin.Parameters: - uri (str) – Splunk collector service URI.
- token (str) – Splunk HEC token.
- index (str) – Splunk HEC token accessible index.
- ca_cert (str) – Location of cetificate file to verify the identity of host in URI, or False to disable verification
- buffer_size (int) – Maximum number of records to hold in in-memory buffer for each record type.
-
done
()¶ Flush any remaining records.
Submodules¶
cloudmarker.baseconfig module¶
Base configuration.
Here is the complete base configuration present as a string in the
config_yaml
attribute:
# Base configuration
plugins:
mockcloud:
plugin: cloudmarker.clouds.mockcloud.MockCloud
filestore:
plugin: cloudmarker.stores.filestore.FileStore
esstore:
plugin: cloudmarker.stores.esstore.EsStore
mongodbstore:
plugin: cloudmarker.stores.mongodbstore.MongoDBStore
firewallruleevent:
plugin: cloudmarker.events.firewallruleevent.FirewallRuleEvent
azvmosdiskencryptionevent:
plugin: cloudmarker.events.azvmosdiskencryptionevent.AzVMOSDiskEncryptionEvent
azvmdatadiskencryptionevent:
plugin: cloudmarker.events.azvmdatadiskencryptionevent.AzVMDataDiskEncryptionEvent
rdbmsenforcetlsevent:
plugin: cloudmarker.events.rdbmsenforcetlsevent.RDBMSEnforceTLSEvent
azwebapptlsevent:
plugin: cloudmarker.events.azwebapptlsevent.AzWebAppTLSEvent
azsqldatabasetdeevent:
plugin: cloudmarker.events.azsqldatabasetdeevent.AzSQLDatabaseTDEEvent
azlogprofileevent:
plugin: cloudmarker.events.azlogprofileevent.AzLogProfileEvent
azlogprofilemissingcategoryevent:
plugin: cloudmarker.events.azlogprofilemissingcategoryevent.AzLogProfileMissingCategoryEvent
azstorageaccountsecuretransferevent:
plugin: cloudmarker.events.azstorageaccountsecuretransferevent.AzStorageAccountSecureTransferEvent
azlogprofileretentionevent:
plugin: cloudmarker.events.azlogprofileretentionevent.AzLogProfileRetentionEvent
azkvsecretnoexpiryevent:
plugin: cloudmarker.events.azkvsecretnoexpiryevent.AzKVSecretNoExpiryEvent
azkvkeynoexpiryevent:
plugin: cloudmarker.events.azkvkeynoexpiryevent.AzKVKeyNoExpiryEvent
azkvnonrecoverableevent:
plugin: cloudmarker.events.azkvnonrecoverableevent.AzKVNonRecoverableEvent
azlogprofilemissinglocationevent:
plugin: arachnoid.events.azlogprofilemissinglocationevent.AzLogProfileMissingLocationEvent
azpostgreslogcheckpointsevent:
plugin: cloudmarker.events.azpostgreslogcheckpointsevent.AzPostgresLogCheckpointsEvent
azpostgreslogconnectionsevent:
plugin: cloudmarker.events.azpostgreslogconnectionsevent.AzPostgresLogConnectionsEvent
azpostgreslogdisconnectionsevent:
plugin: cloudmarker.events.azpostgreslogdisconnectionsevent.AzPostgresLogDisconnectionsEvent
azpostgreslogdurationevent:
plugin: cloudmarker.events.azpostgreslogdurationevent.AzPostgresLogDurationEvent
azpostgresconnectionthrottlingevent:
plugin: cloudmarker.events.azpostgresconnectionthrottlingevent.AzPostgresConnectionThrottlingEvent
azpostgreslogretentiondaysevent:
plugin: cloudmarker.events.azpostgreslogretentiondaysevent.AzPostgresLogRetentionDaysEvent
azvmextensionevent:
plugin: cloudmarker.events.azvmextensionevent.AzVMExtensionEvent
mockevent:
plugin: cloudmarker.events.mockevent.MockEvent
audits:
mockaudit:
clouds:
- mockcloud
stores:
- filestore
events:
- mockevent
alerts:
- filestore
run:
- mockaudit
logger:
version: 1
disable_existing_loggers: false
formatters:
simple:
format: >-
%(asctime)s [%(process)s] [%(processName)s] [%(threadName)s]
%(levelname)s %(name)s:%(lineno)d - %(message)s
datefmt: "%Y-%m-%d %H:%M:%S"
handlers:
console:
class: logging.StreamHandler
formatter: simple
stream: ext://sys.stdout
file:
class: logging.handlers.TimedRotatingFileHandler
formatter: simple
filename: /tmp/cloudmarker.log
when: midnight
encoding: utf8
backupCount: 5
loggers:
adal-python:
level: WARNING
root:
level: INFO
handlers:
- console
- file
schedule: "00:00"
cloudmarker.ioworkers module¶
Concurrent input/output workers implementation.
This module offers a run()
function to run a specified function in
a large number of threads. Unlike the standard library threading
module of Python, this module lets us run threads on multiple CPUs at
the same time. This is achieved by first creating multiple processes
using the standard library multiprocessing
package. These
processes can utilize multiple CPUs. The threads are then launched under
these multiple processes.
-
cloudmarker.ioworkers.
run
(input_func, output_func, processes=0, threads=0, log_tag='')¶ Run concurrent input/output workers with specified functions.
A two-level hierarchy of workers are created using both multiprocessing as well as multithreading. At first,
processes
number of worker processes are created. Then within each process worker,threads
number of worker threads are created. Thus, in total,processes * threads
number of worker threads are created.Parameters: - input_func (callable) – A callable which when called yields
tuples. Each tuple must represent arguments to be passed to
output_func
. - output_func (callable) – A callable that can accept as arguments
an unpacked tuple yielded by
input_func
. When called, this callable must work on the arguments and return an output value. This callable must not returnNone
for any input. - processes (int) – Number of worker processes to run. If
unspecified or
0
or negative integer is specified, then the number returned byos.cpu_count()
is used. - threads (int) – Number of worker threads to run in each process.
If unspecified or
0
or negative integer is specified, then 5 multiplied by the number returned byos.cpu_count()
is used. - log_tag (str) – String to include in every log message. This helps in differentiating between different workers invoked by different callers.
Yields: Each output value returned by
output_func
.- input_func (callable) – A callable which when called yields
tuples. Each tuple must represent arguments to be passed to
cloudmarker.manager module¶
Manager of worker subprocesses.
This module invokes the worker subprocesses that perform the cloud security monitoring tasks. Each worker subprocess wraps around a cloud, store, event, or alert plugin and executes the plugin in a separate subprocess.
-
class
cloudmarker.manager.
Audit
(audit_key, audit_version, config)¶ Bases:
object
Audit manager.
This class encapsulates a set of worker subprocesses and worker input queues for a single audit configuration.
Create an instance of
Audit
from configuration.A single audit definition (from a list of audit definitions under the
audits
key in the configuration) is instantiated. Each audit definition contains lists of cloud plugins, store plugins, event plugins, and alert plugins. These plugins are instantiated and multiprocessing queues are set up to take records from one plugin and feed them to another plugin as per the audit workflow.Parameters: - audit_key (str) – Key name for an audit configuration. This
key is looked for in
config['audits']
. - audit_version (str) – Audit version string.
- config (dict) – Configuration dictionary. This is the
entire configuration dictionary that contains
top-level keys named
clouds
,stores
,events
,alerts
,audits
,run
, etc.
-
join
()¶ Wait until all workers terminate.
-
start
()¶ Start audit by starting all workers.
- audit_key (str) – Key name for an audit configuration. This
key is looked for in
-
cloudmarker.manager.
main
()¶ Run the framework based on the schedule.
cloudmarker.util module¶
Utility functions.
-
exception
cloudmarker.util.
PluginError
¶ Bases:
Exception
Represents an error while loading a plugin.
-
exception
cloudmarker.util.
PluralizeError
¶ Bases:
Exception
Represents an error while converting a word to plural form.
-
cloudmarker.util.
expand_port_ranges
(port_ranges)¶ Expand
port_ranges
to aset
of ports.Examples
Here is an example usage of this function:
>>> from cloudmarker import util >>> ports = util.expand_port_ranges(['22', '3389', '8080-8085']) >>> print(ports == {22, 3389, 8080, 8081, 8082, 8083, 8084, 8085}) True >>> ports = util.expand_port_ranges(['8080-8084', '8082-8086']) >>> print(ports == {8080, 8081, 8082, 8083, 8084, 8085, 8086}) True
Note that in a port range of the form
m-n
, bothm
andn
are included in the expanded port set. Ifm > n
, we get an empty port set.>>> ports = util.expand_port_ranges(['8085-8080']) >>> print(ports == set()) True
If an invalid port range is found, it is ignored.
>>> ports = util.expand_port_ranges(['8080', '8081a', '8082']) >>> print(ports == {8080, 8082}) True >>> ports = util.expand_port_ranges(['7070-7075', '8080a-8085']) >>> print(ports == {7070, 7071, 7072, 7073, 7074, 7075}) True
Parameters: port_ranges (list) – A list of strings where each string is a port number (e.g., '80'
) or port range (e.g.,80-89
).Returns: - A set of integers that represent the ports specified
- by
port_ranges
.
Return type: set
-
cloudmarker.util.
friendly_list
(items, conjunction='and')¶ Translate a list of items to a human-friendly list of items.
Examples
Here are a few example usages of this function:
>>> from cloudmarker import util >>> util.friendly_list([]) 'none' >>> util.friendly_list(['apple']) 'apple' >>> util.friendly_list(['apple', 'ball']) 'apple and ball' >>> util.friendly_list(['apple', 'ball', 'cat']) 'apple, ball, and cat' >>> util.friendly_list(['apple', 'ball'], 'or') 'apple or ball' >>> util.friendly_list(['apple', 'ball', 'cat'], 'or') 'apple, ball, or cat'
Parameters: Returns: Human-friendly list of items with correct placement of comma and conjunction.
Return type:
-
cloudmarker.util.
friendly_string
(technical_string)¶ Translate a technical string to a human-friendly phrase.
In most of our code, we use succint strings to express various technical details, e.g.,
'gcp'
to express Google Cloud Platform. However these technical strings are not ideal while writing human-friendly messages such as a description of a security issue detected or a recommendation to remediate such an issue.This function helps in converting such technical strings into human-friendly phrases that can be used in strings intended to be read by end users (e.g., security analysts responsible for protecting their cloud infrastructure) of this project.
Examples
Here are a few example usages of this function:
>>> from cloudmarker import util >>> util.friendly_string('azure') 'Azure' >>> util.friendly_string('gcp') 'Google Cloud Platform (GCP)'
Parameters: technical_string (str) – A technical string. Returns: - Human-friendly string if a translation from a technical
- string to friendly string exists; the same string otherwise.
Return type: str
-
cloudmarker.util.
load_config
(config_paths)¶ Load configuration from specified configuration paths.
Parameters: config_paths (list) – Configuration paths. Returns: A dictionary of configuration key-value pairs. Return type: dict
-
cloudmarker.util.
load_plugin
(plugin_config)¶ Construct an object with specified plugin class and parameters.
The
plugin_config
parameter must be a dictionary with the following keys:plugin
: The value for this key must be a string that represents the fully qualified class name of the plugin. The fully qualified class name is in the dotted notation, e.g.,pkg.module.ClassName
.params
: The value for this key must be adict
that represents the parameters to be passed to the__init__
method of the plugin class. Each key in the dictionary represents the parameter name and each value represents the value of the parameter.
Example
Here is an example usage of this function:
>>> from cloudmarker import util >>> plugin_config = { ... 'plugin': 'cloudmarker.clouds.mockcloud.MockCloud', ... 'params': { ... 'record_count': 4, ... 'record_types': ('baz', 'qux') ... } ... } ... >>> plugin = util.load_plugin(plugin_config) >>> print(type(plugin)) <class 'cloudmarker.clouds.mockcloud.MockCloud'> >>> for record in plugin.read(): ... print(record['raw']['data'], ... record['ext']['record_type'], ... record['com']['record_type']) ... 0 baz mock 1 qux mock 2 baz mock 3 qux mock
Parameters: plugin_config (dict) – Plugin configuration dictionary. Returns: An object of type mentioned in the plugin
parameter.Return type: object Raises: PluginError
– If plugin class name is invalid.
-
cloudmarker.util.
merge_dicts
(*dicts)¶ Recursively merge dictionaries.
The input dictionaries are not modified. Given any number of dicts, deep copy and merge into a new dict, precedence goes to key value pairs in latter dicts.
Example
Here is an example usage of this function:
>>> from cloudmarker import util >>> a = {'a': 'apple', 'b': 'ball'} >>> b = {'b': 'bat', 'c': 'cat'} >>> c = util.merge_dicts(a, b) >>> print(c == {'a': 'apple', 'b': 'bat', 'c': 'cat'}) True
Parameters: *dicts (dict) – Variable length dictionary list Returns: Merged dictionary Return type: dict
-
cloudmarker.util.
outline_az_sub
(sub_index, sub, tenant)¶ Return a summary of an Azure subscription for logging purpose.
Parameters: Returns: Return a string that can be used in log messages.
Return type:
-
cloudmarker.util.
outline_gcp_project
(project_index, project, zone, key_file_path)¶ Return a summary of a GCP project for logging purpose.
Parameters: Returns: Return a string that can be used in log messages.
Return type:
-
cloudmarker.util.
parse_cli
(args=None)¶ Parse command line arguments.
Parameters: args (list) – List of command line arguments. Returns: Parsed command line arguments. Return type: argparse.Namespace
-
cloudmarker.util.
pluralize
(count, word, *suffixes)¶ Convert
word
to plural form ifcount
is not1
.Examples
In the simplest form usage, this function just adds an
's'
to the input word when the plural form needs to be used.>>> from cloudmarker import util >>> util.pluralize(0, 'apple') 'apples' >>> util.pluralize(1, 'apple') 'apple' >>> util.pluralize(2, 'apple') 'apples'
The plural form of some words cannot be formed merely by adding an
's'
to the word but requires adding a different suffix. For such cases, provide an additional argument that specifies the correct suffix.>>> util.pluralize(0, 'potato', 'es') 'potatoes' >>> util.pluralize(1, 'potato', 'es') 'potato' >>> util.pluralize(2, 'potato', 'es') 'potatoes'
The plural form of some words cannot be formed merely by adding a suffix but requires removing a suffix and then adding a new suffix. For such cases, provide two additional arguments: one that specifies the suffix to remove from the input word and another to specify the suffix to add.
>>> util.pluralize(0, 'sky', 'y', 'ies') 'skies' >>> util.pluralize(1, 'sky', 'y', 'ies') 'sky' >>> util.pluralize(2, 'sky', 'y', 'ies') 'skies'
Returns: - The input
word
itself ifcount
is1
; plural - form of the
word
otherwise.
Return type: str - The input
-
cloudmarker.util.
send_email
(from_addr, to_addrs, subject, content, host='', port=0, ssl_mode='ssl', username='', password='', debug=0)¶ Send email message.
When
ssl_mode` is ``'ssl'
andhost
is uspecified or specified as''
(the default), the local host is used. Whenssl_mode
is'ssl'
andport
is unspecified or specified as0
, the standard SMTP-over-SSL port, i.e., port 465, is used. Seesmtplib.SMTP_SSL
documentation for more details on this.When
ssl_mode
is'ssl'` and if ``host
orport
are unspecified, i.e., if host or port are''
and/or0
, respectively, the OS default behavior is used. Seesmtplib.SMTP
documentation for more details on this.We recommend these parameter values:
- Leave
ssl_mode
unspecified (thus'ssl'
by default) if your SMTP server supports SSL. - Set
ssl_mode
to'starttls'
explicitly if your SMTP server does not support SSL but it supports STARTTLS. - Set
ssl_mode
to'disable'
explicitly if your SMTP server supports neither SSL nor STARTTLS. - Set
host
to the SMTP hostname or address explicitly. - Leave
port
unspecified (thus0
by default), so that the appropriate port is chosen automatically.
With these recommendations, this function should do the right thing automatically, i.e., connect to port 465 if
use_ssl
is unspecified orFalse
and port 25 ifuse_ssl
isTrue
.Note that in case of SMTP, there are two different encryption protocols in use:
- SSL/TLS (or implicit SSL/TLS): SSL/TLS is used from the beginning
of the connection. This occurs typically on port 465. This is
enabled by default (
ssl_mode
as'ssl'
). - STARTTLS (or explicit SSL/TLS): The SMTP session begins as a
plaintext session. Then the client (this function in this case)
makes an explicit request to switch to SSL/TLS by sending the
STARTTLS
command to the server. This occurs typically on port 25 or port 587. Setssl_mode
to'starttls'
to enable this behaviour
If
username
is unspecified or specified as an empty string, no SMTP authentication is done. Ifusername
is specified as a non-empty string, then SMTP authentication is done.Parameters: - from_addr (str) – Sender’s email address.
- to_addrs (list) – A list of
str
objects where eachstr
object is a recipient’s email address. - subject (str) – Email subject.
- content (str) – Email content.
- host (str) – SMTP host.
- port (int) – SMTP port.
- ssl_mode (str) – SSL mode to use:
'ssl'
for SSL/TLS connection (the default),'starttls'
for STARTTLS, and'disable'
to disable SSL. - username (str) – SMTP username.
- password (str) – SMTP password.
- debug (int or bool) – Debug level to pass to
SMTP.set_debuglevel()
to debug an SMTP session. Set to0
(the default) orFalse
to disable debugging. Set to1
orTrue
to see SMTP messages. Set to2
to see timestamped SMTP messages.
- Leave
-
cloudmarker.util.
wrap_paragraphs
(text, width=70)¶ Wrap each paragraph in
text
to the specifiedwidth
.If the
text
is indented with any common leading whitespace, then that common leading whitespace is removed from every line in text. Further, any remaining leading and trailing whitespace is removed. Finally, each paragraph is wrapped to the specifiedwidth
.Parameters:
cloudmarker.workers module¶
Worker functions.
The functions in this module wrap around plugin classes such that these
worker functions can be specified as the target
parameter while
launching a new subprocess with multiprocessing.Process
.
Each worker function can run as a separate subprocess. While wrapping around a plugin class, each worker function creates the multiprocessing queues necessary to pass records from one plugin class to another.
-
cloudmarker.workers.
alert_worker
(audit_key, audit_version, plugin_key, plugin_config, input_queue)¶ Worker function for alert plugins.
This function behaves like
cloudmarker.workers.store_worker()
. See its documentation for details.Parameters: - audit_key (str) – Audit key name in configuration.
- audit_version (str) – Audit version string.
- plugin_key (str) – Plugin key name in configuration.
- plugin_config (dict) – Alert plugin config dictionary.
- input_queue (multiprocessing.Queue) – Queue to read records from.
-
cloudmarker.workers.
cloud_worker
(audit_key, audit_version, plugin_key, plugin_config, output_queues)¶ Worker function for cloud plugins.
This function instantiates a plugin object from the
plugin_config
dictionary. This function expects the plugin object to implement aread
method that yields records. This function calls thisread
method to retrieve records and puts each record into each queue inoutput_queues
.Parameters:
-
cloudmarker.workers.
event_worker
(audit_key, audit_version, plugin_key, plugin_config, input_queue, output_queues)¶ Worker function for event plugins.
This function instantiates a plugin object from the
plugin_config
dictionary. This function expects the plugin object to implement aneval
method that accepts a single record as a parameter and yields one or more records, and adone
method to perform cleanup work in the end.This function gets records from
input_queue
and passes each record to theeval
method of the plugin object. Then it puts each record yielded by theeval
method into each queue inoutput_queues
.When there are no more records in the
input_queue
, i.e., onceNone
is found in theinput_queue
, this function calls thedone
method of the plugin object to indicate that record processing is over.Parameters: - audit_key (str) – Audit key name in configuration.
- audit_version (str) – Audit version string.
- plugin_key (str) – Plugin key name in configuration.
- plugin_config (dict) – Event plugin config dictionary.
- input_queue (multiprocessing.Queue) – Queue to read records from.
- output_queues (list) – List of
multiprocessing.Queue
objects to write records to.
-
cloudmarker.workers.
store_worker
(audit_key, audit_version, plugin_key, plugin_config, input_queue)¶ Worker function for store plugins.
This function instantiates a plugin object from the
plugin_config
dictionary. This function expects the plugin object to implement awrite
method that accepts a single record as a parameter and adone
method to perform cleanup work in the end.This function gets records from
input_queue
and passes each record to thewrite
method of the plugin object.When there are no more records in the
input_queue
, i.e., onceNone
is found in theinput_queue
, this function calls thedone
method of the plugin object to indicate that record processing is over.Parameters: - audit_key (str) – Audit key name in configuration.
- audit_version (str) – Audit version string.
- plugin_key (str) – Plugin key name in configuration.
- plugin_config (dict) – Store plugin config dictionary.
- input_queue (multiprocessing.Queue) – Queue to read records from.