Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The full deployment process for Curiefense:
First, complete the general tasks described in First Tasks
Then complete the specific tasks for your environment:
The instructions below show how to install Curiefense on a Kubernetes cluster, embedded in an Istio service mesh. It assumes that the instructions described in First Tasks have been completed successfully.
The following tasks, each described below in sequence, should be performed:
At the bottom of this page is a Reference section describing the charts and configuration variables.
An AWS S3 bucket must be available to synchronize configurations between the confserver
and the Curiefense Istio sidecars. The following Curiefense variables must be set:
In deploy/istio-helm/chart/values.yaml
:
Setcurieconf_manifest_url
to the bucket URL.
In deploy/curiefense-helm/curiefense/values.yaml
:
Set curieconf_manifest_url
to the bucket URL.
Access to a Kubernetes cluster running Helm v2 is required. Dynamic provisioning of persistent volumes must be supported. To set a StorageClass other than the default, change or override variable storage_class_name
in deploy/curiefense-helm/curiefense/values.yaml
.
Below are instructions for several ways to achieve this:
Using minikube, Kubernetes 1.14.9 and Helm v2.13.1 (dynamic provisioning is enabled by default)
Using Google GKE, Kubernetes 1.16.13 (with RBAC) and Helm v2.16.7 (dynamic provisioning is enabled by default)
Using Amazon EKS, Kubernetes 1.18 (with RBAC) and Helm v2.16.7 (dynamic provisioning is enabled by default)
This section describes the install for a single-node test setup (which is generally not useful for production).
Starting from a fresh ubuntu 20.04 VM:
Install docker (https://docs.docker.com/engine/install/ubuntu/)
Install kubectl (https://kubernetes.io/docs/tasks/tools/install-kubectl/) -- use version 1.14.9.
Install minikube (https://minikube.sigs.k8s.io/docs/start/)
Allow your user to interact with docker: sudo usermod -aG docker $USER && newgrp docker
Start a screen
or tmux
, and keep the following command running:
Run the following commands:
(Alternately, Helm can be manually downloaded as a binary release, as explained at https://helm.sh/docs/intro/install/. If you choose to do this, ensure that you obtain v2.13.1.)
Now install Helm to the Kubernetes cluster:
This option uses a more recent Kubernetes, with RBAC enabled.
Follow instructions at https://kubernetes.io/docs/tasks/tools/install-kubectl/. Use version 1.16.13.
(Alternately, Helm can be manually downloaded as a binary release, as explained at https://helm.sh/docs/intro/install/. If you choose to do this, ensure that you obtain v2.16.7.)
Now we must define RBAC authorizations. Helm needs to be able to deploy applications to both the curiefense
and istio-system
namespaces.
To do that, we provide an example configuration, which installs Tiller in the kube-system
namespaces, and grants it cluster-admin permissions.
Finally, install Helm to the Kubernetes cluster:
This option uses a more recent Kubernetes, with RBAC enabled.
Follow instructions at https://kubernetes.io/docs/tasks/tools/install-kubectl/. Use version 1.18.
Create a cluster
Install Helm v2.16.7
Follow all the "Install Helm v2.16.7" instructions shown above in the Google GKE section.
If you have a clean machine where Curiefense has never been installed, skip this step and go to the next.
Otherwise, run these commands:
Ensure that helm ls -a
outputs nothing.
Run the following commands:
Encode the AWS S3 credentials that have r/w access to the S3 bucket. This yields a base64 string:
Create a local file called s3cfg.yaml
, with the contents below, replacing both occurrences of BASE64_S3CFG
with the previously obtained base64 string:
Deploy this secret to the cluster:
Using TLS is optional.
The UIServer can be made to be reachable over HTTPS. To do that, two secrets have to be created to hold the TLS certificate and TLS key.
Create a local file called uiserver-tls.yaml
, replacing TLS_CERT_BASE64
with the base64-encoded PEM X509 TLS certificate, and TLS_KEY_BASE64
with the base64-encoded TLS key.
Deploy this secret to the cluster:
An example file with self-signed certificates is provided at deploy/curiefense-helm/example-uiserver-tls.yaml
.
When running ./deploy.sh
in the next step, add this argument to enable TLS on the UIServer:
Deploy the Istio service mesh:
And then the Curiefense components:
The application to be protected by Curiefense should now be deployed. These instructions are for the sample application bookinfo
.
Create the Kubernetes namespace, and add the istio-injection=enabled
label that will make Istio automatically inject necessary sidecars to applications that are deployed in this namespace.
Check that bookinfo
Pods are running (wait a bit if they are not):
Sample output example:
Check that the application is working by querying its API directly without going through the Istio service mesh:
Expected output:
(Replace "ip" with "hostname" if running in an environment where the LoadBalancer yields a FQDN, as is the case with Amazon's ELB.)
Expected output:
If this error occurs: Could not resolve host: a6fdxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxx.us-west-2.elb.amazonaws.com
...the ELB is not ready yet. Wait and retry until it becomes available (typically a few minutes).
Run this query
(Replace "ip" with "hostname" if running in an environment where the LoadBalancer yields a FQDN, as is the case with Amazon's ELB.)
Run this to ensure that the logs have been recorded and are reachable from the UI server:
Check that a result is return, and that it does contains TEST_STRING
.
Run the following commands to expose Curiefense services through NodePorts. Warning: if the machine has a public IP, the services will be exposed on the Internet.
Start with this command:
The following command can be used to determine the IP address of your cluster nodes on which services will be exposed:
If you are using minikube, also run the following commands on the host in order to expose services on the Internet:
If you are using Amazon EKS, you will also need to allow inbound connections for port range 30000-30700 from your IP. Go to the EC2 page in the AWS console, select the EC2 instance for the cluster (named curiefense-eks-...-Node
), select the "Security" pane, select the security group (named eks-cluster-sg-curiefense-eks-[0-9]+
), then add the incoming rule.
The UIServer is now available on port 30080 over HTTP, and on port 30443 over HTTPS.
Grafana is now available on port 30300 over HTTP.
For the bookinfo
sample app, the Book Review product page is now available on port 30081 over HTTP, and on port 30444 over HTTPS (if you chose to enable TLS).
The confserver is now available on port 30000 over HTTP.
Kibana is now available on port 30601 over HTTP.
Elasticsearch is now available on port 30200 over HTTP.
For a full list of ports used by Curiefense containers, see the Reference page on services and containers.
Helm charts are divided as follows:
curiefense-admin
- confserver and UIServer.
curiefense-dashboards
- Grafana and Prometheus.
curiefense-log
- log storage: elasticsearch (default); log forwarders for elasticsearch: logstash (default), fluentd; log display interface: kibana (default)
curiefense-proxy
- curielogger, curiesync and redis (used for synchronizationj.
Configuration variables in deploy/curiefense-helm/curiefense/values.yaml
can be modified or overridden to fit your deployment needs:
Variables in the images
section define the Docker image names for each component. Override this if you want to host images on your own private registry.
storage.storage_class_name
is the StorageClass that is used for dynamic provisioning of Persistent Volumes. It defaults to null
(default storage class, which works by default on EKS, GKE and minikube).
storage.*_storage_size
variables define the size of persistent volumes. The defaults are fine for a test or small-scale deployment.
settings.curieconf_manifest_url
is the URL of the AWS S3 bucket that is used to synchronize configurations between the confserver
and the Curiefense Istio sidecars.
settings.curiefense_es_forwarder
defines whether logs are forwarded to elasticsearch using fluentd or logstash (default). Has no effect if settings.curiefense_logdb_type
is set to elasticsearch
.
settings.curiefense_es_hosts
is the hostname for the elasticsearch cluster. Changing it is required only if the elasticsearch cluster supplied by this chart is not used, and replaced with an externally-managed cluster.
settings.curiefense_logstash_url
is the url of the logstash server. Changing it is required only if the logstash instance supplied by this chart is not used, and replaced with an externally-managed instance.
settings.curiefense_fluentd_url
is the url of the fluentd server. Changing it is required only if the fluentd instance supplied by this chart is not used, and replaced with an externally-managed instance.
settings.curiefense_kibana_url
is the url of the kibana server. Changing it is required only if the kibana instance supplied by this chart is not used, and replaced with an externally-managed instance.
settings.curiefense_bucket_type
is the type of cloud bucket that is used to transfer configurations from confserver
to envoy proxies (supported values: s3
or gs
).
settings.curiefense_es_index_name
is the name of the elasticsearch index where logs are stored.
settings.docker_tag
defines the image tag versions that should be used. deploy.sh
will override this to deploy a version that matches the current working directory, unless the DOCKER_TAG
environment variable is set.
settings.redis_port
is the port on which redis listens. This value must be set identically in the Istio chart's values.yaml
.
settings.uiserver_enable_tls
is a boolean that defines whether TLS is enabled on the UI server. If it is enabled, then a certificate and key must have been provisioned (see above).
Variables in the requests
define default CPU requirements for pods.
Variables in the enable
allow disabling parts of a deployment, which can be supplied outside of this chart (ex. kibana, logstash, fluentd, elasticsearch, prometheus...).
Components added or modified by Curiefense are defined in deploy/istio-helm/chart/charts/gateways
. Compared to the upstream Istio Kubernetes distribution, we add or change the following Pods:
An initContainer
called curiesync-initialpull
has been added. It synchronizes configuration before running Envoy.
A container called curiesync
has been added. It periodically fetches the configuration that should be applied from an S3 bucket (configurable with the curieconf_manifest_url
variable), and makes it available to Envoy. This configuration is used by the LUA code that inspects traffic.
The container called istio-proxy
now uses our custom Docker image, embedding our HTTP Filter, written in Lua.
An EnvoyFilter
has been added. It forwards access logs to curielogger
(see curiefense_access_logs_filter.yaml
).
An EnvoyFilter
has been added. It runs Curiefense's Lua code to inspect incoming traffic on the Ingress Gateways (see curiefense_lua_filter.yaml
).
Configuration variables in deploy/istio-helm/chart/values.yaml
can be modified or overridden to fit your deployment needs:
gw_image
defines the name of the image that contains our filtering code and modified Envoy binary.
curiesync_image
defines the name of the image that contains scripts that synchronize local Envoy configuration with the AWS S3 bucket defined in curieconf_manifest_url
.
curieconf_manifest_url
is the URL of the AWS S3 or Google Storage bucket that is used to synchronize configurations between the confserver
and the Curiefense Istio sidecars.
curiefense_namespace
is the name of the namespace where Curiefense components defined in deploy/curiefense-helm/
are running.
curiefense_bucket_type
is the type of cloud bucket that is used to transfer configurations from confserver
to envoy proxies (supported values: s3
or gs
).
redis_host
defines the hostname of the redis server that will be used by curieproxy
. Defaults to the provided redis StatefulSet. Override this to replace the redis instance with one you supply.
redis_port
defines the port of the redis server that will be used by curieproxy
. Defaults to the provided redis StatefulSet. Override this to replace the redis instance with one you supply.
initial_curieconf_pull
defines whether a configuration should be pulled from the AWS S3 bucket before running Envoy (true
), or if traffic should be allowed to flow with a default configuration until the next synchronization (typically every 10s).
Curiefense is an API-first, GitOps-based web-defense HTTP-Filter adapter for . It provides multiple security technologies (WAF, application-layer DDoS protection, bot management, and more) along with real-time traffic monitoring and transparency.
Curiefense is . All configuration data (security rulesets, policies, etc.) can be maintained singularly, or as different branches for different environments, as you choose. All changes are versioned, and reverts can be done at any time.
Curiefense also has a UI console, discussed in this Manual beginning in the section.
This documentation is for version 1.3.0
(To view docs for a previous version, choose it at the top of the left sidebar.)
Curiefense provides traffic filtering that can be configured differently for multiple environments (e.g. dev/qa/prod), all of which can be administered from one central cluster if desired. Here is an overview of its components.
In the diagram above, the Server represents a resource protected by Curiefense (a site, app, service, or API). The User is a traffic source attempting to access that resource.
Incoming traffic passes through Envoy, which is using Curiefense as an HTTP filter. Hostile requests are blocked.
The other components in the diagram represent the Curiefense platform, as follows:
Curiefense proxy (represented by the Curiefense logo): Plugs into Envoy and performs traffic filtering.
Logs DB. Curiefense stores traffic data (headers, payloads, etc.) from all requests here.
Metrics. A Prometheus store of traffic metrics.
Dashboard. Grafana dashboard(s) with visual displays of traffic metrics.
Web UI. Curiefense's web console for configuring the platform.
Config Server: A service which:
Receives configuration edits from the Web UI
Receives configuration edits from API calls (not shown in the diagram)
Creates a new configuration version in response to edits
Stores the new version in one or more Cloud Storage buckets
Cloud Storage: Stores versioned configurations. Each Curiefense proxy periodically checks Cloud Storage: when a new version is found there, the proxy downloads it and updates its security posture.
Curiefense can run in variety of environments, depending on your specific needs. It can be adapted to many different use cases.
If you create an installation workflow for a situation that is not currently described in this manual, please feel free to submit it for inclusion.
Conceptually, there are three primary roles performed by Curiefense:
Configuration (allowing admins to define security policies, assign them to URLs, etc.)
Filtering (applying the defined Configurations to incoming traffic and blocking hostile requests)
Monitoring (displaying traffic data in real-time and in historical logs).
Curiefense maintains its security parameters as Entries, which are contained in Documents, which are contained in Configurations.
A Configuration is a complete definition of Curiefense's behavior for a specific environment. An organization can maintain multiple Configurations (e.g., development, staging, and production).
A Configuration also includes data blobs, which currently are used to store the Maxmind geolocation database. This is where Curiefense obtains its geolocation data and ASN for each request it processes.
A Configuration is the atomic unit for all of Curiefense's parameters. Any edits to a Configuration result in a new Configuration being committed. Configurations are versioned, and can be reverted at any time.
When a Configuration is created or modified (whether by the UI console or an API call), the admin pushes it to a Cloud Storage bucket. An important feature of Curiefense is simultaneous publishing to multiple environments.
Traffic filtering is performed by the Curiefense proxy, as shown in the first diagram above. In other words, this is where the security policies defined in the Configurations are enforced.
Some activities (such as rate limiting) require local data storage. Internally, Curiefense uses Redis for this. Other storage methods can be used instead if desired.
Each time a request goes through Curiefense, a detailed log message is pushed to elasticsearch.
Traffic data is available in several ways:
The input controls at the top of this page are described here: . Specific editing of a Session Flow Control entry is described below.
The Session Flow Control module blocks hostile activity based on defined sequences of session flow.
Threat actors usually behave quite differently than legitimate users. For speed and efficiency, they tend to deviate from normal patterns of activity. The Session Flow Control capabilities of Curiefense allow you to define the expected patterns of behavior, and block access attempts that deviate from them.
For example, when a legitimate user attempts to log into a web application, the initial access of the login page will generate a GET request. Subsequently, a POST request will arrive with the login credentials.
However, a hostile bot that's attempting a credential stuffing attack has no need to issue a GET, and often, will not bother to do so. Therefore, if a POST request arrives that was not preceded by a GET, this is anomalous behavior, and Curiefense can block it.
These parameters define the sequence of requests that will be enforced. The sequence consists of several sequence sections. They must be fulfilled in the order defined here.
By default, a new sequence contains two sections. Additional sections can be added by selecting the "Create new sequence section" button.
A request will fulfill this Sequence Section if it matches all of these parameters:
The HTTP method specified in Method
The domain or host specified in Host
The path specified in Path
And the optional parameters, if any. Optional parameters can be added by selecting the "+" button; each parameter includes matching characteristics for a header, cookie, or argument.
For detailed information about the specific containers and services which perform the roles described above, see the reference page on .
Deployment instructions for several different environments are available in the section of this manual and on the page. More will be added in the future.
Each Configuration contains six Documents (one of each type: ACL Profiles, Rate Limits, etc.) Each Document contains at least one Entry, i.e., an individual security rule or definition. Documents are edited and managed in the UI or via API.
When a Configuration is , it can be pushed to multiple buckets (each of which can be monitored by one or more environments) all at once, from a single button-push or API call.
The Curiefense graphical client provides an which provides comprehensive details for requests.
Curiefense is also integrated with and , for traffic dashboards and other displays.
This page describes the tasks necessary to deploy Curiefense using Docker Compose. It assumes that the instructions described in First Tasks have been completed successfully.
This process consists of the following tasks, described sequentially below:
If during this process you need to rebuild an image, see the instructions here: Building/Rebuilding an Image.
If you want Curiefense to use TLS, then you should have already generated the certificates and keys.
To enable TLS for the protected site/application, go to curiefense/deploy/compose/curiesecrets/curieproxy_ssl/
and do the following:
Edit site.crt
and add the certificate.
Edit site.key
and add the key.
To enable TLS for the nginx server that is used by uiserver
, go to curiefense/deploy/compose/curiesecrets/uiserver_ssl/
and do the following:
Edit ui.crt
and add the certificate.
Edit ui.key
and add the key.
Docker Compose deployments can be configured in two ways:
By setting values for variables in deploy/compose/.env
Or by setting OS environment variables (which will override any variables set in.env
)
These variables are described below.
Curiefense uses the storage defined here for synchronizing configuration changes between confserver
and the Curiefense sidecars.
By default, this points to the local_bucket
Docker volume:
For multi-node deployments, or to use S3 for a single node, replace this value with the URL of an S3 bucket:
In that case, you will need to supply AWS credentials in deploy/compose/curiesecrets/s3cfg
, following this template:
The address of the destination service for which Curiefense acts as a reverse proxy. By default, this points to the echo
container, which simply echoes the HTTP requests it receives.
Defaults to latest
(the latest stable image). To run a version that matches the contents of your working directory, use the following command:
Once the tasks above are completed, run these commands:
After deployment, the Echo service should be running and protected behind Curiefense. You can test the success of the deployment by querying it:
Also verify the following:
The UIServer is now available at http://localhost:30080
Grafana is now available at http://localhost:30300/dashboards
The confserver
is now available at http://localhost:30000/api/v1/
To stop all containers and remove any persistent data stored in volumes, run the following commands:
This page describes the initial tasks that must be performed when deploying Curiefense:
After completing the tasks below, proceed to the tasks for the specific method being used:
During this process, you might find it helpful to read the descriptions (which include the purpose, secrets, and network/port details) of the services and their containers:
Clone the repository, if you have not already done so:
This documentation assumes it has been cloned to ~/curiefense
.
Curiefense can use TLS, but this is optional. (If you do not choose to set it up, HTTPS will be disabled.)
At this point in the setup process, you should decide whether or not to do so:
An Istio Helm deployment can use TLS for communication with Curiefense's UI server.
A Docker Compose deployment can use TLS for communication with Curiefense's UI server and also for the protected service.
If you do not want Curiefense to use TLS, then skip this step and proceed to the next section.
If you want Curiefense to use TLS, generate the certificate(s) and key(s) now. You will add them to Curiefense later.
After performing the previous tasks, perform the tasks for the specific method being used:
Value | Description |
Name | A name for this flow control entry, for display within the interface. |
Active | Whether or not this flow control entry is enforced. |
TTL | The time period within which the traffic source must complete the Flow Control Sequence. In the example screenshot above, a POST request will be rejected if a GET was not received within the previous 60 seconds. |
Count by | Defines the criteria by which Curiefense will associate requests with a single requestor. In other words, this is how Curiefense identifies requests as having originated from the same traffic source. By default, a single parameter is available; to add more, select New entry. Multiple parameters are evaluated with "AND"; requests must match all the parameters to be associated together. |
Action | When the Flow Control Sequence is violated, this Action will be taken. |
Notes | Comments for use within the interface. |
Include |
Exclude | Excludes any request from evaluation if it contains a Tag on this list. |
This Quick Start guide shows how to quickly deploy Curiefense, set up some basic security policies, and test them.
Prerequisite: Ubuntu 20.04 LTS
In this guide, we will deploy Curiefense using Docker Compose, then test and configure.
If you want to use Helm instead of Docker Compose, or if you want more control over the deployment options, then do this:
Go to the Deployment in Depth: First Tasks page and follow its instructions.
Go to the appropriate Deployment in Depth page (Docker Compose or Helm) and follow its instructions.
Return here to the Verify the Deployment section below, and continue.
To ensure we have all tools in place, we will run:
Grab the latest code from GitHub to get started:
💡 ProTip: Try Curiefense out on Katacoda, no install necessary.
This tutorial assumes that host names curie.demo and api.curie.demo are mapped to the host machine. You may replace it with the IP of your host, or set your/etc/hosts
file accordingly. For example, if docker-compose was executed locally, then
127.0.0.1 curie.demo api.curie.demo
At this point you should have the following http interfaces:
Make sure everything is working by testing the echo server:
This section describes the newly-described components of Curiefense. Feel free to skip it if desired, and go straight to the instructions for policy and rules configuration.
This diagram will help us understand the containers we just deployed, their connections, and the data flow:
Before diving in and making changes, let's discuss a few concepts of Curiefense's configuration.
Git is the storage management used to keep track of changes. This means:
Data can be stored anywhere a git repository can (local, remote, hosted, etc).
Every change you made can be reverted.
You can automate deployments based on tagging.
Using a single configuration server, you can maintain configurations of multiple deployments (e.g. production, devops, qa, rc, etc.) by keeping each in a separate branch, and you can merge them the git way at any point in time, via the API and/or UI.
Configurations are organized in Documents and Entries. More on this here.
Curiefense runs every incoming request (and in some cases, responses as well) through a series of mechanisms. We will now walk through some of them to understand how traffic is handled and processed.
During the procedures described below, you will set up some simple rules and then run some requests through Curiefense. By the end of this process, you will understand how to create security rules and policies, you will observe them being applied, and you will see how Curiefense reports on incoming requests and its reactions to them.
Open the UI management console by going to http://curie.demo:30080/. In the left sidebar, select Policies & Rules if it is not already selected.
At the top left of the page, in the second pulldown control, select Tag Rules.
Tag Rules lists attach tags to requests and sessions based on various criteria, from matching headers, cookies, arguments or URLs to traffic sources such as geolocations, IP addresses, CIDRs, and AS numbers. Subsequently, the tags are then used to make decisions about how the requests are handled.
Start by creating a new Tag Rules List by selecting the "+" button at the top:
Next, in the Tags text box on the left, enter the value trusted
.
Then, at the top of the (currently empty) list to the right, add a new entry by selecting the Create New Section button. An empty rule will appear.
In the left pulldown, select Header. Enter foo
for its name, and bar
for its value. Then select "Add".
Your screen should look similar to this:
We have created a simple tag rule. Every request that contains a header named foo
which matches the regex (PCRE) bar
will receive a tag of trusted
.
Now save the new configuration:
And then publish it by going to "Publish Changes" in the left sidebar, and selecting Publish configuration:
After publishing, your changes need time to propagate. Waiting 10-15 seconds should be enough.
Now it is time to test our configuration. Let's run the following curl commands:
Navigating to Access Log in the left sidebar should show a screen similar to this:
Click on the /with/header
entry, and notice the trusted
tag on the right column:
Notice also that along the trusted
tag you defined, Curiefense attached a number of tags that were generated automatically. More information about this.
Tag Rules Lists are a powerful feature of Curiefense (and are explained in depth here). We just demonstrated the ability to create a single-entry self-managed list that characterizes incoming requests based on a header. Curiefense allows you to attach tags based on complex combinations of headers, arguments, cookies, geolocation, methods, paths, and more. External data sources are also supported; sessions can be profiled based on data and rules defined by a third party, such as blocklists and whitelists.
Now that we know how to attach tags to incoming requests, let's tell Curiefense how to react to them.
We're going to block all requests with the trusted
tag.
In the left menu, navigate to Document Editor. By default, ACL Profiles should already be selected.
Enter trusted
into the DENY column, then save your changes.
Your screen should look similar to this:
Publish the new configuration again (and wait 15 seconds for the changes to propagate).
Run this command:
In the Access Log, you should see the request listed. Expanding it will show this:
Note that the request was identified as a risk, because it contains the specified tag and therefore matches the DENY ACL.
However, Curiefense passed the request through the system, as seen in the green HTTP status code (200: successful). If it had been blocked, the code would instead be red with an error code.
This behavior is expected. By default, Curiefense's security profiles are in report/monitor mode; requests will be flagged but not blocked. This mode allows for testing and fine-tuning of new configurations without affecting traffic.
Let's assume that we've tested our new policies and want to make the ACL active.
Navigate to Document Editor and then choose to edit URL Maps in the upper dropdown list.
URL Maps assign security policies to paths within the protected application. You can assign policies at any scale, from globally down to individual URLs. (They are explained in depth here.)
We're going to edit Curiefense's default security profile: the one that applies to every URL which does not otherwise have any policies assigned to it.
Expand the default profile (the one assigned to path /
) by selecting it. Then activate the profile by checking the Active Mode checkbox.
Save your changes and publish the configuration again.
After the change propagates, Curiefense should block the request:
You have seen how to create security policies that filter hostile requests, and how to assign these policies to paths within your application.
Now we'll see how to filter requests that are not obviously hostile at first, but which display hostile intent with increased volume. For example, a user who fails a login attempt might have mistyped their password—but a user who fails ten login attempts in a short time is probably trying to guess the password for an account they do not own.
Return to URL Maps and select the default profile again. At the bottom of its map, there is the Rate Limit Rules section. Currently, it is empty.
Attach an existing rule by select the first "here" link. A pulldown list of available Rate Limit Rules will be displayed.
Open the list, and select its only entry (the one that comes by default with the system). This rule limits requests from a given IP address to a maximum of 5 requests per 60 seconds.
Select the "add" link to add this rule to the default URL Map.
Save your changes, and then publish.
After propagation, we can test it:
Wait briefly, and you should see how the response changes from 403 (ACL) to 503 (Rate limit) on the 6th request.
Now that we're somewhat familiar with the system, let's set up multi-layered rate limiting to protect against a variety of attacks.
Rate limits in Curiefense are reusable "stand-alone" rules that can be attached to different paths in URL Maps.
Previously, we used the default Rate Limit that comes with Curiefense, and applied it to the entire domain. Now we will create three specific Rate Limits for the login process of an API, and attach them to the relevant endpoints.
Create a new URL Map by duplicating the default one:
Set its name (the unlabeled field at the top) to API
. Set Matching Names to api.curie.demo
.
Note that the new URL Map contains a default profile. As you might expect, this will apply to every path within the scope set by the Matching Names entry. (In this tutorial, the Matching Names is a specific subdomain. In production use, this might be a regex describing a range of domains, subdomains, or URLs.)
To add a profile to a URL Map, open an existing profile (in this case, the default) and select the Fork profile button.
Edit the Name and Match condition of the profile and then repeat this process twice more, so that there are four profiles in total. The Names and Match Conditions are shown below:
At this point, we have four profiles: the default /
which we left in place, /api/v1/
and /api/v2
to match API calls of different versions, and an entry for /login
that catches both versions.
Note that the default has one Rate Limit attached to it (shown as a "1" in the RL column), because it already had this when it was duplicated. The other three profiles do not yet have any limits.
For /api/v1/
and /api/v2/
, set the standard rate limit rule as you did before:
For /api/v[1-2]/login
, we will create three new rate limit rules.
Open the Rate Limits section of the UI by selecting Rate Limits at the top of the window (in the pulldown list that currently says URL Maps).
The default Rate Limit should be displayed. Add a new Rate Limit by duplicating it, using the Duplicate Document button in the top right part of the interface.
Edit the new Rate Limit so that it limits login attempts from the same IP address, allowing a maximum of three within 10 minutes:
Create a second Rate Limit by duplicating an existing one. Edit it so that it limits a given User-Id header to a single country within a four hour timespan:
Create a third Rate Limit by duplicating an existing one. Edit it so that it limits each IP to submitting a maximum of eight unique User IDs:
Return to the URL Maps section of the interface. Let's attach the new rules to the /api/v[1-2]/login
matching path.
Expand the appropriate profile, select the link at the bottom ("To attach an existing rule..."), and select the first of the three new rules you created. Repeat for the second and third rules. When you're finished, you should see something similar to this:
Next, let's try to brute-force the login endpoint, using the same user id and IP, but with a new password each time:
To test the other rule, we will have curl send a unique User ID each time:
As traffic gets blocked (returning a 503 error by default) we can look at the Access Log. When expanding a 503 line, you can see the Risk Details, which include the rate limit rule that was violated (in this case, Dictionary Harvesting).
You can also see the system has generated a tag named after the rule name. Lastly, notice that every request is logged with all details.
The demonstration above is only the beginning of what can be done with Rate Limiting. You can configure Curiefense to limit complex combinations of conditions and events, customize its reactions (including blocking, redirecting, monitoring, responding with custom codes, adding headers to requests for backend evaluation), and more.
Here's a common example. Rate Limits like the ones demonstrated above will block a requestor who exceeds a defined limit within the given timespan. However, once the limit resets, the requestor would be able to try again, and could repeat this cycle as often as desired. To prevent this, you can configure Curiefense to ban a requestor (and block all of their requests) when multiple rate limits are violated.
A full explanation of Curiefense's Rate Limits and their capabilities is available here.
The docker-compose deployment process will create Grafana visualizations for Curiefense's traffic data.
Curiefense comes with two dashboards out of the box: Traffic Overview and Top Activities. They are available at http://curie.demo:30300/.
You now have a working Curiefense installation to experiment with. Its capabilities go far beyond those demonstrated in this tutorial; browsing through the rest of this Manual (especially the Document Editor section) will give you some ideas to test, so you can see what the platform can do.
Note that this tutorial was a Quick Start guide, and therefore, it used many default options for the deployment. You might want to change some of them; for example, you might want Curiefense to use TLS for its UI server and for communicating with the backend.
Modifying the deployment is straightforward. For Docker Compose, just go through the procedures described here and then re-run docker-compose up
. For Helm, go through the procedures here.
Curiefense maintains its security parameters in Documents, which contain Entries. (Read more about Curiefense's data structures.)
The Policies & Rules section is where Documents and their Entries are created, defined, and administered via the UI.
Curiefense processes incoming requests according to this traffic flow:
Each incoming request is inspected, and tags are assigned to it. For example, if the request's IP was found on the Spamhaus DROP list, it could be assigned a "spamhaus" tag. Some tags are generated automatically, while others are user-defined. (Read more about tags.)
Next, Rate Limits are enforced.
Then, Session Flow Control is enforced.
Next, Curiefense determines the security ruleset(s) that have been assigned to the request's target URL, and which match the tags. For example, there might be a ruleset defined for the "spamhaus" tag, or for the "devops" tag.
Curiefense then enforces the ruleset(s), and takes the defined Action(s). For example, "block requests from Spamhaus-listed IPs", or "bypass devops requests from further filtering."
This process is based on the Documents as follows:
Tag Rules is the Document which defines tags for external lists and custom lists.
Rate Limits and Flow Control parameters define session-based policies.
ACL Policies and WAF Policies define the actions to take when specific tags and/or other criteria are observed. URL Maps assign these actions to internal URLs.
This page is divided into three vertical sections. From top to bottom, they are:
Administration
Entry editing
Versioning
Each is discussed below.
After editing anything on this page, you must save your changes (with the Save button on the upper right) and then publish them.
The top section contains a toolbar with input controls. On the left, there are these:
Configuration pulldown: Selects the branch/configuration for editing.
Document pulldown: Selects the Document to display for editing.
Download button: Downloads the currently displayed parameters.
On the right are these:
Entry pulldown: Selects the Entry (the ruleset) that is being displayed for editing.
Duplicate button: Makes a copy of the currently displayed Entry.
Add button: Creates a new Entry of the currently selected type.
Save button: Saves all changes that were made since the last Save action.
Delete button. Deletes the currently selected Entry.
The UI in this section will vary, depending on the type of Document being edited. Each is discussed in more depth here:
At the bottom of this section, the URL of the current entry is shown in gray. It reflects the structure of the data.
For example, /conf/api/v1/configs/devops/d/urlmaps/e/__default__
shows that:
The current Configuration (or branch) is devops.
The current Document is urlmaps.
The current Entry is __default__.
The bottom section of this page shows a history of versions for this Document.
To revert this Document to a previous version, hover the cursor over the end of its listing. As shown above, a button will appear; selecting it will restore that version.
Reversions are also available in the API and in the Publish Configuration section of the UI.
The input controls at the top of this page are described here: Policies & Rules Entry Administration. Specific editing of a WAF Profile is described below.
A WAF Profile is a set of security policies that are used by the Curiefense WAF (Web Application Firewall). Every deployment includes a default WAF Profile, and additional Profiles can be created.
Every URL that Curiefense protects has a WAF Profile assigned to it in URL Maps. (If none is assigned explicitly, the default is used.) A request sent to a URL might, or might not, be filtered according to the assigned Profile.
The request was blocked before WAF filtering would have occurred. (Before the WAF is used, several other stages of filtering occur first.)
The applicable ACL Profile resulted in an Action of Bypass, which exempts the request from WAF filtering.
The WAF is not in Active Mode for this URL.
At the top of the page, the following values are defined for incoming requests.
By default, an incoming request will be compared to all the WAF Rules. If any parameter (any header, cookie, or argument within it) fails this evaluation, the request will be blocked.
However, parameters can be whitelisted and exempted from this filtering. For each parameter, this can be done in two ways:
Full exemption is available by specifying a regex pattern which, if it matches the parameter's value, will exempt that parameter from WAF Rule evaluation.
Partial exemption is available by specifying a list of WAF Rules which will not be evaluated, even if the regex pattern is not matched.
Along with this content whitelisting, a "positive security" form of content filtering is also available. Curiefense can be configured to require certain content in a specified parameter, and reject requests that do not contain it.
The bottom part of the UI defines Curiefense's behavior for both whitelisting and content filtering for each parameter.
In the following discussion, a constraint refers to the values in the UI input controls (Parameter, Matching Value, Restrict?, and Exclude WAF Rule) that have been specified for one parameter.
Each incoming request is processed like this:
This behavior is defined in the following fields in the UI.
Constraints are defined in the same way for Headers, Cookies, and Arguments within their respective tabs.
The input controls at the top of this page are described here: Policies & Rules Entry Administration. Specific editing of a URL Map is described below.
This page specifies a list of URLs and the security policies assigned to them.
Every incoming HTTP/S request targets a specific URL. Curiefense finds the best match for that URL in the URL Maps, and applies the security policies defined for it.
The "best match" is determined by regex evaluation. The order in which the URLs are listed in the interface does not matter.
A URL Map consists of:
Host definition: The (sub)domain(s) within which the Path Maps will be found.
Path Maps: one or more paths, and the security policies which will be applied to them.
Every Curiefense deployment includes a default URL Map. If a request does not match any other URL Map, the default one is applied.
To ensure that a default always exists, the Matching Name and Path Map for this URL Map are not editable.
To add a new URL Map, use the buttons at the top of the window to duplicate an existing one or create a new one. Then fill in these fields.
When you create or revise a URL Map, each combination of Matching Name and Path Map must be unique. For this reason, when a new URL Map is created, the UI generates a unique Matching Name.
This should be changed to a correct value before the URL Map is saved.
A new URL Map will include a default Path Map. Clicking on it, or on the expand button at the end of its listing, will expand it for editing.
To add a new Path Map, select an existing one, expand it, and select Fork Profile at the bottom. The existing one will be cloned, and the new one will be displayed for editing.
Note that the buttons at the top of the window are for administering URL Maps (which generally correspond to domains). Administering Path Maps (for paths and URLs within the specified domain) is done in the middle of the window.
Ensure that URL Maps do not overlap. In other words, for every domain defined in a Matching Name, ensure that every possible path within it cannot match more than one Match expression. If an incoming request matches more than one Path Map definition, there is no way to predict which of them Curiefense will use when enforcing security policies.
In addition to editing the fields discussed above, the Path Mapping dialog also provides the ability to:
Activate or deactivate the WAF Policy (by toggling its Active Mode checkbox).
Activate or deactivate the ACL Policy (by toggling its Active Mode checkbox).
Assign an existing Rate Limit rule to this Path Map, via the + button or selecting the link ("To attach an existing rule, click here."), then selecting add. (The + button will only be shown if there are unassigned Rate Limit rules available.)
Create a new Rate Limit rule for this Path Map, by selecting the link ("To create a new rate-limit rule, click here.")
Remove an assigned Rate Limit Rule by selecting remove.
Create a copy of this Path Map, and open it for editing, via the Fork Profile button.
This section displays all the WAF Rules defined within Curiefense. This has various uses; for example, looking up the underlying signature for a tag that appears in the Access Log, or getting the ID of a Rule to exclude in a WAF Policy.
Curiefense comes with many WAF Rules. You can view them by choosing different IDs in the pulldown on the upper right.
Note that this list is for reference only. The entries cannot be edited.
This page offers a search capability globally across Curiefense, or for a specific scope (Document Type, ID, Name, Description, Tags, or Connections).
As shown above, hovering the cursor at the end of a search result will display a button that will bring you directly to the document.
An ACL (Access Control List) Policy is a set of sequential criteria by which a request is evaluated. The input controls at the top of this page are described here: Policies & Rules Entry Administration. Specific editing of an ACL Policy is described below.
This page defines ACL Policies. The Policies are assigned to URLs within the web application via URL Maps.
Out of the box, Curiefense includes a default ACL Policy. It can (and usually should) be edited, but it cannot be deleted. It is used for all URLs where no other Policy has been assigned.
The top part of the interface shows the ACL Policy that is currently being edited. Each Policy consists of one or more tags. Each tag is listed under the action which will be triggered when a request matches that particular tag.
In the interface, the tags are listed below their associated actions. Evaluation is performed from left to right:
The incoming request is evaluated to see if it matches any of the tags in the far left column.
If a match is found, that column's action is performed, and no further evaluation is done.
If a match is not found, then the next column to the right is evaluated. A match will trigger that column's action; otherwise the next column is evaluated.
This process continues until an action is taken or all columns have been evaluated.
If a request does not match any tags in this Policy, it is passed to the WAF for further inspection.
Be very cautious when adding the "all" tag to an action column. In most situations, that action will be taken for all requests for which a match was not found in any columns to the left.
The most common use is the "Deny Bot" column, as noted above. This means that all requestors (except for those previously Allowed or Bypassed) will be challenged and verified to be humans.
Another possible use is to place "all" in the Deny column, to create a positive security model. (This will block all requests which did not explicitly meet any of the conditions to be Bypassed or Allowed.) But even this usage can be dangerous. Unless all the conditions for Bypassing or Allowing requests are fully and correctly defined, this can result in False Positive errors, and some legitimate requests will be blocked and filtered.
In other columns, "all" can have serious consequences. For example, placing it in the Enforce Deny column will block all incoming traffic to which this ACL Policy is applied. On the other hand, placing it in the Bypass column will allow all incoming traffic (and exempt it from being scrubbed by the WAF!), except for those requests which matched a tag in the Enforce Deny column.
Summary: before using the "all" tag in an ACL Policy, carefully consider its ramifications.
Rate Limits are rules which define the number of requests with certain characteristics that are allowed within defined time frames. When a request is received that exceeds a Rate Limit, a specified action is performed.
The input controls at the top of this page are described here: Policies & Rules Entry Administration. Specific editing of a Rate Limit is described below.
A Rate Limit defines the number of times that requests can match certain conditions within a certain time frame. Once that limit has been reached, subsequent requests matching those conditions within the same time frame will trigger an action.
The matching conditions are specified with the parameters in the "Count by" section and the optional Event. See Matching Conditions below.
After a Rate Limit is defined on this page, it will not be active until it is assigned to one or more URLs. This is done in the URL Maps Document.
By default, a Rate Limit will be enforced for all requests for the URL(s) to which it is assigned.
Enforcement can be further limited to a subset of these requests: see Limiting the scope of a Rate Limit below.
A condition consists of a field and a value. Within a Rate Limit, they play a role like this:
"More than <THRESHOLD> requests with the same <CONDITION-VALUE> <CONDITION-FIELD> sent to <ASSIGNED-LOCATION> within <TTL-PERIOD> will cause <ACTION>."
Example: "More than three requests with the same username argument sent to the login form within one hour will cause the requestor to be banned for six hours."
Note that the <ASSIGNED-LOCATION> mentioned above is included for illustration purposes only. This value is not part of a Rate Limit definition—it is defined in a URL Map.
A condition can be built upon any one of these four categories:
Multiple conditions can be defined within the same Rate Limit. To create a new condition and open it for editing, select "New entry" below the list of conditions.
If multiple conditions are defined, they are evaluated by combining them together with a logical AND. In other words, the cumulative count toward the Threshold will be incremented whenever a request is seen that matches all of the conditions simultaneously. Different combinations of conditions will have separate Threshold counts maintained for them.
Example. A Rule contains two conditions: "Attribute / Remote Address" and "Argument / Username". When the first request is received, an internal counter is created (set to a value of one) for this unique combination of Remote Address and Username. A second request is then received, originating from the same Remote Address and for the same Username; this causes the internal counter to be incremented up to two. A third request is then received from the same Remote Address but with a different Username; this causes a new internal counter to be created (and set to a value of one) for this combination.
Below the list of condition(s), there is another condition named "Event."
By default, this is set to "HTTP request,", which simply means to increment a counter each time a request is received that matches the conditions.
However, if the Event condition is changed to a different value, then the following applies.
In the discussion below, "Count Condition" will refer to the condition (or combination of conditions) defined by the Count by input controls.
"Event Condition" will refer to the optional, additional condition defined by the Event input controls.
Adding an Event Condition changes the evaluation process. An Event Condition is not logically combined with the preceding Count Condition; it is always evaluated separately.
More importantly, adding an Event Condition changes the meaning of the Rate Limit.
If an Event Condition is not defined—in other words, if "HTTP request" is selected—then as discussed above, an internal counter is maintained for each Count Condition value, and incremented each time that value is encountered in a request.
If an Event Condition is defined—in other words, if something other than "HTTP request" is selected—an internal counter is maintained for each Count Condition Value, and incremented each time a new, previously unobserved Event Condition value is encountered in a request.
Therefore, if an Event Condition is defined, the Rate Limit constrains the number of allowable Event Condition values for any given Count Condition value.
So, the evaluation becomes something like this:
"More than <THRESHOLD> <EVENT-CONDITION-VALUE> <EVENT-CONDITION-FIELD>s per any one <COUNT-CONDITION-VALUE><COUNT-CONDITION-FIELD> sent to <ASSIGNED-LOCATION> within <TTL-PERIOD> will cause <ACTION>."
Note that the number of Count Condition values is not being limited here. The limit is on the number of Event Condition values that each Count Condition value is allowed.
Example: Let's say we want to allow an individual user to login from a maximum of two ASNs within one hour. (Perhaps the user is accessing our web application from a coffee shop's WiFi, and then a few minutes later, leaves the coffee shop and begins using the cell network instead.) We want to allow this possibility; however, if we receive requests from the same user originating from three or more ASNs within an hour, we want to treat this traffic more suspiciously. This is not possible merely by specifying two Count Conditions, as described earlier in the "Multiple Conditions" section. If we set up two conditions ("Argument / Username" and "Attribute / Organization") with a Threshold of 2, and assign it to our login form, then this will merely limit the number of times that the user can login from each ASN within an hour. Instead, we can set up one Count Condition ("Argument / Username") and then set up the Event Condition ("Attribute / Organization"). Now the Threshold will apply to the number of Organizations that are observed for each specific Username.
When an incoming request exceeds the Threshold, the Action specified here will occur.
Most of the Actions listed above will not fully exclude an attacker that continues pressing the attack.
Example: Access to a login form is rate-limited to three requests per minute. An attacker tries to brute-force the login, and sends 60 requests per minute. The Rate Limit allows the first three requests, but then blocks the next 57 requests with a 503 error. However, after the minute has passed, the Rate Limit resets. The attacker is allowed another three attempts before being temporarily blocked again. This cycle can continue for as long as the attacker wishes. In effect, the Rate Limit is not preventing the attack; it is merely slowing it from 60 attempts per minute down to three attempts per minute.
The Ban action can be used to block (or take some other Action in response to) a Rate Limit violator for an extended period of time.
Example: As described above, a Rate Limit is created to allow three requests per minute, with an Action of 503 Service Unavailable. However, an additional Rate Limit rule is also defined: nine requests per three minutes, with an Action of Ban. The Ban has an Action of 503 Service Unavailable, and a duration of one hour. URL Maps allow for multiple Rate Limits to be assigned to a single URL. Thus, both of the above rules can be assigned to the login form. Now an attacker tries to brute-force the login form, sending 60 requests per minute. The first three requests are allowed. The next six requests are blocked (and a 503 error is issued) by the first Rate Limit. The tenth request triggers the second Rate Limit, and the Ban occurs. For the next hour, the attacker's requests will be blocked with a 503 error.
Second example: A hostile bot receives a bot challenge, which it fails. Curiefense will block the request. If the bot keeps re-submitting its request, it will continue to fail the challenges. However, each time the bot tries again, Curiefense has to issue a new challenge . To solve this problem, a second Rate Limit is created with a Ban action. Now a persistent bot will simply be Banned, saving Curiefense the overhead of issuing continuous challenges.
Note that when setting up a Ban, the most common choices for its Action are to deny the violator's requests (via 503 Service Unavailable, Response, or Redirect). However, you can also choose Tag Only (to observe the violator's actions during the ban period), Challenge (to verify that the violating activity is not being done by bots), or Header (to mark the requests for further scrutiny by the backend).
By default, an active Rate Limit rule will be enforced upon all incoming requests targeting URLs to which this rule has been assigned.
To change this behavior, you can add Include and/or Exclude parameters. These define the portion of the incoming traffic stream that will be evaluated for possible violation of the Rate Limit. In other words, they limit the scope of the Rate Limit's enforcement:
The Include filter will limit enforcement to requests matching its parameters. All other requests in the traffic stream will not have this Rate Limit enforced upon them.
The Exclude filter will exempt requests from enforcement that otherwise would have been subject to it.
(Internally, Curiefense evaluates Exclude parameters first, and then Include parameters.)
To add one or more filters, select New entry, define the parameters, then select the "+" button. If more than one Include filter is specified, they are combined with a logical AND.
The input controls at the top of this page are described here: Policies & Rules Entry Administration. Specific editing of a Tag Rules List is described below.
Early in the traffic evaluation process, Curiefense assigns Tags to an incoming request. Subsequently, the Tags can be used to make decisions about how the request is processed. After processing, a request's Tags remain associated with it, and they are available for display in the Access Log.
This page allows you to administer Tag Rule Lists, which are combinations of user-defined Tags and the criteria for assigning them to requests.
Each Tag Rule List consists of:
Match conditions: Definitions of possible characteristics that a request can match (e.g., a list of IP addresses that it might originate from), plus one or more logical operators to use when evaluating the match.
One or more Tags to assign when a match occurs.
An Action to apply to the request.
If the Action defined here is Tag Only or Header, then the request will undergo further processing after the Tags are assigned. The post-processing actions that are performed as a result of the Tag assignments are administered in ACL Policies and Rate Limits.
For each incoming request, Curiefense will evaluate all active Tag Rule Lists. A single request will receive Tags from all Lists which match it.
The default Action for a Tag Rules List is Tag Only. This means that the specified tag(s) will be applied, and the traffic evaluation process will continue.
A related Action is Header. The specified tag(s) will be applied, and the specified header will be added. Then the traffic evaluation process will continue.
Sometimes the Match Conditions describe a request which should be rejected immediately; if so, there is no need for the complete evaluation process to occur. In this situation, one of the other Actions can be set here, and it will be applied immediately whenever a request meets the Match Conditions.
Note that the Actions defined here are global for their Tags. To define tag-related actions for a set of paths/URLs, set up the Actions within an ACL Policy and then assign the ACL Policy to the paths in a URL Map.
Tag Rule Lists can be either Internet-sourced or self-managed.
Internet-sourced Lists are based upon online sources (e.g., Spamhaus DROP lists). To use an Internet-sourced list, enter its URL into the Source field. For example, to create a list based on the Spamhaus ASN DROP list, you would enter https://www.spamhaus.org/drop/asndrop.txt and select the update now control that will appear. Curiefense will then populate the list automatically.
Self-managed Lists are created manually. The Source field entry will be self-managed
.
Note that Internet-sourced lists are not editable within the interface, because they are obtained automatically; Curiefense updates them every 24 hours (or you can force an immediate update by selecting update now). Typically, these will be Single-Section Lists.
Match conditions are lists of criteria and the logical operators (AND or OR) to use when evaluating them.
Match conditions are combined into sections. An additional logical operator defines the relationship between each section.
Many Tag Rules Lists will have only section. Here's an example.
In the example, the Sections relation toggle is set to AND
. For a single-section list, this toggle is ignored.
Within each section, there is an additional logical operator, shown at the beginning of each list entry after the first. This is used when evaluating the criteria within the list:
OR
means the Tags will be attached to, and the Action taken for, each request that matches any of the entries in the list.
AND
means the Tags will only be attached to, and the Action taken for, requests that match all of the entries in the list.
This operator can be toggled by selecting it.
To add a match condition, select the add control ("+") at the bottom of the list. The following dialog will appear.
For most of the categories (IP Address, Method, etc.), the dialog will appear as it is above. Individual entries can be added by entering their value into the first text box, and an annotation (a label for display within the Curiefense interface) in the second text box, then selecting the Add control.
Multiple entries can be made at once, with each entry on a separate line. Each line contains the value, plus a pound sign (#) followed by the annotation. Example:
Selecting the Add control would then produce the following:
For some categories, one entry can be made at a time, with no annotations.
Once created, these entries cannot be edited. If one needs to be modified, remove it and re-create it.
Here are some sample entries for the various categories. Notice that boolean operators are available.
Match criteria are case-insensitive.
Match conditions can be combined into multiple sections. To add a section to an existing Tag Rules List, select Create new section.
Here's an example:
Each additional section works the same as the initial section. However, a multiple-section list also includes a logical operator for the relationship between the individual sections. It is shown between the sections, and can be changed by toggling the Sections Relation control on the left.
In the example above, this is AND
. Therefore, a request will receive the tag of internal
if it matches any of the IPs in the first section, AND
it also contains one of the HTTP methods specified in the second section.
Here are some examples of sending API requests to Curiefense using curl.
This list is not meant to be exhaustive, and might not reflect recent changes to the API. For current and canonical information about API operations and data structures, the is recommended.
Get the detailed list of existing configurations:
Retrieve a complete configuration:
Create a new configuration, name is in the posted data:
Create a new configuration, name is provided and overrides posted data:
Update an existing configuration:
Delete a configuration:
Clone a configuration, new name is in POST data:
Clone a configuration, new name is in the URL:
Get all versions of a given configuration:
Retrieve a specific version of a configuration:
Create a new version for a configuration from an old version:
Retrieve the list of existing documents in this configuration:
Get a complete document:
Get a given version of a document:
Retrieve the existing versions of a given document:
Create a new complete document:
Update an existing document:
Delete/empty a document:
Create a new version for a document from an old version:
Retrieve the list of entries in a document:
Retrieve an entry from a document:
Get the list of existing versions of a given entry in a document:
Get a given version of a document entry:
Create an entry in a document:
Update an entry in a document:
Delete an entry from a document:
Retrieve the list of available blobs:
Retrieve a blob:
Create a new blob:
Replace a blob with new data:
Delete a blob:
Retrieve the list of versions of a given blob:
Retrieve the given version of a blob:
Create a new version for a blob from an old version:
The Access Log displays requests that were received in the specified time period.
By default, this page shows all requests in the time period. To change the time period, use the controls at the top right of the window. You can also zoom into a subset of the time period currently being shown, by dragging the cursor across the columns in the graph. The controls above the graph define its granularity.
To filter the display, type a search string into the Search box. For example, to see only those requests that include the substring "script", enter it into the box.
To search for (or exclude) the value of an entire parameter, it is often faster to hover the cursor over an existing request with that value. For example, to show all requests originating from IP address 13.212.190.213
, you could manually enter that address into the Search box. Or, find an existing request with that value and hover the mouse over it. A "Filter for value" button will appear; selecting it will create the filter for you automatically.
More powerful filtering capabilities are available immediately below the Search box, by selecting Add filter and manually constructing one or more filtering criteria.
The access log display will change as filters are constructed and edited. To remove all filters, select Reset search at the top of the graph.
It's helpful to spend a few minutes experimenting with these filtering capabilities. You can quickly drill down through large swaths of traffic, discovering events and patterns that can reveal many insights about your traffic. This is helpful when constructing and fine-tuning security policies, especially during attacks.
The primary display shows a summary of each request. To view more information about a request, click on the twirl control (>) at the beginning of its listing. The display will expand to show its full details.
All the details of the request are shown. Hovering the cursor over a parameter, as shown for the headers.request_method
example above, shows controls where you can easily construct a filter for it.
Within the expanded display, the tag
field can be especially useful.
Selecting the API option in the left sidebar will open the window shown above (by default, at ).
Configurations
Documents
Entries
Blobs
A Configuration is a set of Blobs and Documents. A Document is a set of Entries.
All of these data structures can be edited via API:
A Document is a file treated as a JSON list of entries.
An entry is a JSON dictionary with an id
field. The id
field value must be unique inside the document, and must be a valid part of an URL.
A Blob is a file treated as binary data.
The Curiefense API has the following namespaces:
configs (for manipulating Configurations)
db (for accessing persistent key value storage)
tools (for publishing, etc.)
Each namespace contains various endpoints. For example, tools contains five:
Swagger is a useful way to experiment with the API. For example, selecting configs will display a list of endpoints. If you select this one:
... and then select the Try it out button, followed by the Execute button, this will be the result:
This allows you to interact with the API, try different commands, and see what responses will be generated.
As shown in the example above, Swagger will include sample curl commands for each namespace and endpoint. The commands can be copied and pasted for use elsewhere.
For some endpoints, arguments need to be supplied. Swagger will create defaults/samples, and provide input controls for them, as in this example:
Here a sample payload has been created, and is being displayed for editing. After it is edited, selecting the Execute button will display the responses that are generated.
Out of the box, Curiefense stores metrics using , and provides dashboards and alerts via .
As the name suggests, this page allows you to publish a new or revised Configuration to the cloud, or revert to a previous version.
To do so, follow these steps:
In the pulldown on the top left, select the Configuration.
Below it is the Version History: a list of Configurations, with the most recently edited version at the top. If you wish to publish your most recent edits, ensure that the top entry is selected. If instead you wish to revert to a previous entry, find it in the list (using the View More option if necessary) and select it.
On the right is a list of Target Buckets. The default buckets for this branch (which are defined in ) should be selected already. If different buckets are needed, select them instead.
Select the Publish Configuration button on the top right.
This page displays the current System Database in a JSON editor. These settings are used to populate the interface for .
The settings are:
buckets: the complete list of buckets to which a Configuration can be pushed.
branch_buckets: the default list of buckets for each branch. When a Configuration is published, the default buckets for the branch will be initially selected in the Publish Configuration interface (but they can be changed before publishing).
Includes all requests in the evaluation that contain one or more on this list (unless they match an Exclude parameter). If this list is empty, all requests will be included.
This shows all the that were assigned to this request. It can be helpful in understanding how Curiefense evaluated this request, and the decisions that it made.
This displays the API visually using . For production use, can be used; sample curl calls for the various endpoints are available within Swagger.
As discussed , Curiefense's data is stored within:
Each time a Configuration is modified, a new version is created. A Configuration can be .
In a standard installation, the Grafana dashboards are accessible at . The default username and password are admin
and admin
.
Constraint
Meaning
Max Length
The maximum allowable length of a header, cookie, or argument.
Max Count
The maximum number of headers, cookies, or arguments allowed.
Ignore Alphanumeric input
When this is selected, the WAF will not inspect requests that only contain alphanumeric characters. This reduces computational overhead by not evaluating benign requests. (Hostile requests such as SQLi, XSS, etc., will contain some non-alphanumeric characters.)
Field
Value
Parameter
The parameter whose value will be compared to the Matching Value. This can be provided as a specific Name (e.g., sessionid), or as a Regex to match multiple parameters (e.g., user_.+). Note that a Name will be marked with a capital "A", while a Regex will be marked with "</>".
Matching Value
A regex pattern. If a parameter's value matches it, the parameter will be exempted from WAF Rule filtering. If it does not match, the Restrict? option becomes relevant.
Restrict?
If a parameter does not match the Matching Value, and Restrict? is selected, then the request is blocked. If Restrict? is not selected, then the Exclude WAF Rule option becomes relevant.
Mask?
Some requests might contain private data which should not be saved to a traffic log. Parameters which match the Matching Value and for which Mask is set will be masked / hashed when they are written to the logs.
Exclude WAF Rule
A parameter which fails its Matching Value comparison, and for which Restrict? is not selected, will be filtered by all WAF Rules except the ones whose IDs are listed here. (For example, some WAF Rules filter out special characters; if a certain parameter can legitimately contain these characters, it would make sense to exempt that parameter from those specific filters .) It is also possible to always exempt a parameter from specific WAF Rules:
List the rule IDs here
Ensure that Restrict? is not selected
And specify a Matching Value regex pattern that the parameter would never match.
Field
Value
Name
The name of the URL Map for internal use.
Matching Names
A regex for the subdomain(s) and/or domain(s).
Field
Value
Name
A descriptive label for use within the interface.
Match
An expression for the path, expressed as PCRE (Perl Compatible Regular Expressions). See warning below.
WAF
The WAF Policy applied to this path. Its name will be displayed in green if it is active; if displayed in red, it is currently disabled.
ACL
The ACL Policy applied to this path. Its name will be displayed in green if it is active; if displayed in red, it is currently disabled.
RL
The number of Rate Limits assigned to this resource.
Action
Comment
Enforce Deny
Blocks the request. This is a useful way to quickly filter out, with minimal computing overhead, large numbers of requests that are obviously hostile or otherwise unwanted.
Bypass
Allows the request, and bypasses/exempts it from subsequent evaluation by the WAF.
Allow Bot
Passes the request to the WAF for further inspection without triggering a bot challenge (the process by which non-human traffic is identified and blocked). An example usage is to allow search engine spiders.
Deny Bot
If the requestor has not previously been verified to be human, a bot challenge will be issued. If the challenge is passed, the request will continue in the evaluation process. Otherwise the request is blocked. A common use of this column is to add the "all" tag, which means to identify and block all bots that weren't previously Allowed or Bypassed.
Allow
Passes the request to the WAF for further inspection.
Deny
Blocks the request.
Field
Value
Name
A name that will be used within the Curiefense interface, and will also be used to create a tag that will be assigned to requests which trigger the Rate Limit. It is recommended that the name summarizes the rule; for example, a rule with a Threshold of 5 and a TTL of 60 could be named "Rate limit rule 5/60".
Description
A description that will be used within the Curiefense interface.
Field
Value
Threshold
The maximum number of allowable requests within the specified TTL. Subsequent requests within the TTL will trigger the Action.
TTL
Time to Live: the period (specified in seconds) within which the Threshold is enforced.
Field
Result
Header
All requests with the same value for the specified header will be counted together toward the Threshold.
Cookie
All requests with the same value for the specified cookie will be counted together toward the Threshold.
Argument
All requests with the same value for the specified argument will be counted together toward the Threshold.
Attribute
All requests with the same value for the specified attribute will be counted together toward the Threshold.
Action
Meaning
503 Service Unavailable
The request will be blocked and the requestor will receive a response of "503 Service Unavailable".
Challenge
For a browser-based web application, a bot challenge will be issued to verify that the requestor is a human using a browser, and not a bot using a headless browser or emulator. If the challenge is failed, the request is blocked.
Tag Only
The request will not be blocked; it will merely be tagged with the Rate Limit's name, for subsequent viewing in the Access Log and other places. This Action is useful for testing new Rate Limit rules without actually affecting incoming traffic.
Response
Blocks the request, and responds with a custom error code (0-999) and response body.
Redirect
Blocks the request with a custom error code, and redirects the requestor to a specified URL. For example, the URL might be a page that says, "Your activity appears suspicious, and your access has been restricted. Contact support if you think this decision was made in error."
Ban
Blocks the requestor for the specified amount of time. See further discussion below.
Header
Does not block the request, but adds headers to it (indicating the Rate Limit rule name and the threshold) for receipt and evaluation by the user's backend.
Interface
URL
Management UI
http://curie.demo:30080/
Swagger API
http://curie.demo:30000/api/v1/
Echo web server
http://curie.demo:30081/
Grafana
http://curie.demo:30300/
Container Name
Purpose and Functionality
curieproxy
Envoy built with our modules
curiesync
ensures configurations are always in sync with latest policies and rules changes
confserver
API server to manage configuration
uiserver
UI Management Console
echo
Dummy web server for testing
logdb *
stores access log
grafana *
dashboards
prometheus *
stores time series metrics
redis *
Synchronizes session and rules across deployments and Envoy containers
(*) You may replace these containers with your own if desired.
Field
Meaning
Name
A description that will be displayed within the Curiefense interface.
Active
By default, the Tag Rule List will be applied to incoming requests. To prevent this, unselect the checkbox.
Sections Relation
For Lists with multiple sections, this is the logical relation to use when evaluating the Match Conditions in the sections.
Tags
One or more Tags (separated by spaces) that will be assigned to requests if the match conditions are fulfilled. Example: internal team-devops
.
Source
The source of the match conditions. See discussion below.
Action
The action to take for requests that fulfill the match conditions. See discussion below.
Notes
An optional field for including additional information.
Action
Meaning
Tag Only
Apply the specified Tag(s), and continue processing the request.
Header
Apply the specified Tag(s) and add the specified header to it for receipt and evaluation by the user's backend. Then continue processing the request. To specify this parameter, separate the header and value with a colon. Example: X-CustomHdr: Custom-Value
503 Service Unavailable
The request will be blocked and the requestor will receive a response of "503 Service Unavailable".
Challenge
For a browser-based web application, a bot challenge will be issued to verify that the requestor is a human using a browser, and not a bot using a headless browser or emulator. If the challenge is failed, the request is blocked.
Response
Blocks the request, and responds with a custom status code (0-999) and response body.
Redirect
Blocks the request with the specified status code, and redirects the requestor to a specified URL. For example, the URL might be a page that says, "Your activity appears suspicious, and your access has been restricted. Contact support if you think this decision was made in error."
All notable changes to this project will be documented in this file. This project adheres to Semantic Versioning.
[curieconf] Enhance API to allow requesting specific properties of documents
[curieproxy] Add continent data and more country data
[curieproxy] Add geolocation for requests when data is present
[curielogger] Add config file structure
[curieproxy] Add continent data and more country data
[ui] Added 3 categories to tags (legitimate, malicious, neutral)
[curieconf, ui] Added mask boolean field to WAF policy Cookie/Header/Argument
[ui] Added is-single-input-column prop to ResponseAction component
[ui] Added more tests to DocumentSearch component (98%+ Coverage)
[ui] Added routing to document editor page per the following schema: /config/branch/doc_type/doc_id
[ui] Added search page for documents
[ui] Added units suffix (seconds) to TTL in RateLimitsEditor.vue
[ui] Added units suffix (seconds) to TTL in FlowControlEditor.vue
[ui] Added ace json editor to DB editor screen
[ui] Added default textarea json editor when failing to load ace json editor
[ui] Added indicator for missing data in DocumentEditor.vue
[ui] Added indicator for loading data in DocumentEditor.vue
[ui] Added indicator for missing data in DBEditor.vue
[ui] Added indicator for loading data in DBEditor.vue
[ui] Added scrollbar to Burma’s dropdown menu item with max height of 12rem
[confserver] Added an example flow control document to bootstrap data
[confserver] Added basic tags to bootstrap data
[confserver] Add geolite2 city
[curielogger] elasticsearch index: add timestamp field
[images] add fluentd image
[helm] add fluentd support
[helm] add elasticsearch support
[docker-compose] add ELK containers
[helm] deployments: add support for google storage buckets
[helm] deployment: add variables to disable parts of the chart
[curieproxy] add missing lua dependency
[curielogger] Added alpha fluentd support
[curielogger] Added logstash support
[curielogger] Added elasticsearch dumb client
[curieproxy] Added envoy-1.16.2 binary with symbols for lua
[curieconf] Added in-place entry edition in curieconf (server, client, CLI)
[curietasker] Added 'update_and_publish' task
[curietasker] Added 'publish' task
[docker-compose] ELASTICSEARCH_URL added to curielogger entry in compose yaml
[curieproxy] tests branch configuration added
[curieconf] tests branch configuration added
[ui] added links to side menu
[curieproxy] benchmark and tests added
[curieproxy] added debug message for Rust Sig
[curieproxy] rust calls with debug -- :add instead of .add
[curieproxy] debug messages added
[curietasker] log info added for remote debugging
[curietasker] adding jsonschema to setup.y install_requires
[curieproxy] debug added to tagging matching points
[curielogger] Update deployment configs/files
[helm] Update logstash pipeline configuration
[curielogger] Update cflog format and add pg back
[curielogger] Update curielogger for new format
[docker-compose] update env variables for curielogger
[helm] update chart following changes in curielogger
[bootstrap-script] updated version to 1.2.10
[bootstrap-script] Updated axios version to avoid security vulnerability
[confserver] update bootstrap waf signatures
[confserver]: update profiling lists for confdb bootstrap bundle
[ui] Improved performance for EntriesRelationList prop validator
[ui] Replaced all download functions with a new downloadFile function in Utils
[curieconf] Enhance api to allow requesting specific properties of documents
[ui] Use the new enhanced api to drastically improve loading time of “Search Document” page
[ui] Added scrollbar to Burma’s dropdown menu item with max height of 12rem
[ui] Fixed download button in AccessLog component
[ui] Changed colors of JSON Editor menu and mode selector to greyscale
[ui] Hiding "Clear all sections" button in tagrules when source of list is not "self-managed"
[ui] Fix indentation of WAF policy editor and WAF signature viewer content
[ui] Fix bug preventing docs from being downloaded
[ui] Fix name of all download buttons (removed unneeded 'x')
[ui] Now using new document defaults for missing props of documents
[curielogger] Removed postgres support in favor or elasticsearch
[ui] Flow Control - Removed the regex symbol next to Method, Host, and Path
[curielogger] removed addition of hardcoded path to logstash url
[curieproxy] removed reference to bt
[curieproxy] schema removed, waf sig corrected
[curieproxy] Removed old unused schema files
[confserver] Removed unneeded params from bootstrap flow control action prop
[ui] Removed unneeded module from dependencies
[ui] Removed inline styling, !important, tag
[ui] Added main.scss containing general classes
[ui] Removed unneeded whitespace
[ui] Improvements to the ui - general alignment of components throughout the system
[ui] Removed deprecated html tag
[curieproxy] removed logs
[curieproxy] hscan.lus removed
[curieproxy] globals.WAF removed
[ui] Removed unnecessary card wrapper
[ui] Removed conversion of old entries + relation data structure to the new structure, should be received from server in correct new structure
[curietasker] return false removed
[curietasker] removed some more debug prints
[curieconf] remove references to now removed mongobackend package
[curieconf] Removed outdated mongo backend
[curieconf] Removed any loose API calls
[curieconf] Removed duplicated API call in AccessLog.vue
[curielogger] Fix indexpatter for non data stream environments
[deploy, docker-compose] fix use of fluentd
[deploy] deploy-dev.sh: fix log check step
[currielogger] elasticsearch mapping: fix types for arrays
[curielogger] omit keys in upstream when there is not upstream (fixes ES)
[ui] fix jest global window
[curielogger] fix json names
[curielogger, helm] elasticsearch: deployment fixes
[ui] Fixed Bug - When creating multiple documents in a row throws an error
[curielogger] Fixed missing fields in request attribute structure
[curieproxy] waf exclude restrict bug fixed
[curieproxy] acl bug fixed
[curieproxy] more debug messages -- bad data type number error fixed
[ui] Fixed download button in AccessLog component
[curieproxy] exclude sig new format bug fixed
[ui] waf reason UI fixed
[images] grafana image: fix permissions for provisioned dashboards & datasources
[ui] Fix indentation of WAF policy editor and WAF signature viewer content
[ui] Fix bug preventing docs from being downloaded
[ui] Fix name of all download buttons (removed unneeded 'x')
[ui] Fix bug where first load of document editor page would not load docs correctly
[confserver] Fixed wrong bucket name in bootstrap data (duplicated prod instead of prod + devops)
[ui] Fix bug where first load of document editor page would not load docs correctly
Much of the Curiefense interface focuses on configuration for:
The detection and mitigation of hostile requests.
The detection and mitigation of hostile behavior of requestors.
The challenge process is different. It is built into Curiefense, and provides a third approach to security. It mitigates threats based on the requestor's identity, environment, and behavior.
Bot challenges are included in the Premium version of Curiefense.
When Curiefense receives the first request from a previously unknown traffic source (below described as the "user") for a browser-based web application, this is the typical process that is followed.
Curiefense challenges the user's browsing environment. Curiefense uses a variety of proprietary, multi-faceted techniques to verify that this requestor is a human using a browser, instead of a bot using a headless browser or emulator.
The user’s browser is subjected to several dozen tests, verifying the features known to be supported by that browser. This includes hidden canvases, video and audio in various formats, WebRTC and other advanced networking protocols, screen resolution, and more.
The browser is subjected to an invisible “attack”: subtle errors are injected into the environment, and the browser engine’s reactions are captured and analyzed. Curiefense verifies that the exceptions and error messages are those which should be generated, if the browser is what it claims to be. (It is very difficult for threat actors to spoof this behavior using headless browsers and emulators, since there is an infinite number of possible errors to which any browser can be subjected, and threat actors need to replicate the actual reactions for each possible input.)
The above process only takes milliseconds, and it is completely transparent to the end user.
Once a browser has passed these tests, Curiefense signs it cryptographically. This signature accompanies all subsequent activity.
If the challenge is not passed, the request is suspected to be a bot, and another challenge is issued. This process continues until a challenge is passed, or a threshold is reached (e.g., via a Rate Limit) to ban the requestor.
If the challenge is passed, the browser's session is authenticated, and the browser receives cookies from Curiefense.
The browser then automatically resubmits the original request, but this time, the cookies are included. The user is granted access to the requested URL, resources, etc.
Subsequent requests will also include the cookies, and thus, they are not challenged.
This process happens quickly (in a few milliseconds), and is invisible to the user.
The process described above is the active challenge process. Out of the box, this is the challenge process that Curiefense uses.
We recommend that whenever possible, users also enable passive challenges.
Passive challenges add three additional benefits:
They enable biometric behavioral profiling: a much more powerful means of identifying automated traffic. More on this below.
In some situations, active challenges can interfere with certain metrics such as those provided by Google Analytics. (The initial referrer information is lost.) If this is a problem, active challenges can be disabled. In this situation, passive challenges can provide effective bot protection instead.
When caching is being done by a CDN, active challenges will not occur for pages being served from the cache. Passive challenges are necessary for Curiefense to perform bot detection in this situation.
If possible, we recommend that users use both active and passive challenges.
With Biometric Bot Detection, Curiefense continually gathers and analyzes stats such as client-side I/O events, triggered by the user’s keyboard, mouse, scroll, touch, zoom, device orientation, movements, and more. Based on these metrics, the platform uses Machine Learning to construct and maintain behavioral profiles of legitimate human visitors. Curiefense learns and understands how actual humans interact with the applications and services it is protecting. Continuous multivariate analysis verifies that each user is indeed conforming to expected behavioral patterns, and is thus a human user with legitimate intentions.
Using this approach, Curiefense bot detection accuracy is not only high, it is also robust and resistant to reverse-engineering by threat actors. Behavioral profiles are constructed based on private analytics data, and threat actors have no realistic way of obtaining this information.
This is an important reason why we recommend that all users enable Passive Challenges if it is possible to do so. Biometric Behavioral Profiling provides much more robust detection of automated traffic than is possible without it.
Implementing Passive Challenges is simple. Place this Javascript code within the pages of your web applications:
The code snippet can go into the header or at the end of the page. The best practice is to place it within the header. This ensures that subsequent calls contain authenticating cookies.
(This matters for the first page served to a visitor. Subsequent pages will already have the authenticating cookies to include with their requests.)
Most users set up the code snippet as a tag within their tag manager. This makes it simple to install it instantly across their entire site/application.
If desired, the script code can include async
and/or defer
attributes:
These usually are not necessary, and their effect will depend on the placement of the script within the page. Their use is left to your discretion.
To test the implementation, use a browser to visit a page containing the Javascript snippet. Once it runs, the browser should have a cookie named rbzid.
There are two primary situations where users sometimes want to disable Active Challenges:
When a user needs site analytics to correctly reflect all referrers. (Active Challenges can interfere with this.)
For API endpoints. Active Challenges are designed to verify the client's browser environment; for most API calls, there is no browser environment to verify.
Other than those situations, Active Challenges can be very beneficial.
We recommend that you keep Active Challenges enabled if possible. They automatically eliminate almost all DDoS traffic, scanning tools, and other hostile bot traffic.
If you wish to turn off Active Challenges, remove all tags from the "Deny Bot" column within ACL Profiles.
If you have not enabled Passive Challenges (and successfully tested them), disabling Active Challenges is not recommended.
When an incoming request is received, Curiefense generates internal tags and assigns them to it.
Some tags are assigned early, and are used to make decisions about how the request is handled. For example, if a request's IP is found on the Spamhaus DROP list, it might be assigned a tag of "spamhaus". Then an ACL Policy might block the request because it contains that tag.
Some tags can be generated during processing; they reflect the decisions that were made. For example, a request that was blocked because it violated a Rate Limit will be assigned a tag containing that Rate Limit's name. The tag will be shown in the Access Log.
Some tags are defined by the user, while others are generated automatically by Curiefense.
Tag Rules are user-defined lists of criteria with one or more associated tags. Requests which match the criteria will be assigned those tags.
A Tag Rules List can be based on an external list (e.g., the Spamhaus DROP list), or a user-defined custom list (e.g., a list of IP addresses used by the internal QA team).
Many tags are generated automatically by Curiefense. Examples:
Every request receives a tag of "all".
Every request receives several tags according to its source (the IP address, geolocation, etc.)
Every request receives two tags for the URL Map that it matched (both at the domain level and at the Path Map level).
Requests which violate a security policy or have other problems, receive tags with descriptive names (e.g., the name of the policy that was violated).
When tag names are generated from underlying values (IP addresses, security rule names, etc.), hyphens will replace spaces and special characters.
Sometimes a request will get two separate tags that seem to be redundant. For example:
urlmap-default-entry
urlmap-entry-default
When a URL Map is matched with a request, a tag is generated for the URL Map itself, and for the Path Map that was used. If the names are similar (which is often true for default values, as in the example), then the tags can appear to be redundant.
This page displays previous versions of configurations, and allows you to revert/restore the system to any saved configuration.
To do this, hover the cursor over the desired configuration. The "Restore Version" button will appear, as shown above.
Select this button. Once the process is complete, publish. Curiefense will push the selected configuration out to all deployments.
Curiefense evaluates incoming traffic in a multi-stage filtering process. An HTTP/S request which passes all security tests will be forwarded to the backend.
When constructing its security posture, it can be helpful to understand the filtering stages. They are:
Tag Rules: Curiefense assigns automatically-generated tags and user-defined tags to the requests. During this process, requests will be blocked immediately if they match a Tag Rules List that has a blocking action defined for it.
Session Flow Control enforcement.
Rate Limit enforcement.
ACL Policies enforcement.
WAF Policies and WAF Rules enforcement.
Transmission of request to the backend.
Containers are built from recipes contained incuriefense/images/
. Descriptions of the various images are below.
Several tag formats are used.
Images can also have two-part tags to identify what is in the image. The parts are:
the output of git describe --tag --long --dirty
which contains the latest git tag, number of commits since last tag, and abbreviated current commit hash
the shortened hash of the git tree HEAD:curiefense/
where Docker images are stored. It helps to see quickly whether image sources from two different commits are identical.
A REST API server to read, write, and maintain versioning of Curiefense's configuration.
Flask is the web interface. Git is the storage engine for historical and versioned configuration. Nginx serves as the frontend for the Flask web application.
Secrets:
If an S3 bucket is used as a synchronization mechanism between confserver
and curieproxy
instances (this is the default with Helm deployments), then this container requires credentials to access it.
In Docker Compose environments, S3 credentials are defined in deploy/compose/curiesecrets/s3cfg
before deployment, then mounted in /var/run/secrets/s3cfg
.
In Helm environments, S3 credentials are defined in a local file and deployed to the cluster. They are expected to be in a Secret object called s3cfg
, in the same namespace as confserver
, which is mounted to make credentials available in /var/run/secrets/s3cfg/s3cfg
.
Network details:
Port 80 is the configuration API. A Swagger interface is available at endpoint /api/v1/
(reachable at http://localhost:30000/api/v1 in the sample Docker Compose and Helm deployments).
Receives access logs from Envoy (curieproxy
images) over gRPC, and does the following:
Pushes logs into the PostgreSQL server (logdb
)
Aggregates metrics
Serves metrics over HTTP port 2112 for the Prometheus scraper.
Network details:
Port 9001 receives logs from Envoy over GRPC
Port 2112 exposes Prometheus metrics over HTTP
Periodically (every 10 seconds) polls the bucket located at CURIE_BUCKET_LINK
, and extracts the active configuration to /config
, which is shared with curiefense
.
Secrets: the same as described in confserver
, above.
Network details:
No exposed network service
Grafana provides visualization for the metrics stored in Prometheus, and sends alerts based on anomaly thresholds.
Its datasource is prometheus. Its basic dashboards are in the dashboards
directory.
Customization options are described at https://hub.docker.com/r/grafana/grafana/.
Secrets
Default user: admin
Default password: admin
These can be changed upon the first connection.
Network details:
Port 3000 allows access to the Grafana UI over http (reachable at http://localhost:30300 in the sample Docker Compose and Helm deployments).
PostgreSQL server that stores access logs.
Two accounts are used:
postgres
has write access, is used by curielogger
.
logserver_ro
has read-only access, is used by curielogserver
.
Secrets:
The password for the logserver_ro
account is passed in a file whose path is contained in the POSTGRES_READONLY_PASSWORD_FILE
environment variable.
The password for the postgres
account is passed in a file whose path is contained in the POSTGRES_PASSWORD_FILE
environment variable.
Network details:
Port 5432 for PostgreSQL access
Prometheus scrapes metrics from Envoy, curielogger
, and Prometheus itself. These are defined in curiefense/images/prometheus/prometheus.yml
.
curielogger
metrics are exposed as follows:
curiemetric_http_request_total
: total number of requests.
curiemetric_request_bytes
: total inbound (request) bytes.
curiemetric_response_bytes
: total outbound (response) bytes.
curiemetric_session_details_total
: Static labels are a fixed set of labels created for each request, such as "method", "path", "geo", etc.
curiemetric_session_tags_total
: this metric stores the "dynamic" labels: tags and labels created dynamically on a request basis, and per context. For example, while the "blocked" label is set to 0 or 1 for each request, an actual blocked request may carry additional tags such as the block reasons and origin.
Network details:
Port 9090 allows access to the Prometheus user interface over HTTP
Redis is accessed by curieproxy
, and is used to synchronize Curiefense's advanced rate limiting and session control mechanisms.
Network details:
Port 6379 receives Redis client queries
Serves the user interface. A Vue js app developed as single page app with NodeJS and serves the management console UI.
The UI displays Curiefense's configuration for editing. API calls for configuration are routed to confserver
by the Nginx inside the container or Pod. Nginx also used to serve the static parts of the UI such as HTML, CSS and JS.
Secrets: This image will enable TLS on the nginx server if a TLS certificate and key are provided:
For Kubernetes (e.g. Helm) deployments, the certificate is expected at /run/secrets/uisslcrt/uisslcrt
and the key at /run/secrets/uisslkey/uisslkey
For Docker Compose deployments, the certificate is expected at /run/secrets/uisslcrt
and the key at /run/secrets/uisslkey
Network details:
Port 80 allows unencrypted access to the user interface (reachable at http://localhost:30080 in the sample Docker Compose and Helm deployments)
Port 443 allows TLS-encrypted access to the user interface, if TLS certificates have been supplied during the deployment (reachable at http://localhost:30443 in the sample Docker Compose and Helm deployments)
Acts as a reverse proxy to TARGET_ADDRESS:TARGET_PORT
.
Filters traffic according to the active configuration.
Sends access logs over GRPC tocurielogger
.
Uses a custom-built Envoy binary, compiled with symbols needed by Lua. The custom Envoy compilation is described in curiefense/curieproxy/README.md
.
Network details:
Port 80 receives unencrypted traffic from users, which will be proxied to TARGET_ADDRESS:TARGET_PORT
(reachable at http://localhost:30081 in the sample deployments)
Port 443 receives TLS-encrypted traffic from users, which will be proxied to TARGET_ADDRESS:TARGET_PORT
(reachable at http://localhost:30444 in the sample docker-compose deployment)
Port 8001 is the Envoy administration interface
Simple http server that displays Echo
.
Network details:
Listens on port 5678
Acts as a reverse proxy to TARGET_ADDRESS:TARGET_PORT
.
Filters traffic according to the active configuration.
Sends access logs over GRPC tocurielogger
.
Uses a custom-built Envoy binary, compiled with symbols needed by Lua. The custom Envoy compilation is described in curiefense/curieproxy/README.md
.
In Helm deployments, two EnvoyFilters are defined in curiefense/deploy/istio-helm/chart/charts/gateways/templates/
:
curiefense_lua_filter.yaml
orders Envoy to apply the Lua HTTP filter to incoming requests.
curiefense_access_logs_filter.yaml
orders Envoy to send access logs to curielogger
.
Network details:
Port 80 receives unencrypted traffic from users, which will be proxied to TARGET_ADDRESS:TARGET_PORT (reachable at http://localhost:30081 in the sample deployments)
Port 8001 is the Envoy administration interface
If for some reason you need to rebuild the images, run the following command:
Single Tag
Meaning
test
For testing single images
main
For stable images built from the main branch
Value or Situation
Example tag
(Every request)
all
IP address
ip-192-168-0-2
ASN
asn-1680
Country
geo-canada
URL Map that the request matched
urlmap-default-entry
WAF Rule #100039 was violated.
waf-sig-100039
A Rate Limit (named "Rate limit rule 5/60") is being evaluated.
rate-limit-rule-5-60