Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8cc82a9
Added modes and stub functions to the contentctl.py as an entry point…
pyth0n1c Apr 22, 2022
8041232
Small change - renamed a caraible from type to content_type. It is b…
pyth0n1c Apr 22, 2022
760242e
Included basic implementation of clean, which is yet to be tested.
pyth0n1c Apr 22, 2022
d6e09d3
Actually calling clean now instead of just passing over it.
pyth0n1c Apr 22, 2022
814a13c
Stubs for building an application with slim and inspecting with comma…
pyth0n1c Apr 23, 2022
aecd70e
Now support building the app. Added requirements to support CLI-base…
pyth0n1c Apr 23, 2022
0db105e
More progress toward build and inspect of the app.
pyth0n1c Apr 23, 2022
6694a5f
building and appinspecting of the package are now working. removed a…
pyth0n1c Apr 23, 2022
4aeb435
Non working... yet... deploy function.
pyth0n1c Apr 25, 2022
29894c6
Fixed broken 'clean' paths for multiple content folders.
pyth0n1c May 13, 2022
83c6448
Fixing some paths and command line arguments for the contentctl build…
pyth0n1c May 13, 2022
3ef1542
Added another folder to clean.
pyth0n1c May 13, 2022
751736f
Better error handling for inspect
pyth0n1c May 13, 2022
4a86d06
Remove overwrite app as
pyth0n1c May 13, 2022
e751727
Changed all of the clean terminology to init. This is in preparation…
pyth0n1c May 17, 2022
6d6feb9
Name conflict on init... fixed
pyth0n1c May 17, 2022
123600d
Added generation of an app.manifest file based on command line argume…
pyth0n1c May 17, 2022
004710a
Renamed add generation of app configuration file as well as manifest.…
pyth0n1c May 17, 2022
c9552fc
Updates to deploy towards working with the ACS application for deploy…
pyth0n1c May 17, 2022
a9b118a
Deployment using acs is working. It is currently difficult to tell w…
pyth0n1c May 17, 2022
b17b224
Added removal of baselines during initialize.
pyth0n1c May 18, 2022
e47765f
Fixing error introduced when sorting steps
pyth0n1c May 18, 2022
e3459ea
Updates to contentctl, deploy,
pyth0n1c May 18, 2022
ef6ef78
Fixed output dir naming and path for
pyth0n1c May 18, 2022
f6790d1
Updated the initialize output path and
pyth0n1c May 18, 2022
87a8bc0
Merged develop into this branch and resolved merge conflicts.
pyth0n1c Aug 3, 2022
d9649ae
Branch was auto-updated.
pyth0n1c Aug 3, 2022
2c0888a
Merge branch 'develop' into Clean_and_Deploy
pyth0n1c Aug 11, 2022
8bc6cc4
Branch was auto-updated.
pyth0n1c Aug 11, 2022
14b16fa
Updated some of the documentation in contentctl.py and updated the RE…
pyth0n1c Aug 11, 2022
e155453
Branch was auto-updated.
pyth0n1c Aug 11, 2022
f8e3fb6
code to update templates files that must change for an app with diffe…
pyth0n1c Aug 11, 2022
f632813
Changes to a number of files to make them suitable for use in an app …
pyth0n1c Aug 11, 2022
ee0d1c7
Merge branch 'Clean_and_Deploy' of https://github.com/splunk/security…
pyth0n1c Aug 11, 2022
a17b44d
Remove lookups from copied ESCU directory.
pyth0n1c Aug 12, 2022
1a02a53
Updated the order of the options in the help menu for contentctl. Th…
pyth0n1c Aug 12, 2022
4a0424c
Branch was auto-updated.
pyth0n1c Aug 12, 2022
4f6c1f2
Fixed template files that were modified in error
pyth0n1c Aug 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<img src="https://img.shields.io/github/stars/splunk/security_content?style=social" /></a>
</p>


