Skip to content

Commit

Permalink
Latest updates of community apps
Browse files Browse the repository at this point in the history
  • Loading branch information
walshbm15 committed Jan 10, 2019
1 parent c31dd81 commit e94895c
Show file tree
Hide file tree
Showing 55 changed files with 5,294 additions and 2,156 deletions.
2 changes: 1 addition & 1 deletion README.md
@@ -1,4 +1,4 @@
# Resilient Community Applications
# Resilient Community Applications

This repository contains the source-code for packaged Resilient integrations.

Expand Down
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,11 @@
{
"Comment": "A Hello World example of the Amazon States Language using a Pass state",
"StartAt": "HelloWorld",
"States": {
"HelloWorld": {
"Type": "Pass",
"Result": "Hello World!",
"End": true
}
}
}
@@ -0,0 +1,3 @@
exports.handler = async (event) => {
return event.x + event.y;
};
@@ -0,0 +1,2 @@
def lambda_handler(event, context):
return event.get("x") + event.get("y")
3 changes: 2 additions & 1 deletion fn_aws_utilities/fn_aws_utilities/util/config.py
Expand Up @@ -12,7 +12,8 @@ def config_section_data():
config_data = u"""[fn_aws_utilities]
aws_access_key_id=
aws_secret_access_key=
aws_region_name=us-east-1 # aws region identifier
# aws region identifier
aws_region_name=us-east-1
"""

return config_data
1,405 changes: 706 additions & 699 deletions fn_aws_utilities/fn_aws_utilities/util/customize.py

Large diffs are not rendered by default.

5 changes: 1 addition & 4 deletions fn_bigfix/fn_bigfix/lib/__init__.py
@@ -1,4 +1 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright IBM Corp. - Confidential Information
#
24 changes: 20 additions & 4 deletions fn_bigfix/tests/mock_artifacts.py
Expand Up @@ -348,6 +348,16 @@ def get_artifact_data_2():
'result': False, 'computer_name': u'DESKTOP-TUKM3HF-3'}
])

def get_check_exists_subkey():
return list([{'computer_id': 12315195, 'failure': False, 'resp_time': 0, 'query_id': 1,
'result': u'False', 'computer_name': u'bigfix.test-1'}
])

def get_check_is_folder():
return list([{'computer_id': 12315195, 'failure': False, 'resp_time': 0, 'query_id': 1,
'result': u'False', 'computer_name': u'bigfix.test-1'}
])

def mocked_res_client(*args):

"""Function will be used by the mock to replace resilient client"""
Expand Down Expand Up @@ -418,6 +428,12 @@ def get_bf_computer_by_registry_key_name_value(self, bigfix_artifact_value, bigf
def get_bf_computer_properties(self, bigfix_asset_id):
return self._get_bf_computer_properties()

def check_exists_subkey(self, artifact_value, computer_id):
return get_check_exists_subkey()

def check_is_folder(self, artifact_value, computer_id):
return get_check_is_folder()

@staticmethod
def _get_bf_action_status(bigfix_action_id):
if bigfix_action_id == 123:
Expand Down Expand Up @@ -502,14 +518,14 @@ def __init__(self, *arg, **kwargs):
self.text = get_response_artifact_data(query_id)
test=1
elif arg and "/api/clientquery" in arg[0]:
if "exists file" in kwargs["data"]:
if "exists file".encode() in kwargs["data"]:
self.text = post_response_artifact_query("DeleteFile")
elif "exists process" in kwargs["data"]:
elif "exists process".encode() in kwargs["data"]:
self.text = post_response_artifact_query("KillProcess")
elif arg and "/api/actions" in arg[0]:
if "Delete File" in kwargs["data"]:
if "Delete File".encode() in kwargs["data"]:
self.text = post_response_artifact_remediate("DeleteFile")
elif "Delete Registry Key" in kwargs["data"]:
elif "Delete Registry Key".encode() in kwargs["data"]:
self.text = post_response_artifact_remediate("DeleteRegKey")
elif arg and "/response_text" in arg[0]:
self.text = get_response_text_asset_props(arg[1])
Expand Down
3 changes: 3 additions & 0 deletions fn_bigfix/tests/test_bigfix_client.py
Expand Up @@ -21,6 +21,9 @@ def get_config():
"bigfix_port": "12345",
"bigfix_user": "BigFixAdmin",
"bigfix_pass": "MyPassword",
"bigfix_polling_interval": 30,
"bigfix_polling_timeout": 600,
"hunt_results_limit": 200
})

