-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from CrowdStrike/feature/policy-support
Policy Describe/Import/Export
- Loading branch information
Showing
9 changed files
with
679 additions
and
138 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,9 @@ The toolkit provides: | |
- Multiple profile support, including support for MSSP / Falcon Flight Control configurations. | ||
- A shell allowing you to interface with many hosts via RTR at once, and get the output via CSV. | ||
- Scriptability! You can program the shell by providing pre-written routines via a file on disk, and a full Python extensibility API is provided. | ||
- More functionality is coming soon! Already on the roadmap are Policy import/export and IOA import/export. Want more functionality? Open an [Issue](https://github.com/CrowdStrike/Falcon-Toolkit/issues/new)! | ||
- Prevention policy import and export | ||
- Response policy import and export | ||
- More functionality is coming soon! Want more functionality? Open an [Issue](https://github.com/CrowdStrike/Falcon-Toolkit/issues/new)! | ||
|
||
Since this is built on top of Caracara, you get a bunch of great functionality and flexibility free, including the ability to filter hosts using dynamically generated FQL queries, full debug logging where desired, Falcon Flight Control integration, and more! Plus, the tool is lightning quick as it leverages Caracara's parallelisation tricks to pull more information quickly. | ||
|
||
|
@@ -180,13 +182,17 @@ Two types of configuration backends are provided out of the box: the default, wh | |
|
||
Your API keys should have the following scopes enabled in the Falcon dashboard: | ||
|
||
| ↓ API Scopes // Commands → | `host_search` | `shell` | | ||
|--------------------------------------|:-------------:|:-------:| | ||
| **Falcon Flight Control: Read** | X<br>*When using parent<br>CID API Keys* | X<br>*When using parent<br>CID API Keys* | | ||
| **Hosts: Read** | X | X | | ||
| **Real Time Response: Read** | | X | | ||
| **Real Time Response: Write** | | X | | ||
| **Real Time Response: Admin** | | X<br>*for admin commands* | | ||
| ↓ API Scopes // Commands → | `host_search` | `shell` | `policies`<br>(Prevention) | `policies`<br>(Response) | | ||
|--------------------------------------|:-------------:|:-------:|:--------------------------:|:-------------------------:| | ||
| **Falcon Flight Control: Read** | X<br>*When using parent<br>CID API Keys* | X<br>*When using parent<br>CID API Keys* | X<br>*When using parent<br>CID API Keys* | X<br>*When using parent<br>CID API Keys* | | ||
| **Hosts: Read** | X | X | | | | ||
| **Prevention Policies: Read** | | | X<br>`describe` / `export` sub-commands | | | ||
| **Prevention Policies: Write** | | | X<br>`import` sub-command | | | ||
| **Real Time Response: Read** | | X | | | | ||
| **Real Time Response: Write** | | X | | | | ||
| **Real Time Response: Admin** | | X<br>*for admin commands* | | | | ||
| **Response Policies: Read** | | | | X<br>`describe` / `export` sub-commands | | ||
| **Response Policies: Write** | | | | X<br>`import` sub-command | | ||
|
||
### Showing Your Profiles | ||
|
||
|
@@ -289,7 +295,7 @@ falcon -p ProfileName shell -d abcdef12345,ghijkl67890 | |
|
||
Sometimes it is not practical to provide a list of Device IDs at the command line, often because the length of the string containing all the IDs would exceed the maximum command length allowable within your shell. To get around this, Falcon Toolkit provides another parameter (`--device-id-file` / `-df`), which allows you to provide a path to a file containing a list of AIDs, one per line. For example, let's say you wanted to connect to two devices with the AIDs `abcdef12345` and `ghijkl67890`, you may have a file named `device_ids.txt` with the following contents: | ||
|
||
``` | ||
```text | ||
abcdef12345 | ||
ghijkl67890 | ||
``` | ||
|
@@ -300,7 +306,6 @@ Then, you could jump into a shell with these devices via this Falcon Toolkit com | |
falcon -p ProfileName shell -df device_ids.txt | ||
``` | ||
|
||
|
||
### Real Time Response (RTR) Scripting | ||
|
||
The RTR shell is fully scriptable. There are two different scripting methods supported: | ||
|
@@ -350,6 +355,48 @@ Some example usages of this functionality are as follows: | |
|
||
</details> | ||
|
||
## Policy Manipulation | ||
|
||
You can `describe`, `import` and `export` two types of policies: Prevention and Response. The three verbs are applied to the `falcon policies` command to specify what you would like to do with policies, and a command line switch is used to specify the policy type to work with. Exported policies are written to disk as JSON with some Falcon Toolkit-specific data needed to import a policy back again. | ||
|
||
### Examples | ||
|
||
Show all Prevention policies within the `MyCompany` Falcon profile: | ||
|
||
```shell | ||
$ falcon -p MyCompany policies -p describe | ||
platform_default (Platform: Windows) | ||
Platform default policy | ||
... | ||
``` | ||
|
||
Show all Response policies when only one profile is configured: | ||
|
||
```shell | ||
$ falcon policies -r describe | ||
platform_default (Platform: Windows) | ||
Platform default policy | ||
... | ||
``` | ||
|
||
Export a Response policy from the `MyCompany` tenant to disk: | ||
|
||
```shell | ||
$ falcon -p MyCompany policies -r export | ||
Please choose a policy to export | ||
|
||
* My Response Policy [Windows] | ||
My Other Response Policy [Linux] | ||
... | ||
``` | ||
|
||
Import a Prevention policy to the one configured Falcon tenant: | ||
|
||
```shell | ||
$ falcon policies -p import MyExportedPolicy.json | ||
... | ||
``` | ||
|
||
## Support & Community Forums | ||
|
||
Falcon Toolkit is an open source project, and not a formal CrowdStrike product, designed to assist users with managing their Falcon tenants and executing commands at scale. As such, it carries no formal support, express or implied. This project originated out of the CrowdStrike Services Incident Response (IR) team's need to execute commands across Falcon tenants quickly, at scale, and with auditing, and is maintained by [Chris Hammond](mailto:[email protected]). | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
"""Falcon Toolkit: Policy Management. | ||
This sub-module contains the implementation of the falcon policies commands. | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
"""Falcon Toolkit: Policy Management. | ||
This file contains the command line interface for the policies commands. The implementation | ||
of the logic itself is contained in other files, including policies.py | ||
""" | ||
import os | ||
|
||
from typing import List | ||
|
||
import click | ||
import pick | ||
|
||
from caracara import Client | ||
from caracara.common.policy_wrapper import Policy | ||
|
||
from click_option_group import ( | ||
optgroup, | ||
RequiredMutuallyExclusiveOptionGroup, | ||
) | ||
|
||
from falcon_toolkit.common.cli import get_instance | ||
from falcon_toolkit.policies.constants import PoliciesAPIModule | ||
from falcon_toolkit.policies.describe import pretty_print_policies | ||
from falcon_toolkit.policies.container import PolicyContainer | ||
|
||
|
||
@click.group( | ||
name='policies', | ||
help='Manage Falcon Prevention and Response policies', | ||
) | ||
@click.pass_context | ||
@optgroup.group( | ||
"Policy Type", | ||
cls=RequiredMutuallyExclusiveOptionGroup, | ||
help="Choose whether to interface with [-p]revention or [-r]esponse policies", | ||
) | ||
@optgroup.option( | ||
'-p', | ||
'--prevention', | ||
'prevention_policies_option', | ||
is_flag=True, | ||
help="Interface with Prevention policies", | ||
) | ||
@optgroup.option( | ||
'-r', | ||
'--response', | ||
'response_policies_option', | ||
is_flag=True, | ||
help="Interface with Response policies", | ||
) | ||
def cli_policies( | ||
ctx: click.Context, | ||
prevention_policies_option: bool, | ||
response_policies_option: bool, | ||
): | ||
"""Configure the future profiles commands by getting the context in shape.""" | ||
instance = get_instance(ctx) | ||
client: Client = instance.auth_backend.authenticate() | ||
ctx.obj['client'] = client | ||
|
||
if prevention_policies_option: | ||
ctx.obj['policies_api'] = client.prevention_policies | ||
ctx.obj['policies_type'] = "prevention" | ||
elif response_policies_option: | ||
ctx.obj['policies_api'] = client.response_policies | ||
ctx.obj['policies_type'] = "response" | ||
else: | ||
raise ValueError("Impossible scenario: no policy type specified") | ||
|
||
|
||
@click.command( | ||
name='describe', | ||
help='List and describe the policies within the Falcon tenant.' | ||
) | ||
@click.pass_context | ||
def policies_describe(ctx: click.Context): | ||
"""List and describe the Prevention or Response policies within the Falcon tenant.""" | ||
policies_api: PoliciesAPIModule = ctx.obj['policies_api'] | ||
policies_type: str = ctx.obj['policies_type'] | ||
click.echo(click.style(f"Describing all {policies_type} policies", fg='green', bold=True)) | ||
policies = policies_api.describe_policies() | ||
pretty_print_policies(policies) | ||
|
||
|
||
@click.command( | ||
name='export', | ||
help='Export a Prevention or Response policy to disk.', | ||
) | ||
@click.pass_context | ||
def policies_export(ctx: click.Context): | ||
"""Allow a user to choose a Prevention or Response policy to export to disk.""" | ||
# pylint: disable=too-many-locals | ||
policies_api: PoliciesAPIModule = ctx.obj['policies_api'] | ||
policies_type: str = ctx.obj['policies_type'] | ||
click.echo("Loading policies...") | ||
policies = policies_api.describe_policies() | ||
|
||
options: List[pick.Option] = [] | ||
for policy in policies: | ||
option_text = f"{policy.name} [{policy.platform_name}]" | ||
option = pick.Option(label=option_text, value=policy) | ||
options.append(option) | ||
|
||
chosen_option, _ = pick.pick(options, "Please choose a policy to export") | ||
chosen_policy: Policy = chosen_option.value | ||
default_filename = f"{chosen_policy.name}.json" | ||
reasonable_filename = False | ||
while not reasonable_filename: | ||
filename: str = click.prompt("Policy filename", type=str, default=default_filename) | ||
if not filename.endswith(".json"): | ||
click.echo(click.style("Filename must end in .json", fg='yellow')) | ||
continue | ||
|
||
if os.path.exists(filename): | ||
click.echo(click.style("File already exists!", fg='yellow')) | ||
continue | ||
|
||
reasonable_filename = True | ||
|
||
policy_container = PolicyContainer( | ||
policy=chosen_policy, | ||
policy_type=policies_type, | ||
) | ||
|
||
with open(filename, 'wt', encoding='utf-8') as export_file_handle: | ||
export_file_handle.write(policy_container.dumps()) | ||
|
||
click.echo("Export complete") | ||
|
||
|
||
@click.command( | ||
name='import', | ||
help='Import a Prevention or Response policy from disk.', | ||
) | ||
@click.pass_context | ||
@click.argument( | ||
'filename', | ||
type=click.STRING, | ||
) | ||
def policies_import( | ||
ctx: click.Context, | ||
filename: str, | ||
): | ||
"""Import a Prevention or Response policy from the JSON file named FILENAME.""" | ||
policies_api: PoliciesAPIModule = ctx.obj['policies_api'] | ||
|
||
click.echo(f"Loading policy in the file: {filename}") | ||
|
||
with open(filename, 'rt', encoding='utf-8') as policy_file_handle: | ||
policy_str = str(policy_file_handle.read()) | ||
|
||
policy_container = PolicyContainer.loads(policy_str) | ||
|
||
click.echo(f"Uploading the {policy_container.policy.name} policy to Falcon") | ||
policies_api.push_policy(policy_container.policy) | ||
|
||
click.echo("Done!") | ||
|
||
|
||
cli_policies.add_command(policies_describe) | ||
cli_policies.add_command(policies_export) | ||
cli_policies.add_command(policies_import) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
"""Falcon Toolkit: Policy Management. | ||
This file contains constants that are required to properly display and manage Prevention and | ||
Response policies within a Falcon tenant. | ||
""" | ||
from typing import Union | ||
|
||
from caracara.modules.prevention_policies import PreventionPoliciesApiModule | ||
from caracara.modules.response_policies import ResponsePoliciesApiModule | ||
from colorama import Fore | ||
|
||
|
||
ASCII_OFF_BUTTON = ( | ||
f"{Fore.RED}-----------{Fore.RESET}\n" | ||
f"{Fore.RED}| OFF |{Fore.RESET}\n" | ||
f"{Fore.RED}-----------{Fore.RESET}\n" | ||
) | ||
ASCII_ON_BUTTON = ( | ||
f"{Fore.GREEN}-----------{Fore.RESET}\n" | ||
f"{Fore.GREEN}| ON |{Fore.RESET}\n" | ||
f"{Fore.GREEN}-----------{Fore.RESET}\n" | ||
) | ||
|
||
# List of policy types as strings for a quick reference | ||
POLICY_TYPES = [ | ||
"prevention", | ||
"response", | ||
] | ||
|
||
# Union type of all types of all Caracara modules providing policy data | ||
# They all expose a common API, so can be assumed to be one type where convenient | ||
PoliciesAPIModule = Union[ | ||
PreventionPoliciesApiModule, | ||
ResponsePoliciesApiModule, | ||
] |
Oops, something went wrong.