# Splunk Security Content
![security_content](docs/static/logo.png)
=====
Expand All @@ -43,12 +43,16 @@ curl -s https://content.splunkresearch.com | jq
```

# Usage 🧰
### contentctl.py
The Content Control tool allows you to manipulate Splunk Security Content via the following actions:
### contentctl.py
The Content Control tool allows you to manipulate Splunk Security Content via the following actions:

0. **init** - Initilialize a new repo from scratch so you can easily add your own content to a custom application. Note that this requires a large number of command line arguments, so use python _contentctl.py init --help_ for documentation around those arguments.
1. **new_content** - Creates new content (detection, story, baseline)
2. **validate** - Validates written content
3. **generate** - Generates a deployment package for different platforms (splunk_app)
4. **build** - Builds an application suitable for deployment on a search head using Slim, the Splunk Packaging Toolkit
5. **inspect** - Uses a local version of appinspect to ensure that the app you built meets basic quality standards.
6. **cloud_deploy** - Using ACS, deploy your custom app to a running Splunk Cloud Instance.

### pre-requisites
Make sure you use python version 3.9.
Expand All @@ -64,16 +68,16 @@ pip install -r requirements.txt
### Architecture details for the tooling
- [WIKI](https://github.com/splunk/security_content/wiki/Security-Content-Code)

### create a new detection
`python contentctl.py -p . new_content -t detection`
### create a new detection
`python contentctl.py -p . new_content -t detection`

for a more indepth write up on how to write content see our [guide](https://github.com/splunk/security_content/wiki/Developing-Content).

### validate security content
`python contentctl.py -p . validate -pr ESCU`
### validate security content
`python contentctl.py -p . validate -pr ESCU`

### generate a splunk app from current content
`python contentctl.py -p . generate -o dist/escu -pr ESCU`
`python contentctl.py -p . generate -o dist/escu -pr ESCU`

# MITRE ATT&CK ⚔️
### Detection Coverage
Expand Down Expand Up @@ -129,4 +133,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import subprocess
import sys
import tarfile
import os
from typing import TextIO
class Build:
def __init__(self, args):
base_path = args.path
if args.product == "ESCU":
self.source = os.path.join(base_path, "dist","escu")
self.app_name = "DA-ESS-ContentUpdate"
elif args.product == "SSA":
raise(Exception(f"{args.product} build not supported"))
else:
self.source = os.path.join(base_path, "dist", args.product)
self.app_name = args.product
if not os.path.exists(self.source):
raise(Exception(f"Attemping to build app from {self.source}, but it does not exist."))

print(f"Building Splunk App from source {self.source}")


self.output_dir_base = args.output_dir


self.output_dir_source = os.path.join(self.output_dir_base, self.app_name)

#self.output_package = os.path.join(self.output_dir_base, self.app_name+'.tar.gz')

self.copy_app_source()
self.validate_splunk_app()
self.build_splunk_app()
#self.archive_splunk_app()

def copy_app_source(self):
import shutil

try:
if os.path.exists(self.output_dir_source):
print(f"The directory {self.output_dir_source} exists. Deleting it in preparation to build the app... ", end='', flush=True)
try:
shutil.rmtree(self.output_dir_source)
print("Done!")
except Exception as e:
raise(Exception(f"Unable to delete {self.output_dir_source}"))

print(f"Copying Splunk App Source to {self.source} in preparation for building...", end='')
sys.stdout.flush()
shutil.copytree(self.source, self.output_dir_source, dirs_exist_ok=True)
print("done")
except Exception as e:
raise(Exception(f"Failed to copy Splunk app source from {self.source} -> {self.output_dir_source} : {str(e)}"))


def validate_splunk_app(self):
proc = "nothing..."
try:
print("Validating Splunk App...")
sys.stdout.flush()
nothing = subprocess.check_output(["slim", "validate", self.output_dir_source])

print("Package Validation Complete")
except Exception as e:
print(f"error: {str(e)} ")
raise(Exception(f"Error building Splunk App: {str(e)}"))


def build_splunk_app(self):
proc = "nothing..."
try:
print("Building Splunk App...")
sys.stdout.flush()
nothing = subprocess.check_output(["slim", "package", "-o", self.output_dir_base, self.output_dir_source])
print("Package Generation Complete")
except Exception as e:
print("error")
raise(Exception(f"Error building Splunk App: {str(e)}"))

'''
def archive_splunk_app(self):

try:
print(f"Creating Splunk app archive {self.output_package}...", end='')
sys.stdout.flush()
with tarfile.open(self.output_package, "w:gz") as tar:
tar.add(self.output_dir_build, arcname=os.path.basename(self.output_dir_build))
print("done")
except Exception as e:
print("error")
raise(Exception(f"Error creating {self.output_package}: {str(e)}"))
'''


Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import splunklib.client as client
import multiprocessing
import http.server
import time
import sys
import subprocess
import os
class Deploy:
def __init__(self, args):



#First, check to ensure that the legal ack is correct. If not, quit
if args.acs_legal_ack != "Y":
raise(Exception(f"Error - must supply 'acs-legal-ack=Y', not 'acs-legal-ack={args.acs_legal_ack}'"))

self.acs_legal_ack = args.acs_legal_ack
self.app_package = args.app_package
if not os.path.exists(self.app_package):
raise(Exception(f"Error - app_package file {self.app_package} does not exist"))
self.username = args.username
self.password = args.password
self.server = args.server



self.deploy_to_splunk_cloud()
#self.http_process = self.start_http_server()

#self.install_app()


def deploy_to_splunk_cloud(self):

commandline = f"acs apps install private --acs-legal-ack={self.acs_legal_ack} "\
f"--app-package {self.app_package} --server {self.server} --username "\
f"{self.username} --password {self.password}"


try:
res = subprocess.run(args = commandline.split(' '), )
except Exception as e:
raise(Exception(f"Error deploying to Splunk Cloud Instance: {str(e)}"))
print(res.returncode)
if res.returncode != 0:
raise(Exception("Error deploying to Splunk Cloud Instance. Review output to diagnose error."))

'''
def install_app_local(self) -> bool:
#Connect to the service
time.sleep(1)
#self.http_process.start()
#time.sleep(2)


print(f"Connecting to server {self.host}")
try:
service = client.connect(host=self.host, port=self.api_port, username=self.username, password=self.password)
assert isinstance(service, client.Service)

except Exception as e:
raise(Exception(f"Failure connecting the Splunk Search Head: {str(e)}"))


#Install the app
try:
params = {'name': self.server_app_path}
res = service.post('apps/appinstall', **params)
#Check the result?

print(f"Successfully installed {self.server_app_path}!")



except Exception as e:
raise(Exception(f"Failure installing the app {self.server_app_path}: {str(e)}"))


#Query and list all of the installed apps
try:
all_apps = service.apps
except Exception as e:
print(f"Failed listing all apps: {str(e)}")
return False

print("Installed apps:")
for count, app in enumerate(all_apps):
print("\t{count}. {app.name}")


print(f"Installing app {self.path}")

self.http_process.terminate()

return True
'''


Loading