class TestGetBfComputerProperties:
Expand Down
129 changes: 82 additions & 47 deletions fn_elasticsearch/README.md
@@ -1,13 +1,9 @@
# Fn_ElasticSearch_Query
The ElasticSearch integration allows users of the Resilient Platform to connect to and query an ElasticSearch Database.
# Resilient Integration with Elasticsearch

Users can specify the location of a remote ElasticSearch instance and query this instance for data which is then returned to Resilient for display or use by other functions.
**The ElasticSearch integration allows users of the Resilient Platform to connect to and query an ElasticSearch Database.**

The function takes 3 inputs :
Users can specify the location of a remote Elasticsearch instance and query this instance for data which is then returned to Resilient for display or use by other functions.

+ Index (Optional) --> An index to search for data. Default is searching all indices
+ Doc_Type (Optional) --> An type of document to search. Default is searching all doc_types
+ Query (Required) --> The query we will be submitting

Queries provided to the function must be properly formed to work.
Please review the [ElasticSearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/search-request-body.html) for examples on how to form your query.
Expand All @@ -19,54 +15,93 @@ HTTPS connection with username:password authentication

If you wish to connect to a resource with a self signed cert can provide a cafile as one of the config options.

### Installation
#### Set the following values in the config file (`~/.resilient/app.config`) under the `[fn_elasticsearch]` section:
- [app.config settings:](#appconfig-settings)
- [Function Inputs: Elasticsearch Query:](#function-inputs-elasticsearch-query)
- [Pre-Processing Scripts](#pre-processing-scripts)
- [Post-Processing Script](#post-processing-script)
- [ElasticSearch Query Function Output:](#elasticsearch-query-function-output)
- [Rules](#rules)# Resilient Integration with Elasticsearch

```
## app.config settings

```python
[fn_elasticsearch]
es_datastore_url = <YOUR_URL>
es_datastore_scheme = <https OR http>
es_auth_username = <YOUR_USERNAME>
es_auth_password = <YOUR_PASSWORD>
es_cafile = <PATH_TO_CERT_FILE>
```

To install in "development mode"

pip install -e fn_elasticsearch/

To package for distribution,

python fn_elasticsearch/setup.py sdist

The resulting .tar.gz file can be installed using

pip install dist/<filename>.tar.gz

To uninstall,

pip uninstall fn_elasticsearch

## How to use the function

1. Import the necessary customization data into the Resilient platform after pip installing the function:

resilient-circuits customize

This creates the following customization components:

* Function inputs: `es_doc_type`, `es_index`, `es_query`
* Message Destinations:`fn_elasticsearch`
* Functions:`fn_elasticsearch_query`
* Workflows:`example_elasticsearch_query_from_artifact`, `example_elasticsearch_query_from_incident`
* Rules:`Example: ElasticSearch Query from Artifact`, `Example: ElasticSearch Query from Incident`

2. Update and edit `app.config`:
## Function Inputs: Elasticsearch Query

| Function Name | Type | Required | Example |
| ------------- | :--: | :-------:| ------- |
| `es_doc_type ` | `String` | No | `'logs'` |
| `es_index ` | `String` | No | `'logs'` |
| `es_query ` | `String` | Yes | `'logs'` |


## Pre-Processing Scripts

The workflow `Example: ElasticSearch Query from Artifact` includes a pre-processing script which gathers the input `es_query` from the artifact value and uses that as the query.

The workflow `Example: ElasticSearch Query from Incident` does not use a pre-processing script. With this in mind, to improve the usability of this workflow, 3 example query's are provided for `es_query` to help get up to speed.

## Post-Processing Script

```python

"""
# An Example of the result object
results = {
"inputs": {
"es_query": { "query": { "match_all": {} } },
"es_doc_type": logs,
"es_index" : my_logstore
},
"query_results": [
<elasticsearch-record>,
"success": True / False,
"matched_records": 1000,
"returned_records": 100
}
# Note: The schema of elasticsearch-record; outlined above, will reflect the structure of your data in Elastic itself
"""

if results.matched_records:
noteText = """<b>ElasticSearch Query status</b>
<br> Query supplied: <b>{0}</b>
<br> Total matched records :<b>{1}</b>""".format(results.inputs["es_query"], results.matched_records)

if results.returned_records != 0:
noteText += """<br> Total returned records : <b>{0}</b>""".format(results.returned_records)
incident.addNote(helper.createRichText(noteText))
```

resilient-circuits configure -u
## ElasticSearch Query Function Output

The function returns the results as a Python Dictionary. Here is an example ouput:

```python
results = {
"inputs": {
"es_query": { "query": { "match_all": {} } },
"es_doc_type": logs,
"es_index" : my_logstore
},
"query_results": [
<your_elasticsearch_record_schema>
],
"success": True,
"matched_records": 11000,
"returned_records": 1000
}
```

3. Start Resilient Circuits:
```
resilient-circuits run
```
## Rules

4. Trigger the rule.
| Rule Name | Object Type | Workflow Triggered |
| --------- | :---------: | ------------------ |
| Example: ElasticSearch Query from Artifact | `Artifact` | `Example: ElasticSearch Query from Artifact` |
| Example: ElasticSearch Query from Incident | `Incident` | `Example: ElasticSearch Query from Incident` |
@@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-
# (c) Copyright IBM Corp. 2010, 2018. All Rights Reserved.
# pragma pylint: disable=unused-argument, no-self-use,
# pragma pylint: disable=unused-argument, no-self-use, line-too-long
"""Function implementation"""

import logging
import json
from ssl import create_default_context

from elasticsearch import Elasticsearch
from resilient_circuits import ResilientComponent, function, handler, StatusMessage, \
FunctionResult, FunctionError
from elasticsearch import Elasticsearch

from fn_elasticsearch.util.helper import ElasticSearchHelper


Expand Down Expand Up @@ -76,29 +77,27 @@ def _fn_elasticsearch_query_function(self, event, *args, **kwargs):
es = Elasticsearch([ELASTICSEARCH_URL],
verify_certs=False,
cafile=ELASTICSEARCH_CERT)
except:
raise FunctionError("Encountered error while connecting to ElasticSearch")
except Exception as e:
raise FunctionError("Encountered error while connecting to ElasticSearch {0}".format(e))
# Start query results as None
query_results = None
query_results = None
matched_records = 0

try:
es_results = es.search(index=es_index, doc_type=es_doc_type, body=es_query, ignore=[400, 404, 500])
except:
raise FunctionError("Encountered error while submitting query to ElasticSearch")
except Exception as e:
raise FunctionError("Encountered error while submitting query to ElasticSearch {0}".format(e))
# If our results has a 'hits' attribute; inform the user
if 'hits' in es_results:
yield StatusMessage("Call to elasticsearch was successful. Returning results")
# Could do some extra stuff with results here

# Prepare the results object
query_results = es_results["hits"]["hits"]
matched_records = es_results["hits"]["total"]

# Check if we have a status attribute indicating an error we could raise
elif 'status' in es_results:
# If we encounter either a 404 (Not found) or 400 error return the reason

if es_results['status'] in (400, 404, 500):
# Can raise the root_cause of the failure
log.error(es_results["error"]["root_cause"])
Expand All @@ -107,23 +106,27 @@ def _fn_elasticsearch_query_function(self, event, *args, **kwargs):
if es_results['status'] == 400:
# es_results["error"]["root_cause"][1]["reason"] is only available on exceptions of type 400
yield StatusMessage("Exception with code 400 encountered. Error: "+str(es_results["error"]["root_cause"]))

elif es_results['status'] == 404:
# Give reason that 404 happened; index not found?
yield StatusMessage("Exception encounted during query : "+str(es_results["error"]["reason"]))
elif es_results['status'] == 500:
yield StatusMessage("Unexpected 500 error encountered. Error: "+str(es_results["error"]["reason"]))


# Prepare the results object
# Prepare the results object
results = {
"inputs": {
"es_query": es_query,
"es_doc_type": es_doc_type,
"es_index" : es_index
},
"query_results": query_results,
"success": (True if query_results is not None else False),
"matched_records": matched_records
"matched_records": matched_records,
"returned_records": len(query_results)
}

yield StatusMessage("Successful: "+str(results["success"]))
# Produce a FunctionResult with the results
yield FunctionResult(results)
except Exception:
yield FunctionError()
yield FunctionError()
3 changes: 1 addition & 2 deletions fn_elasticsearch/fn_elasticsearch/util/config.py
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# (c) Copyright IBM Corp. 2010, 2018. All Rights Reserved.

"""Generate a default configuration-file section for fn_elasticsearch"""
Expand All @@ -18,4 +18,3 @@ def config_section_data():
es_cafile = <CA_FILE_TO_BE_USED>
"""
return config_data

0 comments on commit e94895c

Please sign in to comment.