Compare commits

..

1 Commits

Author SHA1 Message Date
m0duspwnens 50ab63162a users 2024-01-17 12:51:15 -05:00
1143 changed files with 552688 additions and 339233 deletions
+546
View File
@@ -0,0 +1,546 @@
title = "gitleaks config"
# Gitleaks rules are defined by regular expressions and entropy ranges.
# Some secrets have unique signatures which make detecting those secrets easy.
# Examples of those secrets would be GitLab Personal Access Tokens, AWS keys, and GitHub Access Tokens.
# All these examples have defined prefixes like `glpat`, `AKIA`, `ghp_`, etc.
#
# Other secrets might just be a hash which means we need to write more complex rules to verify
# that what we are matching is a secret.
#
# Here is an example of a semi-generic secret
#
# discord_client_secret = "8dyfuiRyq=vVc3RRr_edRk-fK__JItpZ"
#
# We can write a regular expression to capture the variable name (identifier),
# the assignment symbol (like '=' or ':='), and finally the actual secret.
# The structure of a rule to match this example secret is below:
#
# Beginning string
# quotation
# │ End string quotation
# │ │
# ▼ ▼
# (?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9=_\-]{32})['\"]
#
# ▲ ▲ ▲
# │ │ │
# │ │ │
# identifier assignment symbol
# Secret
#
[[rules]]
id = "gitlab-pat"
description = "GitLab Personal Access Token"
regex = '''glpat-[0-9a-zA-Z\-\_]{20}'''
[[rules]]
id = "aws-access-token"
description = "AWS"
regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}'''
# Cryptographic keys
[[rules]]
id = "PKCS8-PK"
description = "PKCS8 private key"
regex = '''-----BEGIN PRIVATE KEY-----'''
[[rules]]
id = "RSA-PK"
description = "RSA private key"
regex = '''-----BEGIN RSA PRIVATE KEY-----'''
[[rules]]
id = "OPENSSH-PK"
description = "SSH private key"
regex = '''-----BEGIN OPENSSH PRIVATE KEY-----'''
[[rules]]
id = "PGP-PK"
description = "PGP private key"
regex = '''-----BEGIN PGP PRIVATE KEY BLOCK-----'''
[[rules]]
id = "github-pat"
description = "GitHub Personal Access Token"
regex = '''ghp_[0-9a-zA-Z]{36}'''
[[rules]]
id = "github-oauth"
description = "GitHub OAuth Access Token"
regex = '''gho_[0-9a-zA-Z]{36}'''
[[rules]]
id = "SSH-DSA-PK"
description = "SSH (DSA) private key"
regex = '''-----BEGIN DSA PRIVATE KEY-----'''
[[rules]]
id = "SSH-EC-PK"
description = "SSH (EC) private key"
regex = '''-----BEGIN EC PRIVATE KEY-----'''
[[rules]]
id = "github-app-token"
description = "GitHub App Token"
regex = '''(ghu|ghs)_[0-9a-zA-Z]{36}'''
[[rules]]
id = "github-refresh-token"
description = "GitHub Refresh Token"
regex = '''ghr_[0-9a-zA-Z]{76}'''
[[rules]]
id = "shopify-shared-secret"
description = "Shopify shared secret"
regex = '''shpss_[a-fA-F0-9]{32}'''
[[rules]]
id = "shopify-access-token"
description = "Shopify access token"
regex = '''shpat_[a-fA-F0-9]{32}'''
[[rules]]
id = "shopify-custom-access-token"
description = "Shopify custom app access token"
regex = '''shpca_[a-fA-F0-9]{32}'''
[[rules]]
id = "shopify-private-app-access-token"
description = "Shopify private app access token"
regex = '''shppa_[a-fA-F0-9]{32}'''
[[rules]]
id = "slack-access-token"
description = "Slack token"
regex = '''xox[baprs]-([0-9a-zA-Z]{10,48})?'''
[[rules]]
id = "stripe-access-token"
description = "Stripe"
regex = '''(?i)(sk|pk)_(test|live)_[0-9a-z]{10,32}'''
[[rules]]
id = "pypi-upload-token"
description = "PyPI upload token"
regex = '''pypi-AgEIcHlwaS5vcmc[A-Za-z0-9\-_]{50,1000}'''
[[rules]]
id = "gcp-service-account"
description = "Google (GCP) Service-account"
regex = '''\"type\": \"service_account\"'''
[[rules]]
id = "heroku-api-key"
description = "Heroku API Key"
regex = ''' (?i)(heroku[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12})['\"]'''
secretGroup = 3
[[rules]]
id = "slack-web-hook"
description = "Slack Webhook"
regex = '''https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8,12}/[a-zA-Z0-9_]{24}'''
[[rules]]
id = "twilio-api-key"
description = "Twilio API Key"
regex = '''SK[0-9a-fA-F]{32}'''
[[rules]]
id = "age-secret-key"
description = "Age secret key"
regex = '''AGE-SECRET-KEY-1[QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L]{58}'''
[[rules]]
id = "facebook-token"
description = "Facebook token"
regex = '''(?i)(facebook[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "twitter-token"
description = "Twitter token"
regex = '''(?i)(twitter[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{35,44})['\"]'''
secretGroup = 3
[[rules]]
id = "adobe-client-id"
description = "Adobe Client ID (Oauth Web)"
regex = '''(?i)(adobe[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "adobe-client-secret"
description = "Adobe Client Secret"
regex = '''(p8e-)(?i)[a-z0-9]{32}'''
[[rules]]
id = "alibaba-access-key-id"
description = "Alibaba AccessKey ID"
regex = '''(LTAI)(?i)[a-z0-9]{20}'''
[[rules]]
id = "alibaba-secret-key"
description = "Alibaba Secret Key"
regex = '''(?i)(alibaba[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{30})['\"]'''
secretGroup = 3
[[rules]]
id = "asana-client-id"
description = "Asana Client ID"
regex = '''(?i)(asana[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9]{16})['\"]'''
secretGroup = 3
[[rules]]
id = "asana-client-secret"
description = "Asana Client Secret"
regex = '''(?i)(asana[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "atlassian-api-token"
description = "Atlassian API token"
regex = '''(?i)(atlassian[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{24})['\"]'''
secretGroup = 3
[[rules]]
id = "bitbucket-client-id"
description = "Bitbucket client ID"
regex = '''(?i)(bitbucket[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "bitbucket-client-secret"
description = "Bitbucket client secret"
regex = '''(?i)(bitbucket[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9_\-]{64})['\"]'''
secretGroup = 3
[[rules]]
id = "beamer-api-token"
description = "Beamer API token"
regex = '''(?i)(beamer[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](b_[a-z0-9=_\-]{44})['\"]'''
secretGroup = 3
[[rules]]
id = "clojars-api-token"
description = "Clojars API token"
regex = '''(CLOJARS_)(?i)[a-z0-9]{60}'''
[[rules]]
id = "contentful-delivery-api-token"
description = "Contentful delivery API token"
regex = '''(?i)(contentful[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9\-=_]{43})['\"]'''
secretGroup = 3
[[rules]]
id = "databricks-api-token"
description = "Databricks API token"
regex = '''dapi[a-h0-9]{32}'''
[[rules]]
id = "discord-api-token"
description = "Discord API key"
regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{64})['\"]'''
secretGroup = 3
[[rules]]
id = "discord-client-id"
description = "Discord client ID"
regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9]{18})['\"]'''
secretGroup = 3
[[rules]]
id = "discord-client-secret"
description = "Discord client secret"
regex = '''(?i)(discord[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9=_\-]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "doppler-api-token"
description = "Doppler API token"
regex = '''['\"](dp\.pt\.)(?i)[a-z0-9]{43}['\"]'''
[[rules]]
id = "dropbox-api-secret"
description = "Dropbox API secret/key"
regex = '''(?i)(dropbox[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{15})['\"]'''
[[rules]]
id = "dropbox--api-key"
description = "Dropbox API secret/key"
regex = '''(?i)(dropbox[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{15})['\"]'''
[[rules]]
id = "dropbox-short-lived-api-token"
description = "Dropbox short lived API token"
regex = '''(?i)(dropbox[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](sl\.[a-z0-9\-=_]{135})['\"]'''
[[rules]]
id = "dropbox-long-lived-api-token"
description = "Dropbox long lived API token"
regex = '''(?i)(dropbox[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"][a-z0-9]{11}(AAAAAAAAAA)[a-z0-9\-_=]{43}['\"]'''
[[rules]]
id = "duffel-api-token"
description = "Duffel API token"
regex = '''['\"]duffel_(test|live)_(?i)[a-z0-9_-]{43}['\"]'''
[[rules]]
id = "dynatrace-api-token"
description = "Dynatrace API token"
regex = '''['\"]dt0c01\.(?i)[a-z0-9]{24}\.[a-z0-9]{64}['\"]'''
[[rules]]
id = "easypost-api-token"
description = "EasyPost API token"
regex = '''['\"]EZAK(?i)[a-z0-9]{54}['\"]'''
[[rules]]
id = "easypost-test-api-token"
description = "EasyPost test API token"
regex = '''['\"]EZTK(?i)[a-z0-9]{54}['\"]'''
[[rules]]
id = "fastly-api-token"
description = "Fastly API token"
regex = '''(?i)(fastly[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9\-=_]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "finicity-client-secret"
description = "Finicity client secret"
regex = '''(?i)(finicity[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{20})['\"]'''
secretGroup = 3
[[rules]]
id = "finicity-api-token"
description = "Finicity API token"
regex = '''(?i)(finicity[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "flutterwave-public-key"
description = "Flutterwave public key"
regex = '''FLWPUBK_TEST-(?i)[a-h0-9]{32}-X'''
[[rules]]
id = "flutterwave-secret-key"
description = "Flutterwave secret key"
regex = '''FLWSECK_TEST-(?i)[a-h0-9]{32}-X'''
[[rules]]
id = "flutterwave-enc-key"
description = "Flutterwave encrypted key"
regex = '''FLWSECK_TEST[a-h0-9]{12}'''
[[rules]]
id = "frameio-api-token"
description = "Frame.io API token"
regex = '''fio-u-(?i)[a-z0-9\-_=]{64}'''
[[rules]]
id = "gocardless-api-token"
description = "GoCardless API token"
regex = '''['\"]live_(?i)[a-z0-9\-_=]{40}['\"]'''
[[rules]]
id = "grafana-api-token"
description = "Grafana API token"
regex = '''['\"]eyJrIjoi(?i)[a-z0-9\-_=]{72,92}['\"]'''
[[rules]]
id = "hashicorp-tf-api-token"
description = "HashiCorp Terraform user/org API token"
regex = '''['\"](?i)[a-z0-9]{14}\.atlasv1\.[a-z0-9\-_=]{60,70}['\"]'''
[[rules]]
id = "hubspot-api-token"
description = "HubSpot API token"
regex = '''(?i)(hubspot[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{8}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{12})['\"]'''
secretGroup = 3
[[rules]]
id = "intercom-api-token"
description = "Intercom API token"
regex = '''(?i)(intercom[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9=_]{60})['\"]'''
secretGroup = 3
[[rules]]
id = "intercom-client-secret"
description = "Intercom client secret/ID"
regex = '''(?i)(intercom[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{8}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{12})['\"]'''
secretGroup = 3
[[rules]]
id = "ionic-api-token"
description = "Ionic API token"
regex = '''(?i)(ionic[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](ion_[a-z0-9]{42})['\"]'''
[[rules]]
id = "linear-api-token"
description = "Linear API token"
regex = '''lin_api_(?i)[a-z0-9]{40}'''
[[rules]]
id = "linear-client-secret"
description = "Linear client secret/ID"
regex = '''(?i)(linear[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "lob-api-key"
description = "Lob API Key"
regex = '''(?i)(lob[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]((live|test)_[a-f0-9]{35})['\"]'''
secretGroup = 3
[[rules]]
id = "lob-pub-api-key"
description = "Lob Publishable API Key"
regex = '''(?i)(lob[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]((test|live)_pub_[a-f0-9]{31})['\"]'''
secretGroup = 3
[[rules]]
id = "mailchimp-api-key"
description = "Mailchimp API key"
regex = '''(?i)(mailchimp[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-f0-9]{32}-us20)['\"]'''
secretGroup = 3
[[rules]]
id = "mailgun-private-api-token"
description = "Mailgun private API token"
regex = '''(?i)(mailgun[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](key-[a-f0-9]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "mailgun-pub-key"
description = "Mailgun public validation key"
regex = '''(?i)(mailgun[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"](pubkey-[a-f0-9]{32})['\"]'''
secretGroup = 3
[[rules]]
id = "mailgun-signing-key"
description = "Mailgun webhook signing key"
regex = '''(?i)(mailgun[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{32}-[a-h0-9]{8}-[a-h0-9]{8})['\"]'''
secretGroup = 3
[[rules]]
id = "mapbox-api-token"
description = "Mapbox API token"
regex = '''(?i)(pk\.[a-z0-9]{60}\.[a-z0-9]{22})'''
[[rules]]
id = "messagebird-api-token"
description = "MessageBird API token"
regex = '''(?i)(messagebird[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{25})['\"]'''
secretGroup = 3
[[rules]]
id = "messagebird-client-id"
description = "MessageBird API client ID"
regex = '''(?i)(messagebird[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-h0-9]{8}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{4}-[a-h0-9]{12})['\"]'''
secretGroup = 3
[[rules]]
id = "new-relic-user-api-key"
description = "New Relic user API Key"
regex = '''['\"](NRAK-[A-Z0-9]{27})['\"]'''
[[rules]]
id = "new-relic-user-api-id"
description = "New Relic user API ID"
regex = '''(?i)(newrelic[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([A-Z0-9]{64})['\"]'''
secretGroup = 3
[[rules]]
id = "new-relic-browser-api-token"
description = "New Relic ingest browser API token"
regex = '''['\"](NRJS-[a-f0-9]{19})['\"]'''
[[rules]]
id = "npm-access-token"
description = "npm access token"
regex = '''['\"](npm_(?i)[a-z0-9]{36})['\"]'''
[[rules]]
id = "planetscale-password"
description = "PlanetScale password"
regex = '''pscale_pw_(?i)[a-z0-9\-_\.]{43}'''
[[rules]]
id = "planetscale-api-token"
description = "PlanetScale API token"
regex = '''pscale_tkn_(?i)[a-z0-9\-_\.]{43}'''
[[rules]]
id = "postman-api-token"
description = "Postman API token"
regex = '''PMAK-(?i)[a-f0-9]{24}\-[a-f0-9]{34}'''
[[rules]]
id = "pulumi-api-token"
description = "Pulumi API token"
regex = '''pul-[a-f0-9]{40}'''
[[rules]]
id = "rubygems-api-token"
description = "Rubygem API token"
regex = '''rubygems_[a-f0-9]{48}'''
[[rules]]
id = "sendgrid-api-token"
description = "SendGrid API token"
regex = '''SG\.(?i)[a-z0-9_\-\.]{66}'''
[[rules]]
id = "sendinblue-api-token"
description = "Sendinblue API token"
regex = '''xkeysib-[a-f0-9]{64}\-(?i)[a-z0-9]{16}'''
[[rules]]
id = "shippo-api-token"
description = "Shippo API token"
regex = '''shippo_(live|test)_[a-f0-9]{40}'''
[[rules]]
id = "linkedin-client-secret"
description = "LinkedIn Client secret"
regex = '''(?i)(linkedin[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z]{16})['\"]'''
secretGroup = 3
[[rules]]
id = "linkedin-client-id"
description = "LinkedIn Client ID"
regex = '''(?i)(linkedin[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{14})['\"]'''
secretGroup = 3
[[rules]]
id = "twitch-api-token"
description = "Twitch API token"
regex = '''(?i)(twitch[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([a-z0-9]{30})['\"]'''
secretGroup = 3
[[rules]]
id = "typeform-api-token"
description = "Typeform API token"
regex = '''(?i)(typeform[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}(tfp_[a-z0-9\-_\.=]{59})'''
secretGroup = 3
[[rules]]
id = "generic-api-key"
description = "Generic API Key"
regex = '''(?i)((key|api[^Version]|token|secret|password)[a-z0-9_ .\-,]{0,25})(=|>|:=|\|\|:|<=|=>|:).{0,5}['\"]([0-9a-zA-Z\-_=]{8,64})['\"]'''
entropy = 3.7
secretGroup = 4
[allowlist]
description = "global allow lists"
regexes = ['''219-09-9999''', '''078-05-1120''', '''(9[0-9]{2}|666)-\d{2}-\d{4}''', '''RPM-GPG-KEY.*''']
paths = [
'''gitleaks.toml''',
'''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''',
'''(go.mod|go.sum)$''',
'''salt/nginx/files/enterprise-attack.json'''
]
-203
View File
@@ -1,203 +0,0 @@
body:
- type: markdown
attributes:
value: |
If your organization needs more immediate, enterprise grade professional support, with one-on-one virtual meetings and screensharing, contact us via our website: https://securityonion.com/support
- type: dropdown
attributes:
label: Version
description: Which version of Security Onion are you asking about?
options:
-
- 2.4.10
- 2.4.20
- 2.4.30
- 2.4.40
- 2.4.50
- 2.4.60
- 2.4.70
- 2.4.80
- 2.4.90
- 2.4.100
- 2.4.110
- 2.4.111
- 2.4.120
- 2.4.130
- 2.4.140
- 2.4.141
- 2.4.150
- 2.4.160
- 2.4.170
- 2.4.180
- 2.4.190
- 2.4.200
- 2.4.201
- 2.4.210
- 2.4.211
- Other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Installation Method
description: How did you install Security Onion?
options:
-
- Security Onion ISO image
- Cloud image (Amazon, Azure, Google)
- Network installation on Red Hat derivative like Oracle, Rocky, Alma, etc. (unsupported)
- Network installation on Ubuntu (unsupported)
- Network installation on Debian (unsupported)
- Other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Description
description: >
Is this discussion about installation, configuration, upgrading, or other?
options:
-
- installation
- configuration
- upgrading
- other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Installation Type
description: >
When you installed, did you choose Import, Eval, Standalone, Distributed, or something else?
options:
-
- Import
- Eval
- Standalone
- Distributed
- other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Location
description: >
Is this deployment in the cloud, on-prem with Internet access, or airgap?
options:
-
- cloud
- on-prem with Internet access
- airgap
- other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Hardware Specs
description: >
Does your hardware meet or exceed the minimum requirements for your installation type as shown at https://securityonion.net/docs/hardware?
options:
-
- Meets minimum requirements
- Exceeds minimum requirements
- Does not meet minimum requirements
- other (please provide detail below)
validations:
required: true
- type: input
attributes:
label: CPU
description: How many CPU cores do you have?
validations:
required: true
- type: input
attributes:
label: RAM
description: How much RAM do you have?
validations:
required: true
- type: input
attributes:
label: Storage for /
description: How much storage do you have for the / partition?
validations:
required: true
- type: input
attributes:
label: Storage for /nsm
description: How much storage do you have for the /nsm partition?
validations:
required: true
- type: dropdown
attributes:
label: Network Traffic Collection
description: >
Are you collecting network traffic from a tap or span port?
options:
-
- tap
- span port
- other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Network Traffic Speeds
description: >
How much network traffic are you monitoring?
options:
-
- Less than 1Gbps
- 1Gbps to 10Gbps
- more than 10Gbps
validations:
required: true
- type: dropdown
attributes:
label: Status
description: >
Does SOC Grid show all services on all nodes as running OK?
options:
-
- Yes, all services on all nodes are running OK
- No, one or more services are failed (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Salt Status
description: >
Do you get any failures when you run "sudo salt-call state.highstate"?
options:
-
- Yes, there are salt failures (please provide detail below)
- No, there are no failures
validations:
required: true
- type: dropdown
attributes:
label: Logs
description: >
Are there any additional clues in /opt/so/log/?
options:
-
- Yes, there are additional clues in /opt/so/log/ (please provide detail below)
- No, there are no additional clues
validations:
required: true
- type: textarea
attributes:
label: Detail
description: Please read our discussion guidelines at https://github.com/Security-Onion-Solutions/securityonion/discussions/1720 and then provide detailed information to help us help you.
placeholder: |-
STOP! Before typing, please read our discussion guidelines at https://github.com/Security-Onion-Solutions/securityonion/discussions/1720 in their entirety!
If your organization needs more immediate, enterprise grade professional support, with one-on-one virtual meetings and screensharing, contact us via our website: https://securityonion.com/support
validations:
required: true
- type: checkboxes
attributes:
label: Guidelines
options:
- label: I have read the discussion guidelines at https://github.com/Security-Onion-Solutions/securityonion/discussions/1720 and assert that I have followed the guidelines.
required: true
-178
View File
@@ -1,178 +0,0 @@
body:
- type: markdown
attributes:
value: |
If your organization needs more immediate, enterprise grade professional support, with one-on-one virtual meetings and screensharing, contact us via our website: https://securityonion.com/support
- type: dropdown
attributes:
label: Version
description: Which version of Security Onion are you asking about?
options:
-
- 3.0.0
- 3.1.0
- Other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Installation Method
description: How did you install Security Onion?
options:
-
- Security Onion ISO image
- Cloud image (Amazon, Azure, Google)
- Network installation on Oracle 9 (unsupported)
- Other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Description
description: >
Is this discussion about installation, configuration, upgrading, or other?
options:
-
- installation
- configuration
- upgrading
- other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Installation Type
description: >
When you installed, did you choose Import, Eval, Standalone, Distributed, or something else?
options:
-
- Import
- Eval
- Standalone
- Distributed
- other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Location
description: >
Is this deployment in the cloud, on-prem with Internet access, or airgap?
options:
-
- cloud
- on-prem with Internet access
- airgap
- other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Hardware Specs
description: >
Does your hardware meet or exceed the minimum requirements for your installation type as shown at https://securityonion.net/docs/hardware?
options:
-
- Meets minimum requirements
- Exceeds minimum requirements
- Does not meet minimum requirements
- other (please provide detail below)
validations:
required: true
- type: input
attributes:
label: CPU
description: How many CPU cores do you have?
validations:
required: true
- type: input
attributes:
label: RAM
description: How much RAM do you have?
validations:
required: true
- type: input
attributes:
label: Storage for /
description: How much storage do you have for the / partition?
validations:
required: true
- type: input
attributes:
label: Storage for /nsm
description: How much storage do you have for the /nsm partition?
validations:
required: true
- type: dropdown
attributes:
label: Network Traffic Collection
description: >
Are you collecting network traffic from a tap or span port?
options:
-
- tap
- span port
- other (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Network Traffic Speeds
description: >
How much network traffic are you monitoring?
options:
-
- Less than 1Gbps
- 1Gbps to 10Gbps
- more than 10Gbps
validations:
required: true
- type: dropdown
attributes:
label: Status
description: >
Does SOC Grid show all services on all nodes as running OK?
options:
-
- Yes, all services on all nodes are running OK
- No, one or more services are failed (please provide detail below)
validations:
required: true
- type: dropdown
attributes:
label: Salt Status
description: >
Do you get any failures when you run "sudo salt-call state.highstate"?
options:
-
- Yes, there are salt failures (please provide detail below)
- No, there are no failures
validations:
required: true
- type: dropdown
attributes:
label: Logs
description: >
Are there any additional clues in /opt/so/log/?
options:
-
- Yes, there are additional clues in /opt/so/log/ (please provide detail below)
- No, there are no additional clues
validations:
required: true
- type: textarea
attributes:
label: Detail
description: Please read our discussion guidelines at https://github.com/Security-Onion-Solutions/securityonion/discussions/1720 and then provide detailed information to help us help you.
placeholder: |-
STOP! Before typing, please read our discussion guidelines at https://github.com/Security-Onion-Solutions/securityonion/discussions/1720 in their entirety!
If your organization needs more immediate, enterprise grade professional support, with one-on-one virtual meetings and screensharing, contact us via our website: https://securityonion.com/support
validations:
required: true
- type: checkboxes
attributes:
label: Guidelines
options:
- label: I have read the discussion guidelines at https://github.com/Security-Onion-Solutions/securityonion/discussions/1720 and assert that I have followed the guidelines.
required: true
+12
View File
@@ -0,0 +1,12 @@
PLEASE STOP AND READ THIS INFORMATION!
If you are creating an issue just to ask a question, you will likely get faster and better responses by posting to our discussions forum instead:
https://securityonion.net/discuss
If you think you have found a possible bug or are observing a behavior that you weren't expecting, use the discussion forum to start a conversation about it instead of creating an issue.
If you are very familiar with the latest version of the product and are confident you have found a bug in Security Onion, you can continue with creating an issue here, but please make sure you have done the following:
- duplicated the issue on a fresh installation of the latest version
- provide information about your system and how you installed Security Onion
- include relevant log files
- include reproduction steps
-38
View File
@@ -1,38 +0,0 @@
---
name: Bug report
about: This option is for experienced community members to report a confirmed, reproducible bug
title: ''
labels: ''
assignees: ''
---
PLEASE STOP AND READ THIS INFORMATION!
If you are creating an issue just to ask a question, you will likely get faster and better responses by posting to our discussions forum at https://securityonion.net/discuss.
If you think you have found a possible bug or are observing a behavior that you weren't expecting, use the discussion forum at https://securityonion.net/discuss to start a conversation about it instead of creating an issue.
If you are very familiar with the latest version of the product and are confident you have found a bug in Security Onion, you can continue with creating an issue here, but please make sure you have done the following:
- duplicated the issue on a fresh installation of the latest version
- provide information about your system and how you installed Security Onion
- include relevant log files
- include reproduction steps
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
-5
View File
@@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Security Onion Discussions
url: https://securityonion.com/discussions
about: Please ask and answer questions here
-22
View File
@@ -1,22 +0,0 @@
## Description
<!--
Explain the purpose of the pull request. Be brief or detailed depending on the scope of the changes.
-->
## Related Issues
<!--
Optionally, list any related issues that this pull request addresses.
-->
## Checklist
- [ ] I have read and followed the [CONTRIBUTING.md](https://github.com/Security-Onion-Solutions/securityonion/blob/3/main/CONTRIBUTING.md) file.
- [ ] I have read and agree to the terms of the [Contributor License Agreement](https://securityonionsolutions.com/cla)
## Questions or Comments
<!--
If you have any questions or comments about this pull request, add them here.
-->
-33
View File
@@ -1,33 +0,0 @@
name: 'Close Threads'
on:
schedule:
- cron: '50 1 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
discussions: write
concurrency:
group: lock-threads
jobs:
close-threads:
if: github.repository_owner == 'security-onion-solutions'
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
with:
days-before-issue-stale: -1
days-before-issue-close: 60
stale-issue-message: "This issue is stale because it has been inactive for an extended period. Stale issues convey that the issue, while important to someone, is not critical enough for the author, or other community members to work on, sponsor, or otherwise shepherd the issue through to a resolution."
close-issue-message: "This issue was closed because it has been stale for an extended period. It will be automatically locked in 30 days, after which no further commenting will be available."
days-before-pr-stale: 45
days-before-pr-close: 60
stale-pr-message: "This PR is stale because it has been inactive for an extended period. The longer a PR remains stale the more out of date with the main branch it becomes."
close-pr-message: "This PR was closed because it has been stale for an extended period. It will be automatically locked in 30 days. If there is still a commitment to finishing this PR re-open it before it is locked."
+24
View File
@@ -0,0 +1,24 @@
name: contrib
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened,closed,synchronize]
jobs:
CLAssistant:
runs-on: ubuntu-latest
steps:
- name: "Contributor Check"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
uses: cla-assistant/github-action@v2.3.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
path-to-signatures: 'signatures_v1.json'
path-to-document: 'https://securityonionsolutions.com/cla'
allowlist: dependabot[bot],jertel,dougburks,TOoSmOotH,weslambert,defensivedepth,m0duspwnens
remote-organization-name: Security-Onion-Solutions
remote-repository-name: licensing
+17
View File
@@ -0,0 +1,17 @@
name: leak-test
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: '0'
- name: Gitleaks
uses: gitleaks/gitleaks-action@v1.6.0
with:
config-path: .github/.gitleaks.toml
-26
View File
@@ -1,26 +0,0 @@
name: 'Lock Threads'
on:
schedule:
- cron: '50 2 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
discussions: write
concurrency:
group: lock-threads
jobs:
lock-threads:
if: github.repository_owner == 'security-onion-solutions'
runs-on: ubuntu-latest
steps:
- uses: jertel/lock-threads@main
with:
include-discussion-currently-open: true
discussion-inactive-days: 90
issue-inactive-days: 30
pr-inactive-days: 30
+7 -3
View File
@@ -1,10 +1,14 @@
name: python-test name: python-test
on: on:
push:
paths:
- "salt/sensoroni/files/analyzers/**"
- "salt/manager/tools/sbin"
pull_request: pull_request:
paths: paths:
- "salt/sensoroni/files/analyzers/**" - "salt/sensoroni/files/analyzers/**"
- "salt/manager/tools/sbin/**" - "salt/manager/tools/sbin"
jobs: jobs:
build: build:
@@ -13,7 +17,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
python-version: ["3.14"] python-version: ["3.10"]
python-code-path: ["salt/sensoroni/files/analyzers", "salt/manager/tools/sbin"] python-code-path: ["salt/sensoroni/files/analyzers", "salt/manager/tools/sbin"]
steps: steps:
@@ -32,4 +36,4 @@ jobs:
flake8 ${{ matrix.python-code-path }} --show-source --max-complexity=12 --doctests --max-line-length=200 --statistics flake8 ${{ matrix.python-code-path }} --show-source --max-complexity=12 --doctests --max-line-length=200 --statistics
- name: Test with pytest - name: Test with pytest
run: | run: |
PYTHONPATH=${{ matrix.python-code-path }} pytest ${{ matrix.python-code-path }} --cov=${{ matrix.python-code-path }} --doctest-modules --cov-report=term --cov-fail-under=100 --cov-config=pytest.ini pytest ${{ matrix.python-code-path }} --cov=${{ matrix.python-code-path }} --doctest-modules --cov-report=term --cov-fail-under=100 --cov-config=pytest.ini
+1
View File
@@ -1,3 +1,4 @@
# Created by https://www.gitignore.io/api/macos,windows # Created by https://www.gitignore.io/api/macos,windows
# Edit at https://www.gitignore.io/?templates=macos,windows # Edit at https://www.gitignore.io/?templates=macos,windows
+1 -1
View File
@@ -23,7 +23,7 @@
* Link the PR to the related issue, either using [keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) in the PR description, or [manually](https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/linking-a-pull-request-to-an-issue#manually-linking-a-pull-request-to-an-issue). * Link the PR to the related issue, either using [keywords](https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) in the PR description, or [manually](https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-issues/linking-a-pull-request-to-an-issue#manually-linking-a-pull-request-to-an-issue).
* **Pull requests should be opened against the current `?/dev` branch of this repo**, and should clearly describe the problem and solution. * **Pull requests should be opened against the `dev` branch of this repo**, and should clearly describe the problem and solution.
* Be sure you have tested your changes and are confident they will not break other parts of the product. * Be sure you have tested your changes and are confident they will not break other parts of the product.
+14 -16
View File
@@ -1,53 +1,51 @@
### 3.0.0-20260331 ISO image released on 2026/03/31 ### 2.4.30-20231228 ISO image released on 2024/01/02
### Download and Verify ### Download and Verify
3.0.0-20260331 ISO image: 2.4.30-20231228 ISO image:
https://download.securityonion.net/file/securityonion/securityonion-3.0.0-20260331.iso https://download.securityonion.net/file/securityonion/securityonion-2.4.30-20231228.iso
MD5: ECD318A1662A6FDE0EF213F5A9BD4B07 MD5: DBD47645CD6FA8358C51D8753046FB54
SHA1: E55BE314440CCF3392DC0B06BC5E270B43176D9C SHA1: 2494091065434ACB028F71444A5D16E8F8A11EDF
SHA256: 7FC47405E335CBE5C2B6C51FE7AC60248F35CBE504907B8B5A33822B23F8F4D5 SHA256: 3345AE1DC58AC7F29D82E60D9A36CDF8DE19B7DFF999D8C4F89C7BD36AEE7F1D
Signature for ISO image: Signature for ISO image:
https://github.com/Security-Onion-Solutions/securityonion/raw/3/main/sigs/securityonion-3.0.0-20260331.iso.sig https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.30-20231228.iso.sig
Signing key: Signing key:
https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/3/main/KEYS https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS
For example, here are the steps you can use on most Linux distributions to download and verify our Security Onion ISO image. For example, here are the steps you can use on most Linux distributions to download and verify our Security Onion ISO image.
Download and import the signing key: Download and import the signing key:
``` ```
wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/3/main/KEYS -O - | gpg --import - wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS -O - | gpg --import -
``` ```
Download the signature file for the ISO: Download the signature file for the ISO:
``` ```
wget https://github.com/Security-Onion-Solutions/securityonion/raw/3/main/sigs/securityonion-3.0.0-20260331.iso.sig wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.30-20231228.iso.sig
``` ```
Download the ISO image: Download the ISO image:
``` ```
wget https://download.securityonion.net/file/securityonion/securityonion-3.0.0-20260331.iso wget https://download.securityonion.net/file/securityonion/securityonion-2.4.30-20231228.iso
``` ```
Verify the downloaded ISO image using the signature file: Verify the downloaded ISO image using the signature file:
``` ```
gpg --verify securityonion-3.0.0-20260331.iso.sig securityonion-3.0.0-20260331.iso gpg --verify securityonion-2.4.30-20231228.iso.sig securityonion-2.4.30-20231228.iso
``` ```
The output should show "Good signature" and the Primary key fingerprint should match what's shown below: The output should show "Good signature" and the Primary key fingerprint should match what's shown below:
``` ```
gpg: Signature made Mon 30 Mar 2026 06:22:14 PM EDT using RSA key ID FE507013 gpg: Signature made Thu 28 Dec 2023 10:08:31 AM EST using RSA key ID FE507013
gpg: Good signature from "Security Onion Solutions, LLC <info@securityonionsolutions.com>" gpg: Good signature from "Security Onion Solutions, LLC <info@securityonionsolutions.com>"
gpg: WARNING: This key is not certified with a trusted signature! gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner. gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: C804 A93D 36BE 0C73 3EA1 9644 7C10 60B7 FE50 7013 Primary key fingerprint: C804 A93D 36BE 0C73 3EA1 9644 7C10 60B7 FE50 7013
``` ```
If it fails to verify, try downloading again. If it still fails to verify, try downloading from another computer or another network.
Once you've verified the ISO image, you're ready to proceed to our Installation guide: Once you've verified the ISO image, you're ready to proceed to our Installation guide:
https://securityonion.net/docs/installation https://docs.securityonion.net/en/2.4/installation.html
-53
View File
@@ -1,53 +0,0 @@
Elastic License 2.0 (ELv2)
Acceptance
By using the software, you agree to all of the terms and conditions below.
Copyright License
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below.
Limitations
You may not provide the software to third parties as a hosted or managed service, where the service provides users with access to any substantial set of the features or functionality of the software.
You may not move, change, disable, or circumvent the license key functionality in the software, and you may not remove or obscure any functionality in the software that is protected by the license key.
You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensors trademarks is subject to applicable law.
Patents
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
Notices
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms.
If you modify the software, you must include in any modified copies of the software prominent notices stating that you have modified the software.
No Other Rights
These terms do not imply any licenses other than those expressly granted in these terms.
Termination
If you use the software in violation of these terms, such use is not licensed, and your licenses will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your licenses will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your licenses to terminate automatically and permanently.
No Liability
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
Definitions
The licensor is the entity offering these terms, and the software is the software the licensor makes available under these terms, including any portion of it.
you refers to the individual or entity agreeing to these terms.
your company is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
your licenses are all the licenses granted to you for the software under these terms.
use means anything you do with the software requiring one of your licenses.
trademark means trademarks, service marks, and similar rights.
+27 -38
View File
@@ -1,58 +1,47 @@
<p align="center"> ## Security Onion 2.4
<img src="https://securityonionsolutions.com/logo/logo-so-onion-dark.svg" width="400" alt="Security Onion Logo">
</p>
# Security Onion Security Onion 2.4 is here!
Security Onion is a free and open Linux distribution for threat hunting, enterprise security monitoring, and log management. It includes a comprehensive suite of tools designed to work together to provide visibility into your network and host activity. ## Screenshots
## ✨ Features Alerts
![Alerts](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/50_alerts.png)
Security Onion includes everything you need to monitor your network and host systems: Dashboards
![Dashboards](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/51_dashboards.png)
* **Security Onion Console (SOC)**: A unified web interface for analyzing security events and managing your grid. Hunt
* **Elastic Stack**: Powerful search backed by Elasticsearch. ![Hunt](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/52_hunt.png)
* **Intrusion Detection**: Network-based IDS with Suricata and host-based monitoring with Elastic Fleet.
* **Network Metadata**: Detailed network metadata generated by Zeek or Suricata.
* **Full Packet Capture**: Retain and analyze raw network traffic with Suricata PCAP.
## ⭐ Security Onion Pro PCAP
![PCAP](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/53_pcap.png)
For organizations and enterprises requiring advanced capabilities, **Security Onion Pro** offers additional features designed for scale and efficiency: Grid
![Grid](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/57_grid.png)
* **Onion AI**: Leverage powerful AI-driven insights to accelerate your analysis and investigations. Config
* **Enterprise Features**: Enhanced tools and integrations tailored for enterprise-grade security operations. ![Config](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/61_config.png)
For more information, visit the [Security Onion Pro](https://securityonionsolutions.com/pro) page. ### Release Notes
## ☁️ Cloud Deployment https://docs.securityonion.net/en/2.4/release-notes.html
Security Onion is available and ready to deploy in the **AWS**, **Azure**, and **Google Cloud (GCP)** marketplaces. ### Requirements
## 🚀 Getting Started https://docs.securityonion.net/en/2.4/hardware.html
| Goal | Resource | ### Download
| :--- | :--- |
| **Download** | [Security Onion ISO](https://securityonion.net/docs/download) |
| **Requirements** | [Hardware Guide](https://securityonion.net/docs/hardware) |
| **Install** | [Installation Instructions](https://securityonion.net/docs/installation) |
| **What's New** | [Release Notes](https://securityonion.net/docs/release-notes) |
## 📖 Documentation & Support https://docs.securityonion.net/en/2.4/download.html
For more detailed information, please visit our [Documentation](https://docs.securityonion.net). ### Installation
* **FAQ**: [Frequently Asked Questions](https://securityonion.net/docs/faq) https://docs.securityonion.net/en/2.4/installation.html
* **Community**: [Discussions & Support](https://securityonion.net/docs/community-support)
* **Training**: [Official Training](https://securityonion.net/training)
## 🤝 Contributing ### FAQ
We welcome contributions! Please see our [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on how to get involved. https://docs.securityonion.net/en/2.4/faq.html
## 🛡️ License ### Feedback
Security Onion is licensed under the terms of the license found in the [LICENSE](LICENSE) file. https://docs.securityonion.net/en/2.4/community-support.html
---
*Built with 🧅 by Security Onion Solutions.*
+1 -4
View File
@@ -4,13 +4,10 @@
| Version | Supported | | Version | Supported |
| ------- | ------------------ | | ------- | ------------------ |
| 3.x | :white_check_mark: |
| 2.4.x | :white_check_mark: | | 2.4.x | :white_check_mark: |
| 2.3.x | :x: | | 2.3.x | :white_check_mark: |
| 16.04.x | :x: | | 16.04.x | :x: |
Security Onion 2.3 has reached End Of Life and is no longer supported.
Security Onion 16.04 has reached End Of Life and is no longer supported. Security Onion 16.04 has reached End Of Life and is no longer supported.
## Reporting a Vulnerability ## Reporting a Vulnerability
+1 -1
View File
@@ -1 +1 @@
3.1.0 2.4.40
+1 -2
View File
@@ -41,8 +41,7 @@ file_roots:
base: base:
- /opt/so/saltstack/local/salt - /opt/so/saltstack/local/salt
- /opt/so/saltstack/default/salt - /opt/so/saltstack/default/salt
- /nsm/elastic-fleet/artifacts
- /opt/so/rules/nids
# The master_roots setting configures a master-only copy of the file_roots dictionary, # The master_roots setting configures a master-only copy of the file_roots dictionary,
# used by the state compiler. # used by the state compiler.
-2
View File
@@ -1,2 +0,0 @@
ca:
server:
-34
View File
@@ -1,34 +0,0 @@
{% set node_types = {} %}
{% for minionid, ip in salt.saltutil.runner(
'mine.get',
tgt='elasticsearch:enabled:true',
fun='network.ip_addrs',
tgt_type='pillar') | dictsort()
%}
# only add a node to the pillar if it returned an ip from the mine
{% if ip | length > 0%}
{% set hostname = minionid.split('_') | first %}
{% set node_type = minionid.split('_') | last %}
{% if node_type not in node_types.keys() %}
{% do node_types.update({node_type: {hostname: ip[0]}}) %}
{% else %}
{% if hostname not in node_types[node_type] %}
{% do node_types[node_type].update({hostname: ip[0]}) %}
{% else %}
{% do node_types[node_type][hostname].update(ip[0]) %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
elasticsearch:
nodes:
{% for node_type, values in node_types.items() %}
{{node_type}}:
{% for hostname, ip in values.items() %}
{{hostname}}:
ip: {{ip}}
{% endfor %}
{% endfor %}
-34
View File
@@ -1,34 +0,0 @@
{% set node_types = {} %}
{% for minionid, ip in salt.saltutil.runner(
'mine.get',
tgt='G@role:so-hypervisor or G@role:so-managerhype',
fun='network.ip_addrs',
tgt_type='compound') | dictsort()
%}
# only add a node to the pillar if it returned an ip from the mine
{% if ip | length > 0%}
{% set hostname = minionid.split('_') | first %}
{% set node_type = minionid.split('_') | last %}
{% if node_type not in node_types.keys() %}
{% do node_types.update({node_type: {hostname: ip[0]}}) %}
{% else %}
{% if hostname not in node_types[node_type] %}
{% do node_types[node_type].update({hostname: ip[0]}) %}
{% else %}
{% do node_types[node_type][hostname].update(ip[0]) %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
hypervisor:
nodes:
{% for node_type, values in node_types.items() %}
{{node_type}}:
{% for hostname, ip in values.items() %}
{{hostname}}:
ip: {{ip}}
{% endfor %}
{% endfor %}
-2
View File
@@ -1,2 +0,0 @@
kafka:
nodes:
+5 -4
View File
@@ -1,15 +1,16 @@
{% set node_types = {} %} {% set node_types = {} %}
{% set cached_grains = salt.saltutil.runner('cache.grains', tgt='*') %}
{% for minionid, ip in salt.saltutil.runner( {% for minionid, ip in salt.saltutil.runner(
'mine.get', 'mine.get',
tgt='logstash:enabled:true', tgt='G@role:so-manager or G@role:so-managersearch or G@role:so-standalone or G@role:so-searchnode or G@role:so-heavynode or G@role:so-receiver or G@role:so-fleet ',
fun='network.ip_addrs', fun='network.ip_addrs',
tgt_type='pillar') | dictsort() tgt_type='compound') | dictsort()
%} %}
# only add a node to the pillar if it returned an ip from the mine # only add a node to the pillar if it returned an ip from the mine
{% if ip | length > 0%} {% if ip | length > 0%}
{% set hostname = minionid.split('_') | first %} {% set hostname = cached_grains[minionid]['host'] %}
{% set node_type = minionid.split('_') | last %} {% set node_type = minionid.split('_')[1] %}
{% if node_type not in node_types.keys() %} {% if node_type not in node_types.keys() %}
{% do node_types.update({node_type: {hostname: ip[0]}}) %} {% do node_types.update({node_type: {hostname: ip[0]}}) %}
{% else %} {% else %}
-4
View File
@@ -24,7 +24,6 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if node_types %}
node_data: node_data:
{% for node_type, host_values in node_types.items() %} {% for node_type, host_values in node_types.items() %}
{% for hostname, details in host_values.items() %} {% for hostname, details in host_values.items() %}
@@ -34,6 +33,3 @@ node_data:
role: {{node_type}} role: {{node_type}}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
{% else %}
node_data: False
{% endif %}
-34
View File
@@ -1,34 +0,0 @@
{% set node_types = {} %}
{% for minionid, ip in salt.saltutil.runner(
'mine.get',
tgt='redis:enabled:true',
fun='network.ip_addrs',
tgt_type='pillar') | dictsort()
%}
# only add a node to the pillar if it returned an ip from the mine
{% if ip | length > 0%}
{% set hostname = minionid.split('_') | first %}
{% set node_type = minionid.split('_') | last %}
{% if node_type not in node_types.keys() %}
{% do node_types.update({node_type: {hostname: ip[0]}}) %}
{% else %}
{% if hostname not in node_types[node_type] %}
{% do node_types[node_type].update({hostname: ip[0]}) %}
{% else %}
{% do node_types[node_type][hostname].update(ip[0]) %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
redis:
nodes:
{% for node_type, values in node_types.items() %}
{{node_type}}:
{% for hostname, ip in values.items() %}
{{hostname}}:
ip: {{ip}}
{% endfor %}
{% endfor %}
+38 -61
View File
@@ -1,6 +1,5 @@
base: base:
'*': '*':
- ca
- global.soc_global - global.soc_global
- global.adv_global - global.adv_global
- docker.soc_docker - docker.soc_docker
@@ -17,24 +16,17 @@ base:
- sensoroni.adv_sensoroni - sensoroni.adv_sensoroni
- telegraf.soc_telegraf - telegraf.soc_telegraf
- telegraf.adv_telegraf - telegraf.adv_telegraf
- versionlock.soc_versionlock - users
- versionlock.adv_versionlock
- soc.license
'* and not *_desktop': '* and not *_desktop':
- firewall.soc_firewall - firewall.soc_firewall
- firewall.adv_firewall - firewall.adv_firewall
- nginx.soc_nginx - nginx.soc_nginx
- nginx.adv_nginx - nginx.adv_nginx
'salt-cloud:driver:libvirt':
- match: grain
- vm.soc_vm
- vm.adv_vm
'*_manager or *_managersearch or *_managerhype':
- match: compound
- node_data.ips - node_data.ips
'*_manager or *_managersearch':
- match: compound
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %} {% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
- elasticsearch.auth - elasticsearch.auth
{% endif %} {% endif %}
@@ -44,23 +36,24 @@ base:
- secrets - secrets
- manager.soc_manager - manager.soc_manager
- manager.adv_manager - manager.adv_manager
- idstools.soc_idstools
- idstools.adv_idstools
- logstash.nodes - logstash.nodes
- logstash.soc_logstash - logstash.soc_logstash
- logstash.adv_logstash - logstash.adv_logstash
- soc.soc_soc - soc.soc_soc
- soc.adv_soc - soc.adv_soc
- soc.license
- soctopus.soc_soctopus
- soctopus.adv_soctopus
- kibana.soc_kibana - kibana.soc_kibana
- kibana.adv_kibana - kibana.adv_kibana
- kratos.soc_kratos - kratos.soc_kratos
- kratos.adv_kratos - kratos.adv_kratos
- hydra.soc_hydra
- hydra.adv_hydra
- redis.nodes
- redis.soc_redis - redis.soc_redis
- redis.adv_redis - redis.adv_redis
- influxdb.soc_influxdb - influxdb.soc_influxdb
- influxdb.adv_influxdb - influxdb.adv_influxdb
- elasticsearch.nodes
- elasticsearch.soc_elasticsearch - elasticsearch.soc_elasticsearch
- elasticsearch.adv_elasticsearch - elasticsearch.adv_elasticsearch
- elasticfleet.soc_elasticfleet - elasticfleet.soc_elasticfleet
@@ -69,15 +62,10 @@ base:
- elastalert.adv_elastalert - elastalert.adv_elastalert
- backup.soc_backup - backup.soc_backup
- backup.adv_backup - backup.adv_backup
- soctopus.soc_soctopus
- soctopus.adv_soctopus
- minions.{{ grains.id }} - minions.{{ grains.id }}
- minions.adv_{{ grains.id }} - minions.adv_{{ grains.id }}
- kafka.nodes
- kafka.soc_kafka
- kafka.adv_kafka
- hypervisor.nodes
- hypervisor.soc_hypervisor
- hypervisor.adv_hypervisor
- stig.soc_stig
'*_sensor': '*_sensor':
- healthcheck.sensor - healthcheck.sensor
@@ -87,14 +75,14 @@ base:
- zeek.adv_zeek - zeek.adv_zeek
- bpf.soc_bpf - bpf.soc_bpf
- bpf.adv_bpf - bpf.adv_bpf
- pcap.soc_pcap
- pcap.adv_pcap
- suricata.soc_suricata - suricata.soc_suricata
- suricata.adv_suricata - suricata.adv_suricata
- minions.{{ grains.id }} - minions.{{ grains.id }}
- minions.adv_{{ grains.id }} - minions.adv_{{ grains.id }}
- stig.soc_stig
'*_eval': '*_eval':
- node_data.ips
- secrets - secrets
- healthcheck.eval - healthcheck.eval
- elasticsearch.index_templates - elasticsearch.index_templates
@@ -105,7 +93,6 @@ base:
- kibana.secrets - kibana.secrets
{% endif %} {% endif %}
- kratos.soc_kratos - kratos.soc_kratos
- kratos.adv_kratos
- elasticsearch.soc_elasticsearch - elasticsearch.soc_elasticsearch
- elasticsearch.adv_elasticsearch - elasticsearch.adv_elasticsearch
- elasticfleet.soc_elasticfleet - elasticfleet.soc_elasticfleet
@@ -114,14 +101,19 @@ base:
- elastalert.adv_elastalert - elastalert.adv_elastalert
- manager.soc_manager - manager.soc_manager
- manager.adv_manager - manager.adv_manager
- idstools.soc_idstools
- idstools.adv_idstools
- soc.soc_soc - soc.soc_soc
- soc.adv_soc - soc.adv_soc
- soc.license
- soctopus.soc_soctopus
- soctopus.adv_soctopus
- kibana.soc_kibana - kibana.soc_kibana
- kibana.adv_kibana - kibana.adv_kibana
- strelka.soc_strelka - strelka.soc_strelka
- strelka.adv_strelka - strelka.adv_strelka
- hydra.soc_hydra - kratos.soc_kratos
- hydra.adv_hydra - kratos.adv_kratos
- redis.soc_redis - redis.soc_redis
- redis.adv_redis - redis.adv_redis
- influxdb.soc_influxdb - influxdb.soc_influxdb
@@ -132,13 +124,14 @@ base:
- zeek.adv_zeek - zeek.adv_zeek
- bpf.soc_bpf - bpf.soc_bpf
- bpf.adv_bpf - bpf.adv_bpf
- pcap.soc_pcap
- pcap.adv_pcap
- suricata.soc_suricata - suricata.soc_suricata
- suricata.adv_suricata - suricata.adv_suricata
- minions.{{ grains.id }} - minions.{{ grains.id }}
- minions.adv_{{ grains.id }} - minions.adv_{{ grains.id }}
'*_standalone': '*_standalone':
- node_data.ips
- logstash.nodes - logstash.nodes
- logstash.soc_logstash - logstash.soc_logstash
- logstash.adv_logstash - logstash.adv_logstash
@@ -151,16 +144,14 @@ base:
{% endif %} {% endif %}
- secrets - secrets
- healthcheck.standalone - healthcheck.standalone
- idstools.soc_idstools
- idstools.adv_idstools
- kratos.soc_kratos - kratos.soc_kratos
- kratos.adv_kratos - kratos.adv_kratos
- hydra.soc_hydra
- hydra.adv_hydra
- redis.nodes
- redis.soc_redis - redis.soc_redis
- redis.adv_redis - redis.adv_redis
- influxdb.soc_influxdb - influxdb.soc_influxdb
- influxdb.adv_influxdb - influxdb.adv_influxdb
- elasticsearch.nodes
- elasticsearch.soc_elasticsearch - elasticsearch.soc_elasticsearch
- elasticsearch.adv_elasticsearch - elasticsearch.adv_elasticsearch
- elasticfleet.soc_elasticfleet - elasticfleet.soc_elasticfleet
@@ -171,6 +162,9 @@ base:
- manager.adv_manager - manager.adv_manager
- soc.soc_soc - soc.soc_soc
- soc.adv_soc - soc.adv_soc
- soc.license
- soctopus.soc_soctopus
- soctopus.adv_soctopus
- kibana.soc_kibana - kibana.soc_kibana
- kibana.adv_kibana - kibana.adv_kibana
- strelka.soc_strelka - strelka.soc_strelka
@@ -181,14 +175,12 @@ base:
- zeek.adv_zeek - zeek.adv_zeek
- bpf.soc_bpf - bpf.soc_bpf
- bpf.adv_bpf - bpf.adv_bpf
- pcap.soc_pcap
- pcap.adv_pcap
- suricata.soc_suricata - suricata.soc_suricata
- suricata.adv_suricata - suricata.adv_suricata
- minions.{{ grains.id }} - minions.{{ grains.id }}
- minions.adv_{{ grains.id }} - minions.adv_{{ grains.id }}
- stig.soc_stig
- kafka.nodes
- kafka.soc_kafka
- kafka.adv_kafka
'*_heavynode': '*_heavynode':
- elasticsearch.auth - elasticsearch.auth
@@ -203,6 +195,8 @@ base:
- zeek.adv_zeek - zeek.adv_zeek
- bpf.soc_bpf - bpf.soc_bpf
- bpf.adv_bpf - bpf.adv_bpf
- pcap.soc_pcap
- pcap.adv_pcap
- suricata.soc_suricata - suricata.soc_suricata
- suricata.adv_suricata - suricata.adv_suricata
- strelka.soc_strelka - strelka.soc_strelka
@@ -220,21 +214,15 @@ base:
- logstash.nodes - logstash.nodes
- logstash.soc_logstash - logstash.soc_logstash
- logstash.adv_logstash - logstash.adv_logstash
- elasticsearch.nodes
- elasticsearch.soc_elasticsearch - elasticsearch.soc_elasticsearch
- elasticsearch.adv_elasticsearch - elasticsearch.adv_elasticsearch
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %} {% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
- elasticsearch.auth - elasticsearch.auth
{% endif %} {% endif %}
- redis.nodes
- redis.soc_redis - redis.soc_redis
- redis.adv_redis - redis.adv_redis
- minions.{{ grains.id }} - minions.{{ grains.id }}
- minions.adv_{{ grains.id }} - minions.adv_{{ grains.id }}
- stig.soc_stig
- kafka.nodes
- kafka.soc_kafka
- kafka.adv_kafka
'*_receiver': '*_receiver':
- logstash.nodes - logstash.nodes
@@ -247,14 +235,8 @@ base:
- redis.adv_redis - redis.adv_redis
- minions.{{ grains.id }} - minions.{{ grains.id }}
- minions.adv_{{ grains.id }} - minions.adv_{{ grains.id }}
- kafka.nodes
- kafka.soc_kafka
- stig.soc_stig
- elasticfleet.soc_elasticfleet
- elasticfleet.adv_elasticfleet
'*_import': '*_import':
- node_data.ips
- secrets - secrets
- elasticsearch.index_templates - elasticsearch.index_templates
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %} {% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
@@ -264,7 +246,6 @@ base:
- kibana.secrets - kibana.secrets
{% endif %} {% endif %}
- kratos.soc_kratos - kratos.soc_kratos
- kratos.adv_kratos
- elasticsearch.soc_elasticsearch - elasticsearch.soc_elasticsearch
- elasticsearch.adv_elasticsearch - elasticsearch.adv_elasticsearch
- elasticfleet.soc_elasticfleet - elasticfleet.soc_elasticfleet
@@ -275,12 +256,15 @@ base:
- manager.adv_manager - manager.adv_manager
- soc.soc_soc - soc.soc_soc
- soc.adv_soc - soc.adv_soc
- soc.license
- soctopus.soc_soctopus
- soctopus.adv_soctopus
- kibana.soc_kibana - kibana.soc_kibana
- kibana.adv_kibana - kibana.adv_kibana
- backup.soc_backup - backup.soc_backup
- backup.adv_backup - backup.adv_backup
- hydra.soc_hydra - kratos.soc_kratos
- hydra.adv_hydra - kratos.adv_kratos
- redis.soc_redis - redis.soc_redis
- redis.adv_redis - redis.adv_redis
- influxdb.soc_influxdb - influxdb.soc_influxdb
@@ -289,6 +273,8 @@ base:
- zeek.adv_zeek - zeek.adv_zeek
- bpf.soc_bpf - bpf.soc_bpf
- bpf.adv_bpf - bpf.adv_bpf
- pcap.soc_pcap
- pcap.adv_pcap
- suricata.soc_suricata - suricata.soc_suricata
- suricata.adv_suricata - suricata.adv_suricata
- strelka.soc_strelka - strelka.soc_strelka
@@ -297,7 +283,6 @@ base:
- minions.adv_{{ grains.id }} - minions.adv_{{ grains.id }}
'*_fleet': '*_fleet':
- node_data.ips
- backup.soc_backup - backup.soc_backup
- backup.adv_backup - backup.adv_backup
- logstash.nodes - logstash.nodes
@@ -307,15 +292,7 @@ base:
- elasticfleet.adv_elasticfleet - elasticfleet.adv_elasticfleet
- minions.{{ grains.id }} - minions.{{ grains.id }}
- minions.adv_{{ grains.id }} - minions.adv_{{ grains.id }}
- stig.soc_stig
'*_hypervisor':
- minions.{{ grains.id }}
- minions.adv_{{ grains.id }}
- stig.soc_stig
'*_desktop': '*_desktop':
- minions.{{ grains.id }} - minions.{{ grains.id }}
- minions.adv_{{ grains.id }} - minions.adv_{{ grains.id }}
- stig.soc_stig
+2
View File
@@ -0,0 +1,2 @@
# users pillar goes in /opt/so/saltstack/local/pillar/users/init.sls
# the users directory may need to be created under /opt/so/saltstack/local/pillar
+18
View File
@@ -0,0 +1,18 @@
users:
sclapton:
# required fields
status: present
# node_access determines which node types the user can access.
# this can either be by grains.role or by final part of the minion id after the _
node_access:
- standalone
- searchnode
# optional fields
fullname: Stevie Claptoon
uid: 1001
gid: 1001
homephone: does not have a phone
groups:
- mygroup1
- mygroup2
- wheel # give sudo access
+20
View File
@@ -0,0 +1,20 @@
users:
sclapton:
# required fields
status: <present | absent>
# node_access determines which node types the user can access.
# this can either be by grains.role or by final part of the minion id after the _
node_access:
- standalone
- searchnode
# optional fields
fullname: <string>
uid: <integer>
gid: <integer>
roomnumber: <string>
workphone: <string>
homephone: <string>
groups:
- <string>
- <string>
- wheel # give sudo access
+4 -8
View File
@@ -15,16 +15,12 @@ TARGET_DIR=${1:-.}
PATH=$PATH:/usr/local/bin PATH=$PATH:/usr/local/bin
if [ ! -d .venv ]; then if ! which pytest &> /dev/null || ! which flake8 &> /dev/null ; then
python -m venv .venv echo "Missing dependencies. Consider running the following command:"
fi echo " python -m pip install flake8 pytest pytest-cov"
source .venv/bin/activate
if ! pip install flake8 pytest pytest-cov pyyaml; then
echo "Unable to install dependencies."
exit 1 exit 1
fi fi
pip install pytest pytest-cov
flake8 "$TARGET_DIR" "--config=${HOME_DIR}/pytest.ini" flake8 "$TARGET_DIR" "--config=${HOME_DIR}/pytest.ini"
python3 -m pytest "--cov-config=${HOME_DIR}/pytest.ini" "--cov=$TARGET_DIR" --doctest-modules --cov-report=term --cov-fail-under=100 "$TARGET_DIR" python3 -m pytest "--cov-config=${HOME_DIR}/pytest.ini" "--cov=$TARGET_DIR" --doctest-modules --cov-report=term --cov-fail-under=100 "$TARGET_DIR"
-91
View File
@@ -1,91 +0,0 @@
#!/opt/saltstack/salt/bin/python3
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
#
# Note: Per the Elastic License 2.0, the second limitation states:
#
# "You may not move, change, disable, or circumvent the license key functionality
# in the software, and you may not remove or obscure any functionality in the
# software that is protected by the license key."
"""
Salt execution module for hypervisor operations.
This module provides functions for managing hypervisor configurations,
including VM file management.
"""
import json
import logging
import os
log = logging.getLogger(__name__)
__virtualname__ = 'hypervisor'
def __virtual__():
"""
Only load this module if we're on a system that can manage hypervisors.
"""
return __virtualname__
def remove_vm_from_vms_file(vms_file_path, vm_hostname, vm_role):
"""
Remove a VM entry from the hypervisorVMs file.
Args:
vms_file_path (str): Path to the hypervisorVMs file
vm_hostname (str): Hostname of the VM to remove (without role suffix)
vm_role (str): Role of the VM
Returns:
dict: Result dictionary with success status and message
CLI Example:
salt '*' hypervisor.remove_vm_from_vms_file /opt/so/saltstack/local/salt/hypervisor/hosts/hypervisor1VMs node1 nsm
"""
try:
# Check if file exists
if not os.path.exists(vms_file_path):
msg = f"VMs file not found: {vms_file_path}"
log.error(msg)
return {'result': False, 'comment': msg}
# Read current VMs
with open(vms_file_path, 'r') as f:
content = f.read().strip()
vms = json.loads(content) if content else []
# Find and remove the VM entry
original_count = len(vms)
vms = [vm for vm in vms if not (vm.get('hostname') == vm_hostname and vm.get('role') == vm_role)]
if len(vms) < original_count:
# VM was found and removed, write back to file
with open(vms_file_path, 'w') as f:
json.dump(vms, f, indent=2)
# Set socore:socore ownership (939:939)
os.chown(vms_file_path, 939, 939)
msg = f"Removed VM {vm_hostname}_{vm_role} from {vms_file_path}"
log.info(msg)
return {'result': True, 'comment': msg}
else:
msg = f"VM {vm_hostname}_{vm_role} not found in {vms_file_path}"
log.warning(msg)
return {'result': False, 'comment': msg}
except json.JSONDecodeError as e:
msg = f"Failed to parse JSON in {vms_file_path}: {str(e)}"
log.error(msg)
return {'result': False, 'comment': msg}
except Exception as e:
msg = f"Failed to remove VM {vm_hostname}_{vm_role} from {vms_file_path}: {str(e)}"
log.error(msg)
return {'result': False, 'comment': msg}
+10
View File
@@ -1,9 +1,16 @@
from os import path
import subprocess import subprocess
def check(): def check():
osfam = __grains__['os_family']
retval = 'False' retval = 'False'
if osfam == 'Debian':
if path.exists('/var/run/reboot-required'):
retval = 'True'
elif osfam == 'RedHat':
cmd = 'needs-restarting -r > /dev/null 2>&1' cmd = 'needs-restarting -r > /dev/null 2>&1'
try: try:
@@ -11,4 +18,7 @@ def check():
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
retval = 'True' retval = 'True'
else:
retval = 'Unsupported OS: %s' % os
return retval return retval
-335
View File
@@ -1,335 +0,0 @@
#!py
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
"""
Salt module for managing QCOW2 image configurations and VM hardware settings. This module provides functions
for modifying network configurations within QCOW2 images, adjusting virtual machine hardware settings, and
creating virtual storage volumes. It serves as a Salt interface to the so-qcow2-modify-network,
so-kvm-modify-hardware, and so-kvm-create-volume scripts.
The module offers three main capabilities:
1. Network Configuration: Modify network settings (DHCP/static IP) within QCOW2 images
2. Hardware Configuration: Adjust VM hardware settings (CPU, memory, PCI passthrough)
3. Volume Management: Create and attach virtual storage volumes for NSM data
This module is intended to work with Security Onion's virtualization infrastructure and is typically
used in conjunction with salt-cloud for VM provisioning and management.
"""
import logging
import subprocess
import shlex
log = logging.getLogger(__name__)
__virtualname__ = 'qcow2'
def __virtual__():
return __virtualname__
def modify_network_config(image, interface, mode, vm_name, ip4=None, gw4=None, dns4=None, search4=None):
'''
Usage:
salt '*' qcow2.modify_network_config image=<path> interface=<iface> mode=<mode> vm_name=<name> [ip4=<addr>] [gw4=<addr>] [dns4=<servers>] [search4=<domain>]
Options:
image
Path to the QCOW2 image file that will be modified
interface
Network interface name to configure (e.g., 'enp1s0')
mode
Network configuration mode, either 'dhcp4' or 'static4'
vm_name
Full name of the VM (hostname_role)
ip4
IPv4 address with CIDR notation (e.g., '192.168.1.10/24')
Required when mode='static4'
gw4
IPv4 gateway address (e.g., '192.168.1.1')
Required when mode='static4'
dns4
Comma-separated list of IPv4 DNS servers (e.g., '8.8.8.8,8.8.4.4')
Optional for both DHCP and static configurations
search4
DNS search domain for IPv4 (e.g., 'example.local')
Optional for both DHCP and static configurations
Examples:
1. **Configure DHCP:**
```bash
salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='enp1s0' mode='dhcp4'
```
This configures enp1s0 to use DHCP for IP assignment
2. **Configure Static IP:**
```bash
salt '*' qcow2.modify_network_config image='/nsm/libvirt/images/sool9/sool9.qcow2' interface='enp1s0' mode='static4' ip4='192.168.1.10/24' gw4='192.168.1.1' dns4='192.168.1.1,8.8.8.8' search4='example.local'
```
This sets a static IP configuration with DNS servers and search domain
Notes:
- The QCOW2 image must be accessible and writable by the salt minion
- The image should not be in use by a running VM when modified
- Network changes take effect on next VM boot
- Requires so-qcow2-modify-network script to be installed
Description:
This function modifies network configuration within a QCOW2 image file by executing
the so-qcow2-modify-network script. It supports both DHCP and static IPv4 configuration.
The script mounts the image, modifies the network configuration files, and unmounts
safely. All operations are logged for troubleshooting purposes.
Exit Codes:
0: Success
1: Invalid parameters or configuration
2: Image access or mounting error
3: Network configuration error
4: System command error
255: Unexpected error
Logging:
- All operations are logged to the salt minion log
- Log entries are prefixed with 'qcow2 module:'
- Error conditions include detailed error messages and stack traces
- Success/failure status is logged for verification
'''
cmd = ['/usr/sbin/so-qcow2-modify-network', '-I', image, '-i', interface, '-n', vm_name]
if mode.lower() == 'dhcp4':
cmd.append('--dhcp4')
elif mode.lower() == 'static4':
cmd.append('--static4')
if not ip4 or not gw4:
raise ValueError('Both ip4 and gw4 are required for static configuration.')
cmd.extend(['--ip4', ip4, '--gw4', gw4])
if dns4:
cmd.extend(['--dns4', dns4])
if search4:
cmd.extend(['--search4', search4])
else:
raise ValueError("Invalid mode '{}'. Expected 'dhcp4' or 'static4'.".format(mode))
log.info('qcow2 module: Executing command: {}'.format(' '.join(shlex.quote(arg) for arg in cmd)))
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
ret = {
'retcode': result.returncode,
'stdout': result.stdout,
'stderr': result.stderr
}
if result.returncode != 0:
log.error('qcow2 module: Script execution failed with return code {}: {}'.format(result.returncode, result.stderr))
else:
log.info('qcow2 module: Script executed successfully.')
return ret
except Exception as e:
log.error('qcow2 module: An error occurred while executing the script: {}'.format(e))
raise
def modify_hardware_config(vm_name, cpu=None, memory=None, pci=None, start=False):
'''
Usage:
salt '*' qcow2.modify_hardware_config vm_name=<name> [cpu=<count>] [memory=<size>] [pci=<id>] [pci=<id>] [start=<bool>]
Options:
vm_name
Name of the virtual machine to modify
cpu
Number of virtual CPUs to assign (positive integer)
Optional - VM's current CPU count retained if not specified
memory
Amount of memory to assign in MiB (positive integer)
Optional - VM's current memory size retained if not specified
pci
PCI hardware ID(s) to passthrough to the VM (e.g., '0000:c7:00.0')
Can be specified multiple times for multiple devices
Optional - no PCI passthrough if not specified
start
Boolean flag to start the VM after modification
Optional - defaults to False
Examples:
1. **Modify CPU and Memory:**
```bash
salt '*' qcow2.modify_hardware_config vm_name='sensor1' cpu=4 memory=8192
```
This assigns 4 CPUs and 8GB memory to the VM
2. **Enable PCI Passthrough:**
```bash
salt '*' qcow2.modify_hardware_config vm_name='sensor1' pci='0000:c7:00.0' pci='0000:c4:00.0' start=True
```
This configures PCI passthrough and starts the VM
3. **Complete Hardware Configuration:**
```bash
salt '*' qcow2.modify_hardware_config vm_name='sensor1' cpu=8 memory=16384 pci='0000:c7:00.0' start=True
```
This sets CPU, memory, PCI passthrough, and starts the VM
Notes:
- VM must be stopped before modification unless only the start flag is set
- Memory is specified in MiB (1024 = 1GB)
- PCI devices must be available and not in use by the host
- CPU count should align with host capabilities
- Requires so-kvm-modify-hardware script to be installed
Description:
This function modifies the hardware configuration of a KVM virtual machine using
the so-kvm-modify-hardware script. It can adjust CPU count, memory allocation,
and PCI device passthrough. Changes are applied to the VM's libvirt configuration.
The VM can optionally be started after modifications are complete.
Exit Codes:
0: Success
1: Invalid parameters
2: VM state error (running when should be stopped)
3: Hardware configuration error
4: System command error
255: Unexpected error
Logging:
- All operations are logged to the salt minion log
- Log entries are prefixed with 'qcow2 module:'
- Hardware configuration changes are logged
- Errors include detailed messages and stack traces
- Final status of modification is logged
'''
cmd = ['/usr/sbin/so-kvm-modify-hardware', '-v', vm_name]
if cpu is not None:
if isinstance(cpu, int) and cpu > 0:
cmd.extend(['-c', str(cpu)])
else:
raise ValueError('cpu must be a positive integer.')
if memory is not None:
if isinstance(memory, int) and memory > 0:
cmd.extend(['-m', str(memory)])
else:
raise ValueError('memory must be a positive integer.')
if pci:
# Handle PCI IDs (can be a single device or comma-separated list)
if isinstance(pci, str):
devices = [dev.strip() for dev in pci.split(',') if dev.strip()]
elif isinstance(pci, list):
devices = pci
else:
devices = [pci]
# Add each device with its own -p flag
for device in devices:
cmd.extend(['-p', str(device)])
if start:
cmd.append('-s')
log.info('qcow2 module: Executing command: {}'.format(' '.join(shlex.quote(arg) for arg in cmd)))
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
ret = {
'retcode': result.returncode,
'stdout': result.stdout,
'stderr': result.stderr
}
if result.returncode != 0:
log.error('qcow2 module: Script execution failed with return code {}: {}'.format(result.returncode, result.stderr))
else:
log.info('qcow2 module: Script executed successfully.')
return ret
except Exception as e:
log.error('qcow2 module: An error occurred while executing the script: {}'.format(e))
raise
def create_volume_config(vm_name, size_gb, start=False):
'''
Usage:
salt '*' qcow2.create_volume_config vm_name=<name> size_gb=<size> [start=<bool>]
Options:
vm_name
Name of the virtual machine to attach the volume to
size_gb
Volume size in GB (positive integer)
This determines the capacity of the virtual storage volume
start
Boolean flag to start the VM after volume creation
Optional - defaults to False
Examples:
1. **Create 500GB Volume:**
```bash
salt '*' qcow2.create_volume_config vm_name='sensor1_sensor' size_gb=500
```
This creates a 500GB virtual volume for NSM storage
2. **Create 1TB Volume and Start VM:**
```bash
salt '*' qcow2.create_volume_config vm_name='sensor1_sensor' size_gb=1000 start=True
```
This creates a 1TB volume and starts the VM after attachment
Notes:
- VM must be stopped before volume creation
- Volume is created as a qcow2 image and attached to the VM
- This is an alternative to disk passthrough via modify_hardware_config
- Volume is automatically attached to the VM's libvirt configuration
- Requires so-kvm-create-volume script to be installed
- Volume files are stored in the hypervisor's VM storage directory
Description:
This function creates and attaches a virtual storage volume to a KVM virtual machine
using the so-kvm-create-volume script. It creates a qcow2 disk image of the specified
size and attaches it to the VM for NSM (Network Security Monitoring) storage purposes.
This provides an alternative to physical disk passthrough, allowing flexible storage
allocation without requiring dedicated hardware. The VM can optionally be started
after the volume is successfully created and attached.
Exit Codes:
0: Success
1: Invalid parameters
2: VM state error (running when should be stopped)
3: Volume creation error
4: System command error
255: Unexpected error
Logging:
- All operations are logged to the salt minion log
- Log entries are prefixed with 'qcow2 module:'
- Volume creation and attachment operations are logged
- Errors include detailed messages and stack traces
- Final status of volume creation is logged
'''
# Validate size_gb parameter
if not isinstance(size_gb, int) or size_gb <= 0:
raise ValueError('size_gb must be a positive integer.')
cmd = ['/usr/sbin/so-kvm-create-volume', '-v', vm_name, '-s', str(size_gb)]
if start:
cmd.append('-S')
log.info('qcow2 module: Executing command: {}'.format(' '.join(shlex.quote(arg) for arg in cmd)))
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
ret = {
'retcode': result.returncode,
'stdout': result.stdout,
'stderr': result.stderr
}
if result.returncode != 0:
log.error('qcow2 module: Script execution failed with return code {}: {}'.format(result.returncode, result.stderr))
else:
log.info('qcow2 module: Script executed successfully.')
return ret
except Exception as e:
log.error('qcow2 module: An error occurred while executing the script: {}'.format(e))
raise
File diff suppressed because it is too large Load Diff
+225 -131
View File
@@ -1,160 +1,254 @@
{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
https://securityonion.net/license; you may not use this file except in compliance with the # https://securityonion.net/license; you may not use this file except in compliance with the
Elastic License 2.0. #} # Elastic License 2.0.
{% set ISAIRGAP = salt['pillar.get']('global:airgap', False) %} {% set ISAIRGAP = salt['pillar.get']('global:airgap', False) %}
{% import_yaml 'salt/minion.defaults.yaml' as saltversion %} {% import_yaml 'salt/minion.defaults.yaml' as saltversion %}
{% set saltversion = saltversion.salt.minion.version %} {% set saltversion = saltversion.salt.minion.version %}
{# Define common state groups to reduce redundancy #} {# this is the list we are returning from this map file, it gets built below #}
{% set base_states = [ {% set allowed_states= [] %}
'common',
'patch.os.schedule', {% if grains.saltversion | string == saltversion | string %}
'motd',
'salt.minion-check', {% set allowed_states= salt['grains.filter_by']({
'sensoroni', 'so-eval': [
'salt.lasthighstate', 'salt.master',
'salt.minion', 'ca',
'ssl',
'registry',
'manager',
'nginx',
'telegraf',
'influxdb',
'soc',
'kratos',
'elasticfleet',
'elastic-fleet-package-registry',
'firewall',
'idstools',
'suricata.manager',
'healthcheck',
'pcap',
'suricata',
'utility',
'schedule',
'soctopus',
'tcpreplay',
'docker_clean'
],
'so-heavynode': [
'ssl',
'nginx',
'telegraf',
'firewall',
'pcap',
'suricata',
'healthcheck',
'elasticagent',
'schedule',
'tcpreplay',
'docker_clean'
],
'so-idh': [
'ssl',
'telegraf',
'firewall',
'idh',
'schedule',
'docker_clean'
],
'so-import': [
'salt.master',
'ca',
'ssl',
'registry',
'manager',
'nginx',
'soc',
'kratos',
'influxdb',
'telegraf',
'firewall',
'idstools',
'suricata.manager',
'pcap',
'utility',
'suricata',
'zeek',
'schedule',
'tcpreplay',
'docker_clean',
'elasticfleet',
'elastic-fleet-package-registry'
],
'so-manager': [
'salt.master',
'ca',
'ssl',
'registry',
'manager',
'nginx',
'telegraf',
'influxdb',
'soc',
'kratos',
'elasticfleet',
'elastic-fleet-package-registry',
'firewall',
'idstools',
'suricata.manager',
'utility',
'schedule',
'soctopus',
'docker_clean'
],
'so-managersearch': [
'salt.master',
'ca',
'ssl',
'registry',
'nginx',
'telegraf',
'influxdb',
'soc',
'kratos',
'elastic-fleet-package-registry',
'elasticfleet',
'firewall',
'manager',
'idstools',
'suricata.manager',
'utility',
'schedule',
'soctopus',
'docker_clean'
],
'so-searchnode': [
'ssl',
'nginx',
'telegraf', 'telegraf',
'firewall', 'firewall',
'schedule', 'schedule',
'docker_clean' 'docker_clean'
] %} ],
'so-standalone': [
{% set manager_states = [
'salt.master', 'salt.master',
'ca.server', 'ca',
'ssl',
'registry', 'registry',
'manager', 'manager',
'nginx', 'nginx',
'telegraf',
'influxdb', 'influxdb',
'soc', 'soc',
'kratos', 'kratos',
'hydra',
'elasticfleet',
'elastic-fleet-package-registry', 'elastic-fleet-package-registry',
'utility' 'elasticfleet',
] %} 'firewall',
'idstools',
{% set sensor_states = [ 'suricata.manager',
'pcap',
'suricata', 'suricata',
'healthcheck', 'healthcheck',
'utility',
'schedule',
'soctopus',
'tcpreplay', 'tcpreplay',
'zeek', 'docker_clean'
'strelka' ],
] %} 'so-sensor': [
'ssl',
{% set kafka_states = [ 'telegraf',
'kafka' 'firewall',
] %} 'nginx',
'pcap',
{% set stig_states = [ 'suricata',
'stig' 'healthcheck',
] %} 'schedule',
'tcpreplay',
{% set elastic_stack_states = [ 'docker_clean'
'elasticsearch', ],
'elasticsearch.auth', 'so-fleet': [
'kibana', 'ssl',
'kibana.secrets', 'telegraf',
'elastalert', 'firewall',
'logstash', 'logstash',
'redis' 'healthcheck',
] %} 'schedule',
'elasticfleet',
'docker_clean'
],
'so-receiver': [
'ssl',
'telegraf',
'firewall',
'schedule',
'docker_clean'
],
'so-desktop': [
'ssl',
'docker_clean',
'telegraf'
],
}, grain='role') %}
{# Initialize the allowed_states list #} {% if grains.role in ['so-eval', 'so-manager', 'so-managersearch', 'so-standalone'] %}
{% set allowed_states = [] %} {% do allowed_states.append('mysql') %}
{% if grains.saltversion | string == saltversion | string %}
{# Map role-specific states #}
{% set role_states = {
'so-eval': (
manager_states +
sensor_states +
elastic_stack_states | reject('equalto', 'logstash') | list +
['logstash.ssl']
),
'so-heavynode': (
sensor_states +
['elasticagent', 'elasticsearch', 'logstash', 'redis', 'nginx']
),
'so-idh': (
['idh']
),
'so-import': (
manager_states +
sensor_states | reject('equalto', 'strelka') | reject('equalto', 'healthcheck') | list +
['elasticsearch', 'elasticsearch.auth', 'kibana', 'kibana.secrets', 'logstash.ssl', 'strelka.manager']
),
'so-manager': (
manager_states +
['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users', 'strelka.manager'] +
stig_states +
kafka_states +
elastic_stack_states
),
'so-managerhype': (
manager_states +
['salt.cloud', 'strelka.manager', 'hypervisor', 'libvirt'] +
stig_states +
kafka_states +
elastic_stack_states
),
'so-managersearch': (
manager_states +
['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users', 'strelka.manager'] +
stig_states +
kafka_states +
elastic_stack_states
),
'so-searchnode': (
['kafka.ca', 'kafka.ssl', 'elasticsearch', 'logstash', 'nginx'] +
stig_states
),
'so-standalone': (
manager_states +
['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users'] +
sensor_states +
stig_states +
kafka_states +
elastic_stack_states
),
'so-sensor': (
sensor_states +
['nginx'] +
stig_states
),
'so-fleet': (
stig_states +
['logstash', 'nginx', 'healthcheck', 'elasticfleet']
),
'so-receiver': (
kafka_states +
stig_states +
['logstash', 'redis']
),
'so-hypervisor': (
stig_states +
['hypervisor', 'libvirt']
),
'so-desktop': (
stig_states
)
} %}
{# Get states for the current role #}
{% if grains.role in role_states %}
{% set allowed_states = role_states[grains.role] %}
{% endif %} {% endif %}
{# Add base states that apply to all roles #} {%- if grains.role in ['so-sensor', 'so-eval', 'so-standalone', 'so-heavynode'] %}
{% for state in base_states %} {% do allowed_states.append('zeek') %}
{% do allowed_states.append(state) %} {%- endif %}
{% endfor %}
{% if grains.role in ['so-sensor', 'so-eval', 'so-standalone', 'so-heavynode'] %}
{% do allowed_states.append('strelka') %}
{% endif %}
{% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-searchnode', 'so-managersearch', 'so-heavynode', 'so-import'] %}
{% do allowed_states.append('elasticsearch') %}
{% endif %}
{% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %}
{% do allowed_states.append('elasticsearch.auth') %}
{% endif %}
{% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %}
{% do allowed_states.append('kibana') %}
{% do allowed_states.append('kibana.secrets') %}
{% endif %}
{% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch'] %}
{% do allowed_states.append('elastalert') %}
{% endif %}
{% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch'] %}
{% do allowed_states.append('playbook') %}
{% endif %}
{% if grains.role in ['so-manager', 'so-standalone', 'so-searchnode', 'so-managersearch', 'so-heavynode', 'so-receiver'] %}
{% do allowed_states.append('logstash') %}
{% endif %}
{% if grains.role in ['so-manager', 'so-standalone', 'so-managersearch', 'so-heavynode', 'so-receiver', 'so-eval'] %}
{% do allowed_states.append('redis') %}
{% endif %}
{# all nodes on the right salt version can run the following states #}
{% do allowed_states.append('common') %}
{% do allowed_states.append('patch.os.schedule') %}
{% do allowed_states.append('motd') %}
{% do allowed_states.append('salt.minion-check') %}
{% do allowed_states.append('sensoroni') %}
{% do allowed_states.append('salt.lasthighstate') %}
{% endif %} {% endif %}
{# Add airgap state if needed #}
{% if ISAIRGAP %} {% if ISAIRGAP %}
{% do allowed_states.append('airgap') %} {% do allowed_states.append('airgap') %}
{% endif %} {% endif %}
{# all nodes can always run salt.minion state #}
{% do allowed_states.append('salt.minion') %}
-1
View File
@@ -4,5 +4,4 @@ backup:
- /etc/pki - /etc/pki
- /etc/salt - /etc/salt
- /nsm/kratos - /nsm/kratos
- /nsm/hydra
destination: "/nsm/backup" destination: "/nsm/backup"
+2 -2
View File
@@ -1,10 +1,10 @@
backup: backup:
locations: locations:
description: List of locations to back up to the destination. description: List of locations to back up to the destination.
helpLink: backup helpLink: backup.html
global: True global: True
destination: destination:
description: Directory to store the configuration backups in. description: Directory to store the configuration backups in.
helpLink: backup helpLink: backup.html
global: True global: True
@@ -11,10 +11,6 @@ TODAY=$(date '+%Y_%m_%d')
BACKUPDIR={{ DESTINATION }} BACKUPDIR={{ DESTINATION }}
BACKUPFILE="$BACKUPDIR/so-config-backup-$TODAY.tar" BACKUPFILE="$BACKUPDIR/so-config-backup-$TODAY.tar"
MAXBACKUPS=7 MAXBACKUPS=7
EXCLUSIONS=(
"--exclude=/opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers"
)
# Create backup dir if it does not exist # Create backup dir if it does not exist
mkdir -p /nsm/backup mkdir -p /nsm/backup
@@ -27,7 +23,7 @@ if [ ! -f $BACKUPFILE ]; then
# Loop through all paths defined in global.sls, and append them to backup file # Loop through all paths defined in global.sls, and append them to backup file
{%- for LOCATION in BACKUPLOCATIONS %} {%- for LOCATION in BACKUPLOCATIONS %}
tar -rf $BACKUPFILE "${EXCLUSIONS[@]}" {{ LOCATION }} tar -rf $BACKUPFILE {{ LOCATION }}
{%- endfor %} {%- endfor %}
fi fi
+2 -4
View File
@@ -1,12 +1,10 @@
{% macro remove_comments(bpfmerged, app) %} {% macro remove_comments(bpfmerged, app) %}
{# remove comments from the bpf #} {# remove comments from the bpf #}
{% set app_list = [] %}
{% for bpf in bpfmerged[app] %} {% for bpf in bpfmerged[app] %}
{% if not bpf.strip().startswith('#') %} {% if bpf.strip().startswith('#') %}
{% do app_list.append(bpf) %} {% do bpfmerged[app].pop(loop.index0) %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% do bpfmerged.update({app: app_list}) %}
{% endmacro %} {% endmacro %}
+3 -11
View File
@@ -1,15 +1,7 @@
{% from 'vars/globals.map.jinja' import GLOBALS %}
{% set PCAP_BPF_STATUS = 0 %}
{% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %} {% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %}
{% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %} {% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %}
{% import 'bpf/macros.jinja' as MACROS %} {% import 'bpf/macros.jinja' as MACROS %}
{{ MACROS.remove_comments(BPFMERGED, 'pcap') }}
{% set PCAPBPF = BPFMERGED.pcap %}
{% if PCAPBPF %} {{ MACROS.remove_comments(BPFMERGED, 'pcap') }}
{% set PCAP_BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + PCAPBPF|join(" "),cwd='/root') %}
{% if PCAP_BPF_CALC['retcode'] == 0 %} {% set PCAPBPF = BPFMERGED.pcap %}
{% set PCAP_BPF_STATUS = 1 %}
{% endif %}
{% endif %}
+5 -5
View File
@@ -1,16 +1,16 @@
bpf: bpf:
pcap: pcap:
description: List of BPF filters to apply to the PCAP engine. description: List of BPF filters to apply to PCAP.
multiline: True multiline: True
forcedType: "[]string" forcedType: "[]string"
helpLink: bpf helpLink: bpf.html
suricata: suricata:
description: List of BPF filters to apply to Suricata. This will apply to alerts and, if enabled, to metadata and PCAP logs generated by Suricata. description: List of BPF filters to apply to Suricata.
multiline: True multiline: True
forcedType: "[]string" forcedType: "[]string"
helpLink: bpf helpLink: bpf.html
zeek: zeek:
description: List of BPF filters to apply to Zeek. description: List of BPF filters to apply to Zeek.
multiline: True multiline: True
forcedType: "[]string" forcedType: "[]string"
helpLink: bpf helpLink: bpf.html
-9
View File
@@ -1,16 +1,7 @@
{% from 'vars/globals.map.jinja' import GLOBALS %}
{% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %} {% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %}
{% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %} {% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %}
{% set SURICATA_BPF_STATUS = 0 %}
{% import 'bpf/macros.jinja' as MACROS %} {% import 'bpf/macros.jinja' as MACROS %}
{{ MACROS.remove_comments(BPFMERGED, 'suricata') }} {{ MACROS.remove_comments(BPFMERGED, 'suricata') }}
{% set SURICATABPF = BPFMERGED.suricata %} {% set SURICATABPF = BPFMERGED.suricata %}
{% if SURICATABPF %}
{% set SURICATA_BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + SURICATABPF|join(" "),cwd='/root') %}
{% if SURICATA_BPF_CALC['retcode'] == 0 %}
{% set SURICATA_BPF_STATUS = 1 %}
{% endif %}
{% endif %}
-9
View File
@@ -1,16 +1,7 @@
{% from 'vars/globals.map.jinja' import GLOBALS %}
{% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %} {% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %}
{% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %} {% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %}
{% set ZEEK_BPF_STATUS = 0 %}
{% import 'bpf/macros.jinja' as MACROS %} {% import 'bpf/macros.jinja' as MACROS %}
{{ MACROS.remove_comments(BPFMERGED, 'zeek') }} {{ MACROS.remove_comments(BPFMERGED, 'zeek') }}
{% set ZEEKBPF = BPFMERGED.zeek %} {% set ZEEKBPF = BPFMERGED.zeek %}
{% if ZEEKBPF %}
{% set ZEEK_BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + ZEEKBPF|join(" "),cwd='/root') %}
{% if ZEEK_BPF_CALC['retcode'] == 0 %}
{% set ZEEK_BPF_STATUS = 1 %}
{% endif %}
{% endif %}
+4
View File
@@ -0,0 +1,4 @@
pki_issued_certs:
file.directory:
- name: /etc/pki/issued_certs
- makedirs: True
+3 -14
View File
@@ -1,3 +1,6 @@
mine_functions:
x509.get_pem_entries: [/etc/pki/ca.crt]
x509_signing_policies: x509_signing_policies:
filebeat: filebeat:
- minions: '*' - minions: '*'
@@ -67,17 +70,3 @@ x509_signing_policies:
- authorityKeyIdentifier: keyid,issuer:always - authorityKeyIdentifier: keyid,issuer:always
- days_valid: 820 - days_valid: 820
- copypath: /etc/pki/issued_certs/ - copypath: /etc/pki/issued_certs/
kafka:
- minions: '*'
- signing_private_key: /etc/pki/ca.key
- signing_cert: /etc/pki/ca.crt
- C: US
- ST: Utah
- L: Salt Lake City
- basicConstraints: "critical CA:false"
- keyUsage: "digitalSignature, keyEncipherment"
- subjectKeyIdentifier: hash
- authorityKeyIdentifier: keyid,issuer:always
- extendedKeyUsage: "serverAuth, clientAuth"
- days_valid: 820
- copypath: /etc/pki/issued_certs/
+63 -3
View File
@@ -3,10 +3,70 @@
# https://securityonion.net/license; you may not use this file except in compliance with the # https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0. # Elastic License 2.0.
{% from 'allowed_states.map.jinja' import allowed_states %}
{% if sls in allowed_states %}
{% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'vars/globals.map.jinja' import GLOBALS %}
include: include:
{% if GLOBALS.is_manager %} - ca.dirs
- ca.server
/etc/salt/minion.d/signing_policies.conf:
file.managed:
- source: salt://ca/files/signing_policies.conf
pki_private_key:
x509.private_key_managed:
- name: /etc/pki/ca.key
- keysize: 4096
- passphrase:
- backup: True
{% if salt['file.file_exists']('/etc/pki/ca.key') -%}
- prereq:
- x509: /etc/pki/ca.crt
{%- endif %}
pki_public_ca_crt:
x509.certificate_managed:
- name: /etc/pki/ca.crt
- signing_private_key: /etc/pki/ca.key
- CN: {{ GLOBALS.manager }}
- C: US
- ST: Utah
- L: Salt Lake City
- basicConstraints: "critical CA:true"
- keyUsage: "critical cRLSign, keyCertSign"
- extendedkeyUsage: "serverAuth, clientAuth"
- subjectKeyIdentifier: hash
- authorityKeyIdentifier: keyid:always, issuer
- days_valid: 3650
- days_remaining: 0
- backup: True
- replace: False
- require:
- sls: ca.dirs
- timeout: 30
- retry:
attempts: 5
interval: 30
mine_update_ca_crt:
module.run:
- mine.update: []
- onchanges:
- x509: pki_public_ca_crt
cakeyperms:
file.managed:
- replace: False
- name: /etc/pki/ca.key
- mode: 640
- group: 939
{% else %}
{{sls}}_state_not_allowed:
test.fail_without_changes:
- name: {{sls}}_state_not_allowed
{% endif %} {% endif %}
- ca.trustca
-3
View File
@@ -1,3 +0,0 @@
{% set CA = {
'server': pillar.ca.server
}%}
+2 -30
View File
@@ -1,35 +1,7 @@
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one pki_private_key:
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
{% set setup_running = salt['cmd.retcode']('pgrep -x so-setup') == 0 %}
{% if setup_running%}
include:
- ssl.remove
remove_pki_private_key:
file.absent: file.absent:
- name: /etc/pki/ca.key - name: /etc/pki/ca.key
remove_pki_public_ca_crt: pki_public_ca_crt:
file.absent: file.absent:
- name: /etc/pki/ca.crt - name: /etc/pki/ca.crt
remove_trusttheca:
file.absent:
- name: /etc/pki/tls/certs/intca.crt
remove_pki_public_ca_crt_symlink:
file.absent:
- name: /opt/so/saltstack/local/salt/ca/files/ca.crt
{% else %}
so-setup_not_running:
test.show_notification:
- text: "This state is reserved for usage during so-setup."
{% endif %}
-63
View File
@@ -1,63 +0,0 @@
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
{% from 'allowed_states.map.jinja' import allowed_states %}
{% if sls in allowed_states %}
{% from 'vars/globals.map.jinja' import GLOBALS %}
pki_private_key:
x509.private_key_managed:
- name: /etc/pki/ca.key
- keysize: 4096
- passphrase:
- backup: True
{% if salt['file.file_exists']('/etc/pki/ca.key') -%}
- prereq:
- x509: /etc/pki/ca.crt
{%- endif %}
pki_public_ca_crt:
x509.certificate_managed:
- name: /etc/pki/ca.crt
- signing_private_key: /etc/pki/ca.key
- CN: {{ GLOBALS.manager }}
- C: US
- ST: Utah
- L: Salt Lake City
- basicConstraints: "critical CA:true"
- keyUsage: "critical cRLSign, keyCertSign"
- extendedkeyUsage: "serverAuth, clientAuth"
- subjectKeyIdentifier: hash
- authorityKeyIdentifier: keyid:always, issuer
- days_valid: 3650
- days_remaining: 7
- backup: True
- replace: False
- timeout: 30
- retry:
attempts: 5
interval: 30
pki_public_ca_crt_symlink:
file.symlink:
- name: /opt/so/saltstack/local/salt/ca/files/ca.crt
- target: /etc/pki/ca.crt
- require:
- x509: pki_public_ca_crt
cakeyperms:
file.managed:
- replace: False
- name: /etc/pki/ca.key
- mode: 640
- group: 939
{% else %}
{{sls}}_state_not_allowed:
test.fail_without_changes:
- name: {{sls}}_state_not_allowed
{% endif %}
+12
View File
@@ -0,0 +1,12 @@
{
"registry-mirrors": [
"https://:5000"
],
"bip": "172.17.0.1/24",
"default-address-pools": [
{
"base": "172.17.0.0/24",
"size": 24
}
]
}
-21
View File
@@ -1,21 +0,0 @@
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
{% set nsm_exists = salt['file.directory_exists']('/nsm') %}
{% if nsm_exists %}
{% set nsm_total = salt['cmd.shell']('df -BG /nsm | tail -1 | awk \'{print $2}\'') %}
nsm_total:
grains.present:
- name: nsm_total
- value: {{ nsm_total }}
{% else %}
nsm_missing:
test.succeed_without_changes:
- name: /nsm does not exist, skipping grain assignment
{% endif %}
+7 -18
View File
@@ -4,7 +4,7 @@
{% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'vars/globals.map.jinja' import GLOBALS %}
include: include:
- common.grains - common.soup_scripts
- common.packages - common.packages
{% if GLOBALS.role in GLOBALS.manager_roles %} {% if GLOBALS.role in GLOBALS.manager_roles %}
- manager.elasticsearch # needed for elastic_curl_config state - manager.elasticsearch # needed for elastic_curl_config state
@@ -15,10 +15,10 @@ net.core.wmem_default:
sysctl.present: sysctl.present:
- value: 26214400 - value: 26214400
# Users are not a fan of console messages # Remove variables.txt from /tmp - This is temp
kernel.printk: rmvariablesfile:
sysctl.present: file.absent:
- value: "3 4 1 3" - name: /tmp/variables.txt
# Add socore Group # Add socore Group
socoregroup: socoregroup:
@@ -102,7 +102,7 @@ Etc/UTC:
timezone.system timezone.system
# Sync curl configuration for Elasticsearch authentication # Sync curl configuration for Elasticsearch authentication
{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-searchnode'] %} {% if GLOBALS.role in ['so-eval', 'so-heavynode', 'so-import', 'so-manager', 'so-managersearch', 'so-searchnode', 'so-standalone'] %}
elastic_curl_config: elastic_curl_config:
file.managed: file.managed:
- name: /opt/so/conf/elasticsearch/curl.config - name: /opt/so/conf/elasticsearch/curl.config
@@ -124,11 +124,6 @@ common_sbin:
- user: 939 - user: 939
- group: 939 - group: 939
- file_mode: 755 - file_mode: 755
- show_changes: False
{% if GLOBALS.role == 'so-heavynode' %}
- exclude_pat:
- so-pcap-import
{% endif %}
common_sbin_jinja: common_sbin_jinja:
file.recurse: file.recurse:
@@ -138,11 +133,6 @@ common_sbin_jinja:
- group: 939 - group: 939
- file_mode: 755 - file_mode: 755
- template: jinja - template: jinja
- show_changes: False
{% if GLOBALS.role == 'so-heavynode' %}
- exclude_pat:
- so-import-pcap
{% endif %}
so-status_script: so-status_script:
file.managed: file.managed:
@@ -150,7 +140,7 @@ so-status_script:
- source: salt://common/tools/sbin/so-status - source: salt://common/tools/sbin/so-status
- mode: 755 - mode: 755
{% if GLOBALS.is_sensor %} {% if GLOBALS.role in GLOBALS.sensor_roles %}
# Add sensor cleanup # Add sensor cleanup
so-sensor-clean: so-sensor-clean:
cron.present: cron.present:
@@ -176,7 +166,6 @@ sostatus_log:
file.managed: file.managed:
- name: /opt/so/log/sostatus/status.log - name: /opt/so/log/sostatus/status.log
- mode: 644 - mode: 644
- replace: False
# Install sostatus check cron. This is used to populate Grid. # Install sostatus check cron. This is used to populate Grid.
so-status_check_cron: so-status_check_cron:
+50 -3
View File
@@ -1,5 +1,51 @@
# we cannot import GLOBALS from vars/globals.map.jinja in this state since it is called in setup.virt.init {% from 'vars/globals.map.jinja' import GLOBALS %}
# since it is early in setup of a new VM, the pillars imported in GLOBALS are not yet defined
{% if GLOBALS.os_family == 'Debian' %}
commonpkgs:
pkg.installed:
- skip_suggestions: True
- pkgs:
- apache2-utils
- wget
- ntpdate
- jq
- curl
- ca-certificates
- software-properties-common
- apt-transport-https
- openssl
- netcat-openbsd
- sqlite3
- libssl-dev
- procps
- python3-dateutil
- python3-docker
- python3-packaging
- python3-lxml
- git
- rsync
- vim
- tar
- unzip
{% if grains.oscodename != 'focal' %}
- python3-rich
{% endif %}
{% if grains.oscodename == 'focal' %}
# since Ubuntu requires and internet connection we can use pip to install modules
python3-pip:
pkg.installed
python-rich:
pip.installed:
- name: rich
- target: /usr/local/lib/python3.8/dist-packages/
- require:
- pkg: python3-pip
{% endif %}
{% endif %}
{% if GLOBALS.os_family == 'RedHat' %}
remove_mariadb: remove_mariadb:
pkg.removed: pkg.removed:
@@ -10,7 +56,6 @@ commonpkgs:
- skip_suggestions: True - skip_suggestions: True
- pkgs: - pkgs:
- python3-dnf-plugin-versionlock - python3-dnf-plugin-versionlock
- bc
- curl - curl
- device-mapper-persistent-data - device-mapper-persistent-data
- fuse - fuse
@@ -37,3 +82,5 @@ commonpkgs:
- unzip - unzip
- wget - wget
- yum-utils - yum-utils
{% endif %}
+22 -111
View File
@@ -1,112 +1,23 @@
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # Sync some Utilities
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at soup_scripts:
# https://securityonion.net/license; you may not use this file except in compliance with the file.recurse:
# Elastic License 2.0. - name: /usr/sbin
- user: root
- group: root
- file_mode: 755
- source: salt://common/tools/sbin
- include_pat:
- so-common
- so-image-common
{% import_yaml '/opt/so/saltstack/local/pillar/global/soc_global.sls' as SOC_GLOBAL %} soup_manager_scripts:
{% if SOC_GLOBAL.global.airgap %} file.recurse:
{% set UPDATE_DIR='/tmp/soagupdate/SecurityOnion' %} - name: /usr/sbin
{% else %} - user: root
{% set UPDATE_DIR='/tmp/sogh/securityonion' %} - group: root
{% endif %} - file_mode: 755
{% set SOVERSION = salt['file.read']('/etc/soversion').strip() %} - source: salt://manager/tools/sbin
- include_pat:
# This section is used to put the scripts in place in the Salt file system - so-firewall
# in case a state run tries to overwrite what we do in the next section. - so-repo-sync
copy_so-common_common_tools_sbin: - soup
file.copy:
- name: /opt/so/saltstack/default/salt/common/tools/sbin/so-common
- source: {{UPDATE_DIR}}/salt/common/tools/sbin/so-common
- force: True
- preserve: True
copy_so-image-common_common_tools_sbin:
file.copy:
- name: /opt/so/saltstack/default/salt/common/tools/sbin/so-image-common
- source: {{UPDATE_DIR}}/salt/common/tools/sbin/so-image-common
- force: True
- preserve: True
copy_soup_manager_tools_sbin:
file.copy:
- name: /opt/so/saltstack/default/salt/manager/tools/sbin/soup
- source: {{UPDATE_DIR}}/salt/manager/tools/sbin/soup
- force: True
- preserve: True
copy_so-firewall_manager_tools_sbin:
file.copy:
- name: /opt/so/saltstack/default/salt/manager/tools/sbin/so-firewall
- source: {{UPDATE_DIR}}/salt/manager/tools/sbin/so-firewall
- force: True
- preserve: True
copy_so-yaml_manager_tools_sbin:
file.copy:
- name: /opt/so/saltstack/default/salt/manager/tools/sbin/so-yaml.py
- source: {{UPDATE_DIR}}/salt/manager/tools/sbin/so-yaml.py
- force: True
- preserve: True
copy_so-repo-sync_manager_tools_sbin:
file.copy:
- name: /opt/so/saltstack/default/salt/manager/tools/sbin/so-repo-sync
- source: {{UPDATE_DIR}}/salt/manager/tools/sbin/so-repo-sync
- preserve: True
copy_bootstrap-salt_manager_tools_sbin:
file.copy:
- name: /opt/so/saltstack/default/salt/salt/scripts/bootstrap-salt.sh
- source: {{UPDATE_DIR}}/salt/salt/scripts/bootstrap-salt.sh
- preserve: True
# This section is used to put the new script in place so that it can be called during soup.
# It is faster than calling the states that normally manage them to put them in place.
copy_so-common_sbin:
file.copy:
- name: /usr/sbin/so-common
- source: {{UPDATE_DIR}}/salt/common/tools/sbin/so-common
- force: True
- preserve: True
copy_so-image-common_sbin:
file.copy:
- name: /usr/sbin/so-image-common
- source: {{UPDATE_DIR}}/salt/common/tools/sbin/so-image-common
- force: True
- preserve: True
copy_soup_sbin:
file.copy:
- name: /usr/sbin/soup
- source: {{UPDATE_DIR}}/salt/manager/tools/sbin/soup
- force: True
- preserve: True
copy_so-firewall_sbin:
file.copy:
- name: /usr/sbin/so-firewall
- source: {{UPDATE_DIR}}/salt/manager/tools/sbin/so-firewall
- force: True
- preserve: True
copy_so-yaml_sbin:
file.copy:
- name: /usr/sbin/so-yaml.py
- source: {{UPDATE_DIR}}/salt/manager/tools/sbin/so-yaml.py
- force: True
- preserve: True
copy_so-repo-sync_sbin:
file.copy:
- name: /usr/sbin/so-repo-sync
- source: {{UPDATE_DIR}}/salt/manager/tools/sbin/so-repo-sync
- force: True
- preserve: True
copy_bootstrap-salt_sbin:
file.copy:
- name: /usr/sbin/bootstrap-salt.sh
- source: {{UPDATE_DIR}}/salt/salt/scripts/bootstrap-salt.sh
- force: True
- preserve: True
+4 -21
View File
@@ -16,7 +16,7 @@
if [ "$#" -lt 2 ]; then if [ "$#" -lt 2 ]; then
cat 1>&2 <<EOF cat 1>&2 <<EOF
$0 compiles a BPF expression to be passed to PCAP to apply a socket filter. $0 compiles a BPF expression to be passed to stenotype to apply a socket filter.
Its first argument is the interface (link type is required) and all other arguments Its first argument is the interface (link type is required) and all other arguments
are passed to TCPDump. are passed to TCPDump.
@@ -29,26 +29,9 @@ fi
interface="$1" interface="$1"
shift shift
tcpdump -i $interface -ddd $@ | tail -n+2 |
# Capture tcpdump output and exit code while read line; do
tcpdump_output=$(tcpdump -i "$interface" -ddd "$@" 2>&1)
tcpdump_exit=$?
if [ $tcpdump_exit -ne 0 ]; then
echo "$tcpdump_output" >&2
exit $tcpdump_exit
fi
# Process the output, skipping the first line
echo "$tcpdump_output" | tail -n+2 | while read -r line; do
cols=( $line ) cols=( $line )
printf "%04x%02x%02x%08x" "${cols[0]}" "${cols[1]}" "${cols[2]}" "${cols[3]}" printf "%04x%02x%02x%08x" ${cols[0]} ${cols[1]} ${cols[2]} ${cols[3]}
done done
# Check if the pipeline succeeded
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
exit 1
fi
echo "" echo ""
exit 0
+3 -8
View File
@@ -5,13 +5,8 @@
# https://securityonion.net/license; you may not use this file except in compliance with the # https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0. # Elastic License 2.0.
. /usr/sbin/so-common . /usr/sbin/so-common
cat << EOF salt-call state.highstate -l info
so-checkin will run a full salt highstate to apply all salt states. If a highstate is already running, this request will be queued and so it may pause for a few minutes before you see any more output. For more information about so-checkin and salt, please see:
https://securityonion.net/docs/salt
EOF
salt-call state.highstate -l info queue=True
+83 -198
View File
@@ -8,9 +8,15 @@
# Elastic agent is not managed by salt. Because of this we must store this base information in a # Elastic agent is not managed by salt. Because of this we must store this base information in a
# script that accompanies the soup system. Since so-common is one of those special soup files, # script that accompanies the soup system. Since so-common is one of those special soup files,
# and since this same logic is required during installation, it's included in this file. # and since this same logic is required during installation, it's included in this file.
ELASTIC_AGENT_TARBALL_VERSION="8.10.4"
ELASTIC_AGENT_URL="https://repo.securityonion.net/file/so-repo/prod/2.4/elasticagent/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.tar.gz"
ELASTIC_AGENT_MD5_URL="https://repo.securityonion.net/file/so-repo/prod/2.4/elasticagent/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.md5"
ELASTIC_AGENT_FILE="/nsm/elastic-fleet/artifacts/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.tar.gz"
ELASTIC_AGENT_MD5="/nsm/elastic-fleet/artifacts/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.md5"
ELASTIC_AGENT_EXPANSION_DIR=/nsm/elastic-fleet/artifacts/beats/elastic-agent
DEFAULT_SALT_DIR=/opt/so/saltstack/default DEFAULT_SALT_DIR=/opt/so/saltstack/default
DOC_BASE_URL="https://securityonion.net/docs" DOC_BASE_URL="https://docs.securityonion.net/en/2.4"
if [ -z $NOROOT ]; then if [ -z $NOROOT ]; then
# Check for prerequisites # Check for prerequisites
@@ -25,11 +31,6 @@ if ! echo "$PATH" | grep -q "/usr/sbin"; then
export PATH="$PATH:/usr/sbin" export PATH="$PATH:/usr/sbin"
fi fi
# See if a proxy is set. If so use it.
if [ -f /etc/profile.d/so-proxy.sh ]; then
. /etc/profile.d/so-proxy.sh
fi
# Define a banner to separate sections # Define a banner to separate sections
banner="=========================================================================" banner="========================================================================="
@@ -99,17 +100,6 @@ add_interface_bond0() {
fi fi
} }
airgap_playbooks() {
SRC_DIR=$1
# Copy playbooks if using airgap
mkdir -p /nsm/airgap-resources
# Purge old airgap playbooks to ensure SO only uses the latest released playbooks
rm -fr /nsm/airgap-resources/playbooks
tar xf $SRC_DIR/airgap-resources/playbooks.tgz -C /nsm/airgap-resources/
chown -R socore:socore /nsm/airgap-resources/playbooks
git config --global --add safe.directory /nsm/airgap-resources/playbooks
}
check_container() { check_container() {
docker ps | grep "$1:" > /dev/null 2>&1 docker ps | grep "$1:" > /dev/null 2>&1
return $? return $?
@@ -179,81 +169,16 @@ check_salt_minion_status() {
return $status return $status
} }
# Compare es versions and return the highest version
compare_es_versions() {
# Save the original IFS
local OLD_IFS="$IFS"
IFS=.
local i ver1=($1) ver2=($2)
# Restore the original IFS
IFS="$OLD_IFS"
# Determine the maximum length between the two version arrays
local max_len=${#ver1[@]}
if [[ ${#ver2[@]} -gt $max_len ]]; then
max_len=${#ver2[@]}
fi
# Compare each segment of the versions
for ((i=0; i<max_len; i++)); do
# If a segment in ver1 or ver2 is missing, set it to 0
if [[ -z ${ver1[i]} ]]; then
ver1[i]=0
fi
if [[ -z ${ver2[i]} ]]; then
ver2[i]=0
fi
if ((10#${ver1[i]} > 10#${ver2[i]})); then
echo "$1"
return 0
fi
if ((10#${ver1[i]} < 10#${ver2[i]})); then
echo "$2"
return 0
fi
done
echo "$1" # If versions are equal, return either
return 0
}
copy_new_files() { copy_new_files() {
# Define files to exclude from deletion (relative to their respective base directories)
local EXCLUDE_FILES=(
"salt/hypervisor/soc_hypervisor.yaml"
)
# Build rsync exclude arguments
local EXCLUDE_ARGS=()
for file in "${EXCLUDE_FILES[@]}"; do
EXCLUDE_ARGS+=(--exclude="$file")
done
# Copy new files over to the salt dir # Copy new files over to the salt dir
cd $UPDATE_DIR cd $UPDATE_DIR
rsync -a salt $DEFAULT_SALT_DIR/ --delete "${EXCLUDE_ARGS[@]}" rsync -a salt $DEFAULT_SALT_DIR/ --delete
rsync -a pillar $DEFAULT_SALT_DIR/ --delete "${EXCLUDE_ARGS[@]}" rsync -a pillar $DEFAULT_SALT_DIR/ --delete
chown -R socore:socore $DEFAULT_SALT_DIR/ chown -R socore:socore $DEFAULT_SALT_DIR/
chmod 755 $DEFAULT_SALT_DIR/pillar/firewall/addfirewall.sh
cd /tmp cd /tmp
} }
create_local_directories() {
echo "Creating local pillar and salt directories if needed"
PILLARSALTDIR=$1
local_salt_dir="/opt/so/saltstack/local"
for i in "pillar" "salt"; do
for d in $(find $PILLARSALTDIR/$i -type d); do
suffixdir=${d//$PILLARSALTDIR/}
if [ ! -d "$local_salt_dir/$suffixdir" ]; then
mkdir -p $local_salt_dir$suffixdir
fi
done
chown -R socore:socore $local_salt_dir/$i
done
}
disable_fastestmirror() { disable_fastestmirror() {
sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf
} }
@@ -318,37 +243,13 @@ fail() {
exit 1 exit 1
} }
get_agent_count() {
if [ -f /opt/so/log/agents/agentstatus.log ]; then
AGENTCOUNT=$(cat /opt/so/log/agents/agentstatus.log | grep -wF active | awk '{print $2}' | sed 's/,//')
[[ -z "$AGENTCOUNT" ]] && AGENTCOUNT="0"
else
AGENTCOUNT=0
fi
}
get_elastic_agent_vars() {
local path="${1:-/opt/so/saltstack/default}"
local defaultsfile="${path}/salt/elasticsearch/defaults.yaml"
if [ -f "$defaultsfile" ]; then
ELASTIC_AGENT_TARBALL_VERSION=$(egrep " +version: " $defaultsfile | awk -F: '{print $2}' | tr -d '[:space:]')
ELASTIC_AGENT_URL="https://repo.securityonion.net/file/so-repo/prod/3/elasticagent/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.tar.gz"
ELASTIC_AGENT_MD5_URL="https://repo.securityonion.net/file/so-repo/prod/3/elasticagent/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.md5"
ELASTIC_AGENT_FILE="/nsm/elastic-fleet/artifacts/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.tar.gz"
ELASTIC_AGENT_MD5="/nsm/elastic-fleet/artifacts/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.md5"
ELASTIC_AGENT_EXPANSION_DIR=/nsm/elastic-fleet/artifacts/beats/elastic-agent
else
fail "Could not find salt/elasticsearch/defaults.yaml"
fi
}
get_random_value() { get_random_value() {
length=${1:-20} length=${1:-20}
head -c 5000 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $length | head -n 1 head -c 5000 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $length | head -n 1
} }
gpg_rpm_import() { gpg_rpm_import() {
if [[ $is_oracle ]]; then
if [[ "$WHATWOULDYOUSAYYAHDOHERE" == "setup" ]]; then if [[ "$WHATWOULDYOUSAYYAHDOHERE" == "setup" ]]; then
local RPMKEYSLOC="../salt/repo/client/files/$OS/keys" local RPMKEYSLOC="../salt/repo/client/files/$OS/keys"
else else
@@ -359,6 +260,10 @@ gpg_rpm_import() {
rpm --import $RPMKEYSLOC/$RPMKEY rpm --import $RPMKEYSLOC/$RPMKEY
echo "Imported $RPMKEY" echo "Imported $RPMKEY"
done done
elif [[ $is_rpm ]]; then
echo "Importing the security onion GPG key"
rpm --import ../salt/repo/client/files/oracle/keys/securityonion.pub
fi
} }
header() { header() {
@@ -390,7 +295,7 @@ is_manager_node() {
} }
is_sensor_node() { is_sensor_node() {
# Check to see if this is a sensor node # Check to see if this is a sensor (forward) node
is_single_node_grid && return 0 is_single_node_grid && return 0
grep "role: so-" /etc/salt/grains | grep -E "sensor|heavynode" &> /dev/null grep "role: so-" /etc/salt/grains | grep -E "sensor|heavynode" &> /dev/null
} }
@@ -399,25 +304,6 @@ is_single_node_grid() {
grep "role: so-" /etc/salt/grains | grep -E "eval|standalone|import" &> /dev/null grep "role: so-" /etc/salt/grains | grep -E "eval|standalone|import" &> /dev/null
} }
initialize_elasticsearch_indices() {
local index_names=$1
local default_entry=${2:-'{"@timestamp":"0"}'}
for idx in $index_names; do
if ! so-elasticsearch-query "$idx" --fail --retry 3 --retry-delay 30 >/dev/null 2>&1; then
echo "Index does not already exist. Initializing $idx index."
if retry 3 10 "so-elasticsearch-query "$idx/_doc" -d '$default_entry' -XPOST --fail 2>/dev/null" '"successful":1'; then
echo "Successfully initialized $idx index."
else
echo "Failed to initialize $idx index after 3 attempts."
fi
else
echo "Index $idx already exists. No action needed."
fi
done
}
lookup_bond_interfaces() { lookup_bond_interfaces() {
cat /proc/net/bonding/bond0 | grep "Slave Interface:" | sed -e "s/Slave Interface: //g" cat /proc/net/bonding/bond0 | grep "Slave Interface:" | sed -e "s/Slave Interface: //g"
} }
@@ -443,7 +329,7 @@ lookup_salt_value() {
local="" local=""
fi fi
salt-call -lerror --no-color ${kind}.get ${group}${key} --out=${output} ${local} salt-call --no-color ${kind}.get ${group}${key} --out=${output} ${local}
} }
lookup_pillar() { lookup_pillar() {
@@ -465,7 +351,8 @@ lookup_grain() {
lookup_role() { lookup_role() {
id=$(lookup_grain id) id=$(lookup_grain id)
echo "${id##*_}" pieces=($(echo $id | tr '_' ' '))
echo ${pieces[1]}
} }
is_feature_enabled() { is_feature_enabled() {
@@ -479,13 +366,6 @@ is_feature_enabled() {
return 1 return 1
} }
read_feat() {
if [ -f /opt/so/log/sostatus/lks_enabled ]; then
lic_id=$(cat /opt/so/saltstack/local/pillar/soc/license.sls | grep license_id: | awk '{print $2}')
echo "$lic_id/$(cat /opt/so/log/sostatus/lks_enabled)/$(cat /opt/so/log/sostatus/fps_enabled)"
fi
}
require_manager() { require_manager() {
if is_manager_node; then if is_manager_node; then
echo "This is a manager, so we can proceed." echo "This is a manager, so we can proceed."
@@ -545,22 +425,6 @@ retry() {
return $exitcode return $exitcode
} }
rollover_index() {
idx=$1
exists=$(so-elasticsearch-query $idx -o /dev/null -w "%{http_code}")
if [[ $exists -eq 200 ]]; then
rollover=$(so-elasticsearch-query $idx/_rollover -o /dev/null -w "%{http_code}" -XPOST)
if [[ $rollover -eq 200 ]]; then
echo "Successfully triggered rollover for $idx..."
else
echo "Could not trigger rollover for $idx..."
fi
else
echo "Could not find index $idx..."
fi
}
run_check_net_err() { run_check_net_err() {
local cmd=$1 local cmd=$1
local err_msg=${2:-"Unknown error occured, please check /root/$WHATWOULDYOUSAYYAHDOHERE.log for details."} # Really need to rename that variable local err_msg=${2:-"Unknown error occured, please check /root/$WHATWOULDYOUSAYYAHDOHERE.log for details."} # Really need to rename that variable
@@ -585,38 +449,20 @@ run_check_net_err() {
wait_for_salt_minion() { wait_for_salt_minion() {
local minion="$1" local minion="$1"
local max_wait="${2:-30}" local timeout="${2:-5}"
local interval="${3:-2}" local logfile="${3:-'/dev/stdout'}"
local logfile="${4:-'/dev/stdout'}" retry 60 5 "journalctl -u salt-minion.service | grep 'Minion is ready to receive requests'" >> "$logfile" 2>&1 || fail
local elapsed=0 local attempt=0
# each attempts would take about 15 seconds
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - Waiting for salt-minion '$minion' to be ready..." local maxAttempts=20
until check_salt_minion_status "$minion" "$timeout" "$logfile"; do
while [ $elapsed -lt $max_wait ]; do attempt=$((attempt+1))
# Check if service is running if [[ $attempt -eq $maxAttempts ]]; then
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - Check if salt-minion service is running"
if ! systemctl is-active --quiet salt-minion; then
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - salt-minion service not running (elapsed: ${elapsed}s)"
sleep $interval
elapsed=$((elapsed + interval))
continue
fi
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - salt-minion service is running"
# Check if minion responds to ping
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - Check if $minion responds to ping"
if salt "$minion" test.ping --timeout=3 --out=json 2>> "$logfile" | grep -q "true"; then
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - salt-minion '$minion' is connected and ready!"
return 0
fi
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - Waiting... (${elapsed}s / ${max_wait}s)"
sleep $interval
elapsed=$((elapsed + interval))
done
echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - ERROR: salt-minion '$minion' not ready after $max_wait seconds"
return 1 return 1
fi
sleep 10
done
return 0
} }
salt_minion_count() { salt_minion_count() {
@@ -626,19 +472,69 @@ salt_minion_count() {
} }
set_os() { set_os() {
if [ -f /etc/redhat-release ] && grep -q "Red Hat Enterprise Linux release 9" /etc/redhat-release && [ -f /etc/oracle-release ]; then if [ -f /etc/redhat-release ]; then
if grep -q "Rocky Linux release 9" /etc/redhat-release; then
OS=rocky
OSVER=9
is_rocky=true
is_rpm=true
elif grep -q "CentOS Stream release 9" /etc/redhat-release; then
OS=centos
OSVER=9
is_centos=true
is_rpm=true
elif grep -q "AlmaLinux release 9" /etc/redhat-release; then
OS=alma
OSVER=9
is_alma=true
is_rpm=true
elif grep -q "Red Hat Enterprise Linux release 9" /etc/redhat-release; then
if [ -f /etc/oracle-release ]; then
OS=oracle OS=oracle
OSVER=9 OSVER=9
is_oracle=true is_oracle=true
is_rpm=true is_rpm=true
else
OS=rhel
OSVER=9
is_rhel=true
is_rpm=true
fi
fi fi
cron_service_name="crond" cron_service_name="crond"
elif [ -f /etc/os-release ]; then
if grep -q "UBUNTU_CODENAME=focal" /etc/os-release; then
OSVER=focal
UBVER=20.04
OS=ubuntu
is_ubuntu=true
is_deb=true
elif grep -q "UBUNTU_CODENAME=jammy" /etc/os-release; then
OSVER=jammy
UBVER=22.04
OS=ubuntu
is_ubuntu=true
is_deb=true
elif grep -q "VERSION_CODENAME=bookworm" /etc/os-release; then
OSVER=bookworm
DEBVER=12
is_debian=true
OS=debian
is_deb=true
fi
cron_service_name="cron"
fi
} }
set_minionid() { set_minionid() {
MINIONID=$(lookup_grain id) MINIONID=$(lookup_grain id)
} }
set_palette() {
if [[ $is_deb ]]; then
update-alternatives --set newt-palette /etc/newt/palette.original
fi
}
set_version() { set_version() {
CURRENTVERSION=0.0.0 CURRENTVERSION=0.0.0
@@ -663,15 +559,6 @@ status () {
printf "\n=========================================================================\n$(date) | $1\n=========================================================================\n" printf "\n=========================================================================\n$(date) | $1\n=========================================================================\n"
} }
sync_options() {
set_version
set_os
salt_minion_count
get_agent_count
echo "$VERSION/$OS/$(uname -r)/$MINIONCOUNT:$AGENTCOUNT/$(read_feat)"
}
systemctl_func() { systemctl_func() {
local action=$1 local action=$1
local echo_action=$1 local echo_action=$1
@@ -696,8 +583,6 @@ has_uppercase() {
} }
update_elastic_agent() { update_elastic_agent() {
local path="${1:-/opt/so/saltstack/default}"
get_elastic_agent_vars "$path"
echo "Checking if Elastic Agent update is necessary..." echo "Checking if Elastic Agent update is necessary..."
download_and_verify "$ELASTIC_AGENT_URL" "$ELASTIC_AGENT_MD5_URL" "$ELASTIC_AGENT_FILE" "$ELASTIC_AGENT_MD5" "$ELASTIC_AGENT_EXPANSION_DIR" download_and_verify "$ELASTIC_AGENT_URL" "$ELASTIC_AGENT_MD5_URL" "$ELASTIC_AGENT_FILE" "$ELASTIC_AGENT_MD5" "$ELASTIC_AGENT_EXPANSION_DIR"
} }
+2 -53
View File
@@ -8,7 +8,6 @@
import sys import sys
import subprocess import subprocess
import os import os
import json
sys.path.append('/opt/saltstack/salt/lib/python3.10/site-packages/') sys.path.append('/opt/saltstack/salt/lib/python3.10/site-packages/')
import salt.config import salt.config
@@ -37,67 +36,17 @@ def check_needs_restarted():
with open(outfile, 'w') as f: with open(outfile, 'w') as f:
f.write(val) f.write(val)
def check_for_fps():
feat = 'fps'
feat_full = feat.replace('ps', 'ips')
fps = 0
try:
result = subprocess.run([feat_full + '-mode-setup', '--is-enabled'], stdout=subprocess.PIPE)
if result.returncode == 0:
fps = 1
except:
fn = '/proc/sys/crypto/' + feat_full + '_enabled'
try:
with open(fn, 'r') as f:
contents = f.read()
if '1' in contents:
fps = 1
except:
# Unknown, so assume 0
fps = 0
with open('/opt/so/log/sostatus/fps_enabled', 'w') as f:
f.write(str(fps))
def check_for_lks():
feat = 'Lks'
feat_full = feat.replace('ks', 'uks')
lks = 0
result = subprocess.run(['lsblk', '-p', '-J'], check=True, stdout=subprocess.PIPE)
data = json.loads(result.stdout)
for device in data['blockdevices']:
if 'children' in device:
for gc in device['children']:
if 'children' in gc:
try:
arg = 'is' + feat_full
result = subprocess.run(['cryptsetup', arg, gc['name']], stdout=subprocess.PIPE)
if result.returncode == 0:
lks = 1
except FileNotFoundError:
for ggc in gc['children']:
if 'crypt' in ggc['type']:
lks = 1
if lks:
break
with open('/opt/so/log/sostatus/lks_enabled', 'w') as f:
f.write(str(lks))
def fail(msg): def fail(msg):
print(msg, file=sys.stderr) print(msg, file=sys.stderr)
sys.exit(1) sys.exit(1)
def main(): def main():
proc = subprocess.run(['id', '-u'], stdout=subprocess.PIPE, encoding="utf-8") proc = subprocess.run(['id', '-u'], stdout=subprocess.PIPE, encoding="utf-8")
if proc.stdout.strip() != "0": if proc.stdout.strip() != "0":
fail("This program must be run as root") fail("This program must be run as root")
# Ensure that umask is 0022 so that files created by this script have rw-r-r permissions
org_umask = os.umask(0o022)
check_needs_restarted() check_needs_restarted()
check_for_fps()
check_for_lks()
# Restore umask to whatever value was set before this script was run. SXIG sets to 0077 rw---
os.umask(org_umask)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
+21 -34
View File
@@ -4,16 +4,22 @@
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the # https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0. # Elastic License 2.0.
import sys, argparse, re, subprocess, json
import sys, argparse, re, docker
from packaging.version import Version, InvalidVersion from packaging.version import Version, InvalidVersion
from itertools import groupby, chain from itertools import groupby, chain
def get_image_name(string) -> str: def get_image_name(string) -> str:
return ':'.join(string.split(':')[:-1]) return ':'.join(string.split(':')[:-1])
def get_so_image_basename(string) -> str: def get_so_image_basename(string) -> str:
return get_image_name(string).split('/so-')[-1] return get_image_name(string).split('/so-')[-1]
def get_image_version(string) -> str: def get_image_version(string) -> str:
ver = string.split(':')[-1] ver = string.split(':')[-1]
if ver == 'latest': if ver == 'latest':
@@ -29,49 +35,33 @@ def get_image_version(string) -> str:
return '999999.9.9' return '999999.9.9'
return ver return ver
def run_command(command):
process = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if process.returncode != 0:
print(f"Error executing command: {command}", file=sys.stderr)
print(f"Error message: {process.stderr}", file=sys.stderr)
exit(1)
return process.stdout
def main(quiet): def main(quiet):
try: client = docker.from_env()
# Prune old/stopped containers using docker CLI
# Prune old/stopped containers
if not quiet: print('Pruning old containers') if not quiet: print('Pruning old containers')
run_command('docker container prune -f') client.containers.prune()
# Get list of images using docker CLI image_list = client.images.list(filters={ 'dangling': False })
images_json = run_command('docker images --format "{{json .}}"')
# Parse the JSON output # Map list of image objects to flattened list of tags (format: "name:version")
image_list = [] tag_list = list(chain.from_iterable(list(map(lambda x: x.attrs.get('RepoTags'), image_list))))
for line in images_json.strip().split('\n'):
if line: # Skip empty lines
image_list.append(json.loads(line))
# Extract tags in the format "name:version"
tag_list = []
for img in image_list:
# Skip dangling images
if img.get('Repository') != "<none>" and img.get('Tag') != "<none>":
tag = f"{img.get('Repository')}:{img.get('Tag')}"
# Filter to only SO images (base name begins with "so-") # Filter to only SO images (base name begins with "so-")
if re.match(r'^.*\/so-[^\/]*$', get_image_name(tag)): tag_list = list(filter(lambda x: re.match(r'^.*\/so-[^\/]*$', get_image_name(x)), tag_list))
tag_list.append(tag)
# Group tags into lists by base name (sort by same projection first) # Group tags into lists by base name (sort by same projection first)
tag_list.sort(key=lambda x: get_so_image_basename(x)) tag_list.sort(key=lambda x: get_so_image_basename(x))
grouped_tag_lists = [list(it) for k, it in groupby(tag_list, lambda x: get_so_image_basename(x))] grouped_tag_lists = [ list(it) for _, it in groupby(tag_list, lambda x: get_so_image_basename(x)) ]
no_prunable = True no_prunable = True
for t_list in grouped_tag_lists: for t_list in grouped_tag_lists:
try: try:
# Group tags by version, in case multiple images exist with the same version string # Group tags by version, in case multiple images exist with the same version string
t_list.sort(key=lambda x: Version(get_image_version(x)), reverse=True) t_list.sort(key=lambda x: Version(get_image_version(x)), reverse=True)
grouped_t_list = [list(it) for k, it in groupby(t_list, lambda x: get_image_version(x))] grouped_t_list = [ list(it) for _,it in groupby(t_list, lambda x: get_image_version(x)) ]
# Keep the 2 most current version groups # Keep the 2 most current version groups
if len(grouped_t_list) <= 2: if len(grouped_t_list) <= 2:
continue continue
@@ -81,10 +71,10 @@ def main(quiet):
for tag in group: for tag in group:
if not quiet: print(f'Removing image {tag}') if not quiet: print(f'Removing image {tag}')
try: try:
run_command(f'docker rmi -f {tag}') client.images.remove(tag, force=True)
except Exception as e: except docker.errors.ClientError as e:
print(f'Could not remove image {tag}, continuing...') print(f'Could not remove image {tag}, continuing...')
except (InvalidVersion) as e: except (docker.errors.APIError, InvalidVersion) as e:
print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr) print(f'so-{get_so_image_basename(t_list[0])}: {e}', file=sys.stderr)
exit(1) exit(1)
except Exception as e: except Exception as e:
@@ -95,9 +85,6 @@ def main(quiet):
if no_prunable and not quiet: if no_prunable and not quiet:
print('No Security Onion images to prune') print('No Security Onion images to prune')
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
exit(1)
if __name__ == "__main__": if __name__ == "__main__":
main_parser = argparse.ArgumentParser(add_help=False) main_parser = argparse.ArgumentParser(add_help=False)
+13 -30
View File
@@ -25,13 +25,14 @@ container_list() {
if [ $MANAGERCHECK == 'so-import' ]; then if [ $MANAGERCHECK == 'so-import' ]; then
TRUSTED_CONTAINERS=( TRUSTED_CONTAINERS=(
"so-elasticsearch" "so-elasticsearch"
"so-idstools"
"so-influxdb" "so-influxdb"
"so-kibana" "so-kibana"
"so-kratos" "so-kratos"
"so-hydra"
"so-nginx" "so-nginx"
"so-pcaptools" "so-pcaptools"
"so-soc" "so-soc"
"so-steno"
"so-suricata" "so-suricata"
"so-telegraf" "so-telegraf"
"so-zeek" "so-zeek"
@@ -47,17 +48,22 @@ container_list() {
"so-elastic-fleet-package-registry" "so-elastic-fleet-package-registry"
"so-elasticsearch" "so-elasticsearch"
"so-idh" "so-idh"
"so-idstools"
"so-influxdb" "so-influxdb"
"so-kafka"
"so-kibana" "so-kibana"
"so-kratos" "so-kratos"
"so-hydra"
"so-logstash" "so-logstash"
"so-mysql"
"so-nginx" "so-nginx"
"so-pcaptools" "so-pcaptools"
"so-playbook"
"so-redis" "so-redis"
"so-soc" "so-soc"
"so-soctopus"
"so-steno"
"so-strelka-backend" "so-strelka-backend"
"so-strelka-filestream"
"so-strelka-frontend"
"so-strelka-manager" "so-strelka-manager"
"so-suricata" "so-suricata"
"so-telegraf" "so-telegraf"
@@ -65,10 +71,12 @@ container_list() {
) )
else else
TRUSTED_CONTAINERS=( TRUSTED_CONTAINERS=(
"so-idstools"
"so-elasticsearch" "so-elasticsearch"
"so-logstash" "so-logstash"
"so-nginx" "so-nginx"
"so-redis" "so-redis"
"so-steno"
"so-suricata" "so-suricata"
"so-soc" "so-soc"
"so-telegraf" "so-telegraf"
@@ -106,10 +114,6 @@ update_docker_containers() {
container_list container_list
fi fi
# all the images using ELASTICSEARCHDEFAULTS.elasticsearch.version
# does not include so-elastic-fleet since that container uses so-elastic-agent image
local IMAGES_USING_ES_VERSION=("so-elasticsearch")
rm -rf $SIGNPATH >> "$LOG_FILE" 2>&1 rm -rf $SIGNPATH >> "$LOG_FILE" 2>&1
mkdir -p $SIGNPATH >> "$LOG_FILE" 2>&1 mkdir -p $SIGNPATH >> "$LOG_FILE" 2>&1
@@ -137,36 +141,15 @@ update_docker_containers() {
$PROGRESS_CALLBACK $i $PROGRESS_CALLBACK $i
fi fi
if [[ " ${IMAGES_USING_ES_VERSION[*]} " =~ [[:space:]]${i}[[:space:]] ]]; then
# this is an es container so use version defined in elasticsearch defaults.yaml
local UPDATE_DIR='/tmp/sogh/securityonion'
if [ ! -d "$UPDATE_DIR" ]; then
UPDATE_DIR=/securityonion
fi
local v1=0
local v2=0
if [[ -f "$UPDATE_DIR/salt/elasticsearch/defaults.yaml" ]]; then
v1=$(egrep " +version: " "$UPDATE_DIR/salt/elasticsearch/defaults.yaml" | awk -F: '{print $2}' | tr -d '[:space:]')
fi
if [[ -f "$DEFAULT_SALT_DIR/salt/elasticsearch/defaults.yaml" ]]; then
v2=$(egrep " +version: " "$DEFAULT_SALT_DIR/salt/elasticsearch/defaults.yaml" | awk -F: '{print $2}' | tr -d '[:space:]')
fi
local highest_es_version=$(compare_es_versions "$v1" "$v2")
local image=$i:$highest_es_version$IMAGE_TAG_SUFFIX
local sig_url=https://sigs.securityonion.net/es-$highest_es_version/$image.sig
else
# this is not an es container so use the so version for the version
local image=$i:$VERSION$IMAGE_TAG_SUFFIX
local sig_url=https://sigs.securityonion.net/$VERSION/$image.sig
fi
# Pull down the trusted docker image # Pull down the trusted docker image
local image=$i:$VERSION$IMAGE_TAG_SUFFIX
run_check_net_err \ run_check_net_err \
"docker pull $CONTAINER_REGISTRY/$IMAGEREPO/$image" \ "docker pull $CONTAINER_REGISTRY/$IMAGEREPO/$image" \
"Could not pull $image, please ensure connectivity to $CONTAINER_REGISTRY" >> "$LOG_FILE" 2>&1 "Could not pull $image, please ensure connectivity to $CONTAINER_REGISTRY" >> "$LOG_FILE" 2>&1
# Get signature # Get signature
run_check_net_err \ run_check_net_err \
"curl --retry 5 --retry-delay 60 -A '$CURLTYPE/$CURRENTVERSION/$OS/$(uname -r)' $sig_url --output $SIGNPATH/$image.sig" \ "curl --retry 5 --retry-delay 60 -A '$CURLTYPE/$CURRENTVERSION/$OS/$(uname -r)' https://sigs.securityonion.net/$VERSION/$i:$VERSION$IMAGE_TAG_SUFFIX.sig --output $SIGNPATH/$image.sig" \
"Could not pull signature file for $image, please ensure connectivity to https://sigs.securityonion.net " \ "Could not pull signature file for $image, please ensure connectivity to https://sigs.securityonion.net " \
noretry >> "$LOG_FILE" 2>&1 noretry >> "$LOG_FILE" 2>&1
# Dump our hash values # Dump our hash values
+4
View File
@@ -49,6 +49,10 @@ if [ "$CONTINUE" == "y" ]; then
sed -i "s|$OLD_IP|$NEW_IP|g" $file sed -i "s|$OLD_IP|$NEW_IP|g" $file
done done
echo "Granting MySQL root user permissions on $NEW_IP"
docker exec -i so-mysql mysql --user=root --password=$(lookup_pillar_secret 'mysql') -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'$NEW_IP' IDENTIFIED BY '$(lookup_pillar_secret 'mysql')' WITH GRANT OPTION;" &> /dev/null
echo "Removing MySQL root user from $OLD_IP"
docker exec -i so-mysql mysql --user=root --password=$(lookup_pillar_secret 'mysql') -e "DROP USER 'root'@'$OLD_IP';" &> /dev/null
echo "Updating Kibana dashboards" echo "Updating Kibana dashboards"
salt-call state.apply kibana.so_savedobjects_defaults -l info queue=True salt-call state.apply kibana.so_savedobjects_defaults -l info queue=True
+7 -51
View File
@@ -95,8 +95,6 @@ if [[ $EXCLUDE_STARTUP_ERRORS == 'Y' ]]; then
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|shutdown process" # server not yet ready (logstash waiting on elastic) EXCLUDED_ERRORS="$EXCLUDED_ERRORS|shutdown process" # server not yet ready (logstash waiting on elastic)
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|contain valid certificates" # server not yet ready (logstash waiting on elastic) EXCLUDED_ERRORS="$EXCLUDED_ERRORS|contain valid certificates" # server not yet ready (logstash waiting on elastic)
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|failedaction" # server not yet ready (logstash waiting on elastic) EXCLUDED_ERRORS="$EXCLUDED_ERRORS|failedaction" # server not yet ready (logstash waiting on elastic)
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|block in start_workers" # server not yet ready (logstash waiting on elastic)
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|block in buffer_initialize" # server not yet ready (logstash waiting on elastic)
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|no route to host" # server not yet ready EXCLUDED_ERRORS="$EXCLUDED_ERRORS|no route to host" # server not yet ready
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|not running" # server not yet ready EXCLUDED_ERRORS="$EXCLUDED_ERRORS|not running" # server not yet ready
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|unavailable" # server not yet ready EXCLUDED_ERRORS="$EXCLUDED_ERRORS|unavailable" # server not yet ready
@@ -124,14 +122,6 @@ if [[ $EXCLUDE_STARTUP_ERRORS == 'Y' ]]; then
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|error while communicating" # Elasticsearch MS -> HN "sensor" temporarily unavailable EXCLUDED_ERRORS="$EXCLUDED_ERRORS|error while communicating" # Elasticsearch MS -> HN "sensor" temporarily unavailable
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|tls handshake error" # Docker registry container when new node comes onlines EXCLUDED_ERRORS="$EXCLUDED_ERRORS|tls handshake error" # Docker registry container when new node comes onlines
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Unable to get license information" # Logstash trying to contact ES before it's ready EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Unable to get license information" # Logstash trying to contact ES before it's ready
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|process already finished" # Telegraf script finished just as the auto kill timeout kicked in
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|No shard available" # Typical error when making a query before ES has finished loading all indices
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|responded with status-code 503" # telegraf getting 503 from ES during startup
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|process_cluster_event_timeout_exception" # logstash waiting for elasticsearch to start
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|not configured for GeoIP" # SO does not bundle the maxminddb with Zeek
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|HTTP 404: Not Found" # Salt loops until Kratos returns 200, during startup Kratos may not be ready
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Cancelling deferred write event maybeFenceReplicas because the event queue is now closed" # Kafka controller log during shutdown/restart
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Redis may have been restarted" # Redis likely restarted by salt
fi fi
if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then
@@ -156,15 +146,6 @@ if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|status 200" # false positive (request successful, contained error string in content) EXCLUDED_ERRORS="$EXCLUDED_ERRORS|status 200" # false positive (request successful, contained error string in content)
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|app_layer.error" # false positive (suricata 7) in stats.log e.g. app_layer.error.imap.parser | Total | 0 EXCLUDED_ERRORS="$EXCLUDED_ERRORS|app_layer.error" # false positive (suricata 7) in stats.log e.g. app_layer.error.imap.parser | Total | 0
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|is not an ip string literal" # false positive (Open Canary logging out blank IP addresses) EXCLUDED_ERRORS="$EXCLUDED_ERRORS|is not an ip string literal" # false positive (Open Canary logging out blank IP addresses)
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|syncing rule" # false positive (rule sync log line includes rule name which can contain 'error')
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|request_unauthorized" # false positive (login failures to Hydra result in an 'error' log)
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|adding index lifecycle policy" # false positive (elasticsearch policy names contain 'error')
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|adding ingest pipeline" # false positive (elasticsearch ingest pipeline names contain 'error')
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|updating index template" # false positive (elasticsearch index or template names contain 'error')
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|updating component template" # false positive (elasticsearch index or template names contain 'error')
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|upgrading component template" # false positive (elasticsearch index or template names contain 'error')
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|upgrading composable template" # false positive (elasticsearch composable template names contain 'error')
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Error while parsing document for index \[.ds-logs-kratos-so-.*object mapping for \[file\]" # false positive (mapping error occuring BEFORE kratos index has rolled over in 2.4.210)
fi fi
if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then
@@ -173,13 +154,18 @@ if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|fail\\(error\\)" # redis/python generic stack line, rely on other lines for actual error EXCLUDED_ERRORS="$EXCLUDED_ERRORS|fail\\(error\\)" # redis/python generic stack line, rely on other lines for actual error
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|urlerror" # idstools connection timeout EXCLUDED_ERRORS="$EXCLUDED_ERRORS|urlerror" # idstools connection timeout
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|timeouterror" # idstools connection timeout EXCLUDED_ERRORS="$EXCLUDED_ERRORS|timeouterror" # idstools connection timeout
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|forbidden" # playbook
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|_ml" # Elastic ML errors EXCLUDED_ERRORS="$EXCLUDED_ERRORS|_ml" # Elastic ML errors
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|context canceled" # elastic agent during shutdown EXCLUDED_ERRORS="$EXCLUDED_ERRORS|context canceled" # elastic agent during shutdown
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|exited with code 128" # soctopus errors during forced restart by highstate
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|geoip databases update" # airgap can't update GeoIP DB EXCLUDED_ERRORS="$EXCLUDED_ERRORS|geoip databases update" # airgap can't update GeoIP DB
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|filenotfounderror" # bug in 2.4.10 filecheck salt state caused duplicate cronjobs EXCLUDED_ERRORS="$EXCLUDED_ERRORS|filenotfounderror" # bug in 2.4.10 filecheck salt state caused duplicate cronjobs
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|salt-minion-check" # bug in early 2.4 place Jinja script in non-jinja salt dir causing cron output errors EXCLUDED_ERRORS="$EXCLUDED_ERRORS|salt-minion-check" # bug in early 2.4 place Jinja script in non-jinja salt dir causing cron output errors
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|generating elastalert config" # playbook expected error
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|activerecord" # playbook expected error
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|monitoring.metrics" # known issue with elastic agent casting the field incorrectly if an integer value shows up before a float EXCLUDED_ERRORS="$EXCLUDED_ERRORS|monitoring.metrics" # known issue with elastic agent casting the field incorrectly if an integer value shows up before a float
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|repodownload.conf" # known issue with reposync on pre-2.4.20 EXCLUDED_ERRORS="$EXCLUDED_ERRORS|repodownload.conf" # known issue with reposync on pre-2.4.20
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|missing versions record" # stenographer corrupt index
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|soc.field." # known ingest type collisions issue with earlier versions of SO EXCLUDED_ERRORS="$EXCLUDED_ERRORS|soc.field." # known ingest type collisions issue with earlier versions of SO
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|error parsing signature" # Malformed Suricata rule, from upstream provider EXCLUDED_ERRORS="$EXCLUDED_ERRORS|error parsing signature" # Malformed Suricata rule, from upstream provider
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|sticky buffer has no matches" # Non-critical Suricata error EXCLUDED_ERRORS="$EXCLUDED_ERRORS|sticky buffer has no matches" # Non-critical Suricata error
@@ -187,7 +173,6 @@ if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|cannot join on an empty table" # InfluxDB flux query, import nodes EXCLUDED_ERRORS="$EXCLUDED_ERRORS|cannot join on an empty table" # InfluxDB flux query, import nodes
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|exhausting result iterator" # InfluxDB flux query mismatched table results (temporary data issue) EXCLUDED_ERRORS="$EXCLUDED_ERRORS|exhausting result iterator" # InfluxDB flux query mismatched table results (temporary data issue)
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|failed to finish run" # InfluxDB rare error, self-recoverable EXCLUDED_ERRORS="$EXCLUDED_ERRORS|failed to finish run" # InfluxDB rare error, self-recoverable
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Unable to gather disk name" # InfluxDB known error, can't read disks because the container doesn't have them mounted
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|iteration" EXCLUDED_ERRORS="$EXCLUDED_ERRORS|iteration"
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|communication packets" EXCLUDED_ERRORS="$EXCLUDED_ERRORS|communication packets"
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|use of closed" EXCLUDED_ERRORS="$EXCLUDED_ERRORS|use of closed"
@@ -216,19 +201,7 @@ if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|req.LocalMeta.host.ip" # known issue in GH EXCLUDED_ERRORS="$EXCLUDED_ERRORS|req.LocalMeta.host.ip" # known issue in GH
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|sendmail" # zeek EXCLUDED_ERRORS="$EXCLUDED_ERRORS|sendmail" # zeek
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|stats.log" EXCLUDED_ERRORS="$EXCLUDED_ERRORS|stats.log"
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Unknown column" # Elastalert errors from running EQL queries
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|parsing_exception" # Elastalert EQL parsing issue. Temp.
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|context deadline exceeded" EXCLUDED_ERRORS="$EXCLUDED_ERRORS|context deadline exceeded"
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Error running query:" # Specific issues with detection rules
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|detect-parse" # Suricata encountering a malformed rule
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|integrity check failed" # Detections: Exclude false positive due to automated testing
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|syncErrors" # Detections: Not an actual error
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|Initialized license manager" # SOC log: before fields.status was changed to fields.licenseStatus
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|from NIC checksum offloading" # zeek reporter.log
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|marked for removal" # docker container getting recycled
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|tcp 127.0.0.1:6791: bind: address already in use" # so-elastic-fleet agent restarting. Seen starting w/ 8.18.8 https://github.com/elastic/kibana/issues/201459
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|TransformTask\] \[logs-(tychon|aws_billing|microsoft_defender_endpoint).*user so_kibana lacks the required permissions \[logs-\1" # Known issue with 3 integrations using kibana_system role vs creating unique api creds with proper permissions.
EXCLUDED_ERRORS="$EXCLUDED_ERRORS|manifest unknown" # appears in so-dockerregistry log for so-tcpreplay following docker upgrade to 29.2.1-1
fi fi
RESULT=0 RESULT=0
@@ -237,9 +210,7 @@ RESULT=0
CONTAINER_IDS=$(docker ps -q) CONTAINER_IDS=$(docker ps -q)
exclude_container so-kibana # kibana error logs are too verbose with large varieties of errors most of which are temporary exclude_container so-kibana # kibana error logs are too verbose with large varieties of errors most of which are temporary
exclude_container so-idstools # ignore due to known issues and noisy logging exclude_container so-idstools # ignore due to known issues and noisy logging
exclude_container so-playbook # Playbook is removed as of 2.4.70, disregard output in stopped containers exclude_container so-playbook # ignore due to several playbook known issues
exclude_container so-mysql # MySQL is removed as of 2.4.70, disregard output in stopped containers
exclude_container so-soctopus # Soctopus is removed as of 2.4.70, disregard output in stopped containers
for container_id in $CONTAINER_IDS; do for container_id in $CONTAINER_IDS; do
container_name=$(docker ps --format json | jq ". | select(.ID==\"$container_id\")|.Names") container_name=$(docker ps --format json | jq ". | select(.ID==\"$container_id\")|.Names")
@@ -257,31 +228,16 @@ exclude_log "kibana.log" # kibana error logs are too verbose with large variet
exclude_log "spool" # disregard zeek analyze logs as this is data specific exclude_log "spool" # disregard zeek analyze logs as this is data specific
exclude_log "import" # disregard imported test data the contains error strings exclude_log "import" # disregard imported test data the contains error strings
exclude_log "update.log" # ignore playbook updates due to several known issues exclude_log "update.log" # ignore playbook updates due to several known issues
exclude_log "playbook.log" # ignore due to several playbook known issues
exclude_log "cron-cluster-delete.log" # ignore since Curator has been removed exclude_log "cron-cluster-delete.log" # ignore since Curator has been removed
exclude_log "cron-close.log" # ignore since Curator has been removed exclude_log "cron-close.log" # ignore since Curator has been removed
exclude_log "curator.log" # ignore since Curator has been removed exclude_log "curator.log" # ignore since Curator has been removed
exclude_log "playbook.log" # Playbook is removed as of 2.4.70, logs may still be on disk
exclude_log "mysqld.log" # MySQL is removed as of 2.4.70, logs may still be on disk
exclude_log "soctopus.log" # Soctopus is removed as of 2.4.70, logs may still be on disk
exclude_log "agentstatus.log" # ignore this log since it tracks agents in error state
exclude_log "detections_runtime-status_yara.log" # temporarily ignore this log until Detections is more stable
exclude_log "/nsm/kafka/data/" # ignore Kafka data directory from log check.
# Include Zeek reporter.log to detect errors after running known good pcap(s) through sensor
echo "/nsm/zeek/spool/logger/reporter.log" >> /tmp/log_check_files
for log_file in $(cat /tmp/log_check_files); do for log_file in $(cat /tmp/log_check_files); do
status "Checking log file $log_file" status "Checking log file $log_file"
tail -n $RECENT_LOG_LINES $log_file > /tmp/log_check tail -n $RECENT_LOG_LINES $log_file > /tmp/log_check
check_for_errors check_for_errors
done done
# Look for OOM specific errors in /var/log/messages which can lead to odd behavior / test failures
if [[ -f /var/log/messages ]]; then
status "Checking log file /var/log/messages"
if journalctl --since "24 hours ago" | grep -iE 'out of memory|oom-kill'; then
RESULT=1
fi
fi
# Cleanup temp files # Cleanup temp files
rm -f /tmp/log_check_files rm -f /tmp/log_check_files
-98
View File
@@ -1,98 +0,0 @@
#!/bin/bash
#
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0."
set -e
# This script is intended to be used in the case the ISO install did not properly setup TPM decrypt for LUKS partitions at boot.
if [ -z $NOROOT ]; then
# Check for prerequisites
if [ "$(id -u)" -ne 0 ]; then
echo "This script must be run using sudo!"
exit 1
fi
fi
ENROLL_TPM=N
while [[ $# -gt 0 ]]; do
case $1 in
--enroll-tpm)
ENROLL_TPM=Y
;;
*)
echo "Usage: $0 [options]"
echo ""
echo "where options are:"
echo " --enroll-tpm for when TPM enrollment was not selected during ISO install."
echo ""
exit 1
;;
esac
shift
done
check_for_tpm() {
echo -n "Checking for TPM: "
if [ -d /sys/class/tpm/tpm0 ]; then
echo -e "tpm0 found."
TPM="yes"
# Check if TPM is using sha1 or sha256
if [ -d /sys/class/tpm/tpm0/pcr-sha1 ]; then
echo -e "TPM is using sha1.\n"
TPM_PCR="sha1"
elif [ -d /sys/class/tpm/tpm0/pcr-sha256 ]; then
echo -e "TPM is using sha256.\n"
TPM_PCR="sha256"
fi
else
echo -e "No TPM found.\n"
exit 1
fi
}
check_for_luks_partitions() {
echo "Checking for LUKS partitions"
for part in $(lsblk -o NAME,FSTYPE -ln | grep crypto_LUKS | awk '{print $1}'); do
echo "Found LUKS partition: $part"
LUKS_PARTITIONS+=("$part")
done
if [ ${#LUKS_PARTITIONS[@]} -eq 0 ]; then
echo -e "No LUKS partitions found.\n"
exit 1
fi
echo ""
}
enroll_tpm_in_luks() {
read -s -p "Enter the LUKS passphrase used during ISO install: " LUKS_PASSPHRASE
echo ""
for part in "${LUKS_PARTITIONS[@]}"; do
echo "Enrolling TPM for LUKS device: /dev/$part"
if [ "$TPM_PCR" == "sha1" ]; then
clevis luks bind -d /dev/$part tpm2 '{"pcr_bank":"sha1","pcr_ids":"7"}' <<< $LUKS_PASSPHRASE
elif [ "$TPM_PCR" == "sha256" ]; then
clevis luks bind -d /dev/$part tpm2 '{"pcr_bank":"sha256","pcr_ids":"7"}' <<< $LUKS_PASSPHRASE
fi
done
}
regenerate_tpm_enrollment_token() {
for part in "${LUKS_PARTITIONS[@]}"; do
clevis luks regen -d /dev/$part -s 1 -q
done
}
check_for_tpm
check_for_luks_partitions
if [[ $ENROLL_TPM == "Y" ]]; then
enroll_tpm_in_luks
else
regenerate_tpm_enrollment_token
fi
echo "Running dracut"
dracut -fv
echo -e "\nTPM configuration complete. Reboot the system to verify the TPM is correctly decrypting the LUKS partition(s) at boot.\n"
+3 -6
View File
@@ -55,22 +55,19 @@ if [ $SKIP -ne 1 ]; then
fi fi
delete_pcap() { delete_pcap() {
PCAP_DATA="/nsm/suripcap/" PCAP_DATA="/nsm/pcap/"
[ -d $PCAP_DATA ] && rm -rf $PCAP_DATA/* [ -d $PCAP_DATA ] && so-pcap-stop && rm -rf $PCAP_DATA/* && so-pcap-start
} }
delete_suricata() { delete_suricata() {
SURI_LOG="/nsm/suricata/" SURI_LOG="/nsm/suricata/"
[ -d $SURI_LOG ] && rm -rf $SURI_LOG/* [ -d $SURI_LOG ] && so-suricata-stop && rm -rf $SURI_LOG/* && so-suricata-start
} }
delete_zeek() { delete_zeek() {
ZEEK_LOG="/nsm/zeek/logs/" ZEEK_LOG="/nsm/zeek/logs/"
[ -d $ZEEK_LOG ] && so-zeek-stop && rm -rf $ZEEK_LOG/* && so-zeek-start [ -d $ZEEK_LOG ] && so-zeek-stop && rm -rf $ZEEK_LOG/* && so-zeek-start
} }
so-suricata-stop
delete_pcap delete_pcap
delete_suricata delete_suricata
delete_zeek delete_zeek
so-suricata-start
+1
View File
@@ -23,6 +23,7 @@ if [ $# -ge 1 ]; then
fi fi
case $1 in case $1 in
"steno") docker stop so-steno && docker rm so-steno && salt-call state.apply pcap queue=True;;
"elastic-fleet") docker stop so-elastic-fleet && docker rm so-elastic-fleet && salt-call state.apply elasticfleet queue=True;; "elastic-fleet") docker stop so-elastic-fleet && docker rm so-elastic-fleet && salt-call state.apply elasticfleet queue=True;;
*) docker stop so-$1 ; docker rm so-$1 ; salt-call state.apply $1 queue=True;; *) docker stop so-$1 ; docker rm so-$1 ; salt-call state.apply $1 queue=True;;
esac esac
+1 -1
View File
@@ -72,7 +72,7 @@ clean() {
done done
fi fi
## Clean up extracted pcaps ## Clean up extracted pcaps from Steno
PCAPS='/nsm/pcapout' PCAPS='/nsm/pcapout'
OLDEST_PCAP=$(find $PCAPS -type f -printf '%T+ %p\n' | sort -n | head -n 1) OLDEST_PCAP=$(find $PCAPS -type f -printf '%T+ %p\n' | sort -n | head -n 1)
if [ -z "$OLDEST_PCAP" -o "$OLDEST_PCAP" == ".." -o "$OLDEST_PCAP" == "." ]; then if [ -z "$OLDEST_PCAP" -o "$OLDEST_PCAP" == ".." -o "$OLDEST_PCAP" == "." ]; then
+1
View File
@@ -23,6 +23,7 @@ if [ $# -ge 1 ]; then
case $1 in case $1 in
"all") salt-call state.highstate queue=True;; "all") salt-call state.highstate queue=True;;
"steno") if docker ps | grep -q so-$1; then printf "\n$1 is already running!\n\n"; else docker rm so-$1 >/dev/null 2>&1 ; salt-call state.apply pcap queue=True; fi ;;
"elastic-fleet") if docker ps | grep -q so-$1; then printf "\n$1 is already running!\n\n"; else docker rm so-$1 >/dev/null 2>&1 ; salt-call state.apply elasticfleet queue=True; fi ;; "elastic-fleet") if docker ps | grep -q so-$1; then printf "\n$1 is already running!\n\n"; else docker rm so-$1 >/dev/null 2>&1 ; salt-call state.apply elasticfleet queue=True; fi ;;
*) if docker ps | grep -E -q '^so-$1$'; then printf "\n$1 is already running\n\n"; else docker rm so-$1 >/dev/null 2>&1 ; salt-call state.apply $1 queue=True; fi ;; *) if docker ps | grep -E -q '^so-$1$'; then printf "\n$1 is already running\n\n"; else docker rm so-$1 >/dev/null 2>&1 ; salt-call state.apply $1 queue=True; fi ;;
esac esac
@@ -10,7 +10,7 @@
. /usr/sbin/so-common . /usr/sbin/so-common
. /usr/sbin/so-image-common . /usr/sbin/so-image-common
REPLAYIFACE=${REPLAYIFACE:-"{{salt['pillar.get']('sensor:interface', '')}}"} REPLAYIFACE=${REPLAYIFACE:-$(lookup_pillar interface sensor)}
REPLAYSPEED=${REPLAYSPEED:-10} REPLAYSPEED=${REPLAYSPEED:-10}
mkdir -p /opt/so/samples mkdir -p /opt/so/samples
@@ -1,53 +0,0 @@
#!/usr/bin/python3
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
import logging
import os
import sys
def setup_logging(logger_name, log_file_path, log_level=logging.INFO, format_str='%(asctime)s - %(levelname)s - %(message)s'):
"""
Sets up logging for a script.
Parameters:
logger_name (str): The name of the logger.
log_file_path (str): The file path for the log file.
log_level (int): The logging level (e.g., logging.INFO, logging.DEBUG).
format_str (str): The format string for log messages.
Returns:
logging.Logger: Configured logger object.
"""
logger = logging.getLogger(logger_name)
logger.setLevel(log_level)
# Create directory for log file if it doesn't exist
log_file_dir = os.path.dirname(log_file_path)
if log_file_dir and not os.path.exists(log_file_dir):
try:
os.makedirs(log_file_dir)
except OSError as e:
print(f"Error creating directory {log_file_dir}: {e}")
sys.exit(1)
# Create handlers
c_handler = logging.StreamHandler()
f_handler = logging.FileHandler(log_file_path)
c_handler.setLevel(log_level)
f_handler.setLevel(log_level)
# Create formatter and add it to handlers
formatter = logging.Formatter(format_str)
c_handler.setFormatter(formatter)
f_handler.setFormatter(formatter)
# Add handlers to the logger if they are not already added
if not logger.hasHandlers():
logger.addHandler(c_handler)
logger.addHandler(f_handler)
return logger
@@ -6,7 +6,7 @@
# Elastic License 2.0. # Elastic License 2.0.
source /usr/sbin/so-common source /usr/sbin/so-common
doc_desktop_url="$DOC_BASE_URL/desktop" doc_desktop_url="$DOC_BASE_URL/desktop.html"
{# we only want the script to install the desktop if it is OEL -#} {# we only want the script to install the desktop if it is OEL -#}
{% if grains.os == 'OEL' -%} {% if grains.os == 'OEL' -%}
+6 -7
View File
@@ -63,7 +63,7 @@ function status {
function pcapinfo() { function pcapinfo() {
PCAP=$1 PCAP=$1
ARGS=$2 ARGS=$2
docker run --rm -v "$PCAP:/input.pcap" --entrypoint capinfos {{ MANAGER }}:5000/{{ IMAGEREPO }}/so-pcaptools:{{ VERSION }} /input.pcap -ae $ARGS docker run --rm -v "$PCAP:/input.pcap" --entrypoint capinfos {{ MANAGER }}:5000/{{ IMAGEREPO }}/so-pcaptools:{{ VERSION }} /input.pcap $ARGS
} }
function pcapfix() { function pcapfix() {
@@ -85,11 +85,10 @@ function suricata() {
docker run --rm \ docker run --rm \
-v /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro \ -v /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro \
-v /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro \ -v /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro \
-v /opt/so/rules/suricata/:/etc/suricata/rules:ro \ -v /opt/so/conf/suricata/rules:/etc/suricata/rules:ro \
-v ${LOG_PATH}:/var/log/suricata/:rw \ -v ${LOG_PATH}:/var/log/suricata/:rw \
-v ${NSM_PATH}/:/nsm/:rw \ -v ${NSM_PATH}/:/nsm/:rw \
-v "$PCAP:/input.pcap:ro" \ -v "$PCAP:/input.pcap:ro" \
-v /dev/null:/nsm/suripcap:rw \
-v /opt/so/conf/suricata/bpf:/etc/suricata/bpf:ro \ -v /opt/so/conf/suricata/bpf:/etc/suricata/bpf:ro \
{{ MANAGER }}:5000/{{ IMAGEREPO }}/so-suricata:{{ VERSION }} \ {{ MANAGER }}:5000/{{ IMAGEREPO }}/so-suricata:{{ VERSION }} \
--runmode single -k none -r /input.pcap > $LOG_PATH/console.log 2>&1 --runmode single -k none -r /input.pcap > $LOG_PATH/console.log 2>&1
@@ -173,7 +172,7 @@ for PCAP in $INPUT_FILES; do
status "- assigning unique identifier to import: $HASH" status "- assigning unique identifier to import: $HASH"
pcap_data=$(pcapinfo "${PCAP}") pcap_data=$(pcapinfo "${PCAP}")
if ! echo "$pcap_data" | grep -q "Earliest packet time:" || echo "$pcap_data" |egrep -q "Latest packet time: 1970-01-01|Latest packet time: n/a"; then if ! echo "$pcap_data" | grep -q "First packet time:" || echo "$pcap_data" |egrep -q "Last packet time: 1970-01-01|Last packet time: n/a"; then
status "- this PCAP file is invalid; skipping" status "- this PCAP file is invalid; skipping"
INVALID_PCAPS_COUNT=$((INVALID_PCAPS_COUNT + 1)) INVALID_PCAPS_COUNT=$((INVALID_PCAPS_COUNT + 1))
else else
@@ -205,8 +204,8 @@ for PCAP in $INPUT_FILES; do
HASHES="${HASHES} ${HASH}" HASHES="${HASHES} ${HASH}"
fi fi
START=$(pcapinfo "${PCAP}" -a |grep "Earliest packet time:" | awk '{print $4}') START=$(pcapinfo "${PCAP}" -a |grep "First packet time:" | awk '{print $4}')
END=$(pcapinfo "${PCAP}" -e |grep "Latest packet time:" | awk '{print $4}') END=$(pcapinfo "${PCAP}" -e |grep "Last packet time:" | awk '{print $4}')
status "- found PCAP data spanning dates $START through $END" status "- found PCAP data spanning dates $START through $END"
# compare $START to $START_OLDEST # compare $START to $START_OLDEST
@@ -248,7 +247,7 @@ fi
START_OLDEST_SLASH=$(echo $START_OLDEST | sed -e 's/-/%2F/g') START_OLDEST_SLASH=$(echo $START_OLDEST | sed -e 's/-/%2F/g')
END_NEWEST_SLASH=$(echo $END_NEWEST | sed -e 's/-/%2F/g') END_NEWEST_SLASH=$(echo $END_NEWEST | sed -e 's/-/%2F/g')
if [[ $VALID_PCAPS_COUNT -gt 0 ]] || [[ $SKIPPED_PCAPS_COUNT -gt 0 ]]; then if [[ $VALID_PCAPS_COUNT -gt 0 ]] || [[ $SKIPPED_PCAPS_COUNT -gt 0 ]]; then
URL="https://{{ URLBASE }}/#/dashboards?q=$HASH_FILTERS%20%7C%20groupby%20event.module*%20%7C%20groupby%20-sankey%20event.module*%20event.dataset%20%7C%20groupby%20event.dataset%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port%20%7C%20groupby%20network.protocol%20%7C%20groupby%20rule.name%20rule.category%20event.severity_label%20%7C%20groupby%20dns.query.name%20%7C%20groupby%20file.mime_type%20%7C%20groupby%20http.virtual_host%20http.uri%20%7C%20groupby%20notice.note%20notice.message%20notice.sub_message%20%7C%20groupby%20ssl.server_name%20%7C%20groupby%20source.as.organization.name%20source.geo.country_name%20%7C%20groupby%20destination.as.organization.name%20destination.geo.country_name&t=${START_OLDEST_SLASH}%2000%3A00%3A00%20AM%20-%20${END_NEWEST_SLASH}%2000%3A00%3A00%20AM&z=UTC" URL="https://{{ URLBASE }}/#/dashboards?q=$HASH_FILTERS%20%7C%20groupby%20-sankey%20event.dataset%20event.category%2a%20%7C%20groupby%20-pie%20event.category%20%7C%20groupby%20-bar%20event.module%20%7C%20groupby%20event.dataset%20%7C%20groupby%20event.module%20%7C%20groupby%20event.category%20%7C%20groupby%20observer.name%20%7C%20groupby%20source.ip%20%7C%20groupby%20destination.ip%20%7C%20groupby%20destination.port&t=${START_OLDEST_SLASH}%2000%3A00%3A00%20AM%20-%20${END_NEWEST_SLASH}%2000%3A00%3A00%20AM&z=UTC"
status "Import complete!" status "Import complete!"
status status
+16 -37
View File
@@ -9,9 +9,6 @@
. /usr/sbin/so-common . /usr/sbin/so-common
software_raid=("SOSMN" "SOSMN-DE02" "SOSSNNV" "SOSSNNV-DE02" "SOS10k-DE02" "SOS10KNV" "SOS10KNV-DE02" "SOS10KNV-DE02" "SOS2000-DE02" "SOS-GOFAST-LT-DE02" "SOS-GOFAST-MD-DE02" "SOS-GOFAST-HV-DE02")
hardware_raid=("SOS1000" "SOS1000F" "SOSSN7200" "SOS5000" "SOS4000")
{%- if salt['grains.get']('sosmodel', '') %} {%- if salt['grains.get']('sosmodel', '') %}
{%- set model = salt['grains.get']('sosmodel') %} {%- set model = salt['grains.get']('sosmodel') %}
model={{ model }} model={{ model }}
@@ -19,35 +16,25 @@ model={{ model }}
if [[ $model =~ ^(SO2AMI01|SO2AZI01|SO2GCI01)$ ]]; then if [[ $model =~ ^(SO2AMI01|SO2AZI01|SO2GCI01)$ ]]; then
exit 0 exit 0
fi fi
for i in "${software_raid[@]}"; do
if [[ "$model" == $i ]]; then
is_softwareraid=true
is_hwraid=false
break
fi
done
for i in "${hardware_raid[@]}"; do
if [[ "$model" == $i ]]; then
is_softwareraid=false
is_hwraid=true
break
fi
done
{%- else %} {%- else %}
echo "This is not an appliance" echo "This is not an appliance"
exit 0 exit 0
{%- endif %} {%- endif %}
if [[ $model =~ ^(SOS10K|SOS500|SOS1000|SOS1000F|SOS4000|SOSSN7200|SOSSNNV|SOSMN)$ ]]; then
is_bossraid=true
fi
if [[ $model =~ ^(SOSSNNV|SOSMN)$ ]]; then
is_swraid=true
fi
if [[ $model =~ ^(SOS10K|SOS500|SOS1000|SOS1000F|SOS4000|SOSSN7200)$ ]]; then
is_hwraid=true
fi
check_nsm_raid() { check_nsm_raid() {
PERCCLI=$(/opt/raidtools/perccli/perccli64 /c0/v0 show|grep RAID|grep Optl) PERCCLI=$(/opt/raidtools/perccli/perccli64 /c0/v0 show|grep RAID|grep Optl)
MEGACTL=$(/opt/raidtools/megasasctl |grep optimal) MEGACTL=$(/opt/raidtools/megasasctl |grep optimal)
if [[ "$model" == "SOS500" || "$model" == "SOS500-DE02" ]]; then
#This doesn't have raid if [[ $APPLIANCE == '1' ]]; then
HWRAID=0
else
if [[ -n $PERCCLI ]]; then if [[ -n $PERCCLI ]]; then
HWRAID=0 HWRAID=0
elif [[ -n $MEGACTL ]]; then elif [[ -n $MEGACTL ]]; then
@@ -55,6 +42,7 @@ check_nsm_raid() {
else else
HWRAID=1 HWRAID=1
fi fi
fi fi
} }
@@ -62,16 +50,7 @@ check_nsm_raid() {
check_boss_raid() { check_boss_raid() {
MVCLI=$(/usr/local/bin/mvcli info -o vd |grep status |grep functional) MVCLI=$(/usr/local/bin/mvcli info -o vd |grep status |grep functional)
MVTEST=$(/usr/local/bin/mvcli info -o vd | grep "No adapter") MVTEST=$(/usr/local/bin/mvcli info -o vd | grep "No adapter")
BOSSNVMECLI=$(/usr/local/bin/mnv_cli info -o vd -i 0 | grep Functional)
# Is this NVMe Boss Raid?
if [[ "$model" =~ "-DE02" ]]; then
if [[ -n $BOSSNVMECLI ]]; then
BOSSRAID=0
else
BOSSRAID=1
fi
else
# Check to see if this is a SM based system # Check to see if this is a SM based system
if [[ -z $MVTEST ]]; then if [[ -z $MVTEST ]]; then
if [[ -n $MVCLI ]]; then if [[ -n $MVCLI ]]; then
@@ -83,7 +62,6 @@ check_boss_raid() {
# This doesn't have boss raid so lets make it 0 # This doesn't have boss raid so lets make it 0
BOSSRAID=0 BOSSRAID=0
fi fi
fi
} }
check_software_raid() { check_software_raid() {
@@ -101,13 +79,14 @@ SWRAID=0
BOSSRAID=0 BOSSRAID=0
HWRAID=0 HWRAID=0
if [[ "$is_hwraid" == "true" ]]; then if [[ $is_hwraid ]]; then
check_nsm_raid check_nsm_raid
fi
if [[ $is_bossraid ]]; then
check_boss_raid check_boss_raid
fi fi
if [[ "$is_softwareraid" == "true" ]]; then if [[ $is_swraid ]]; then
check_software_raid check_software_raid
check_boss_raid
fi fi
sum=$(($SWRAID + $BOSSRAID + $HWRAID)) sum=$(($SWRAID + $BOSSRAID + $HWRAID))
@@ -1,132 +0,0 @@
#!/opt/saltstack/salt/bin/python3
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
#
# Note: Per the Elastic License 2.0, the second limitation states:
#
# "You may not move, change, disable, or circumvent the license key functionality
# in the software, and you may not remove or obscure any functionality in the
# software that is protected by the license key."
{% if 'vrt' in salt['pillar.get']('features', []) -%}
"""
Script for emitting VM deployment status events to the Salt event bus.
This script provides functionality to emit status events for VM deployment operations,
used by various Security Onion VM management tools.
Usage:
so-salt-emit-vm-deployment-status-event -v <vm_name> -H <hypervisor> -s <status>
Arguments:
-v, --vm-name Name of the VM (hostname_role)
-H, --hypervisor Name of the hypervisor
-s, --status Current deployment status of the VM
Example:
so-salt-emit-vm-deployment-status-event -v sensor1_sensor -H hypervisor1 -s "Creating"
"""
import sys
import argparse
import logging
import salt.client
from typing import Dict, Any
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
log = logging.getLogger(__name__)
def emit_event(vm_name: str, hypervisor: str, status: str) -> bool:
"""
Emit a VM deployment status event to the salt event bus.
Args:
vm_name: Name of the VM (hostname_role)
hypervisor: Name of the hypervisor
status: Current deployment status of the VM
Returns:
bool: True if event was sent successfully, False otherwise
Raises:
ValueError: If status is not a valid deployment status
"""
log.info("Attempting to emit deployment event...")
try:
caller = salt.client.Caller()
event_data = {
'vm_name': vm_name,
'hypervisor': hypervisor,
'status': status
}
# Use consistent event tag structure
event_tag = f'soc/dyanno/hypervisor/{status.lower()}'
ret = caller.cmd(
'event.send',
event_tag,
event_data
)
if not ret:
log.error("Failed to emit VM deployment status event: %s", event_data)
return False
log.info("Successfully emitted VM deployment status event: %s", event_data)
return True
except Exception as e:
log.error("Error emitting VM deployment status event: %s", str(e))
return False
def parse_args():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description='Emit VM deployment status events to the Salt event bus.'
)
parser.add_argument('-v', '--vm-name', required=True,
help='Name of the VM (hostname_role)')
parser.add_argument('-H', '--hypervisor', required=True,
help='Name of the hypervisor')
parser.add_argument('-s', '--status', required=True,
help='Current deployment status of the VM')
return parser.parse_args()
def main():
"""Main entry point for the script."""
try:
args = parse_args()
success = emit_event(
vm_name=args.vm_name,
hypervisor=args.hypervisor,
status=args.status
)
if not success:
sys.exit(1)
except Exception as e:
log.error("Failed to emit status event: %s", str(e))
sys.exit(1)
if __name__ == '__main__':
main()
{%- else -%}
echo "Hypervisor nodes are a feature supported only for customers with a valid license. \
Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com \
for more information about purchasing a license to enable this feature."
{% endif -%}
+34
View File
@@ -0,0 +1,34 @@
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
so-curator:
docker_container.absent:
- force: True
so-curator_so-status.disabled:
file.line:
- name: /opt/so/conf/so-status/so-status.conf
- match: ^so-curator$
- mode: delete
so-curator-cluster-close:
cron.absent:
- identifier: so-curator-cluster-close
so-curator-cluster-delete:
cron.absent:
- identifier: so-curator-cluster-delete
delete_curator_configuration:
file.absent:
- name: /opt/so/conf/curator
- recurse: True
{% set files = salt.file.find(path='/usr/sbin', name='so-curator*') %}
{% if files|length > 0 %}
delete_curator_scripts:
file.absent:
- names: {{files|yaml}}
{% endif %}
-1
View File
@@ -334,7 +334,6 @@ desktop_packages:
- pulseaudio-libs - pulseaudio-libs
- pulseaudio-libs-glib2 - pulseaudio-libs-glib2
- pulseaudio-utils - pulseaudio-utils
- putty
- sane-airscan - sane-airscan
- sane-backends - sane-backends
- sane-backends-drivers-cameras - sane-backends-drivers-cameras
+16 -3
View File
@@ -3,16 +3,29 @@
{# we only want this state to run it is CentOS #} {# we only want this state to run it is CentOS #}
{% if GLOBALS.os == 'OEL' %} {% if GLOBALS.os == 'OEL' %}
{% set global_ca_text = [] %}
{% set global_ca_server = [] %}
{% set manager = GLOBALS.manager %}
{% set x509dict = salt['mine.get'](manager | lower~'*', 'x509.get_pem_entries') %}
{% for host in x509dict %}
{% if host.split('_')|last in ['manager', 'managersearch', 'standalone', 'import', 'eval'] %}
{% do global_ca_text.append(x509dict[host].get('/etc/pki/ca.crt')|replace('\n', '')) %}
{% do global_ca_server.append(host) %}
{% endif %}
{% endfor %}
{% set trusttheca_text = global_ca_text[0] %}
{% set ca_server = global_ca_server[0] %}
trusted_ca: trusted_ca:
file.managed: x509.pem_managed:
- name: /etc/pki/ca-trust/source/anchors/ca.crt - name: /etc/pki/ca-trust/source/anchors/ca.crt
- source: salt://ca/files/ca.crt - text: {{ trusttheca_text }}
update_ca_certs: update_ca_certs:
cmd.run: cmd.run:
- name: update-ca-trust - name: update-ca-trust
- onchanges: - onchanges:
- file: trusted_ca - x509: trusted_ca
{% else %} {% else %}
+27 -65
View File
@@ -1,10 +1,6 @@
docker: docker:
range: '172.17.1.0/24' range: '172.17.1.0/24'
gateway: '172.17.1.1' gateway: '172.17.1.1'
ulimits:
- name: nofile
soft: 1048576
hard: 1048576
containers: containers:
'so-dockerregistry': 'so-dockerregistry':
final_octet: 20 final_octet: 20
@@ -13,7 +9,6 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-elastic-fleet': 'so-elastic-fleet':
final_octet: 21 final_octet: 21
port_bindings: port_bindings:
@@ -21,7 +16,6 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-elasticsearch': 'so-elasticsearch':
final_octet: 22 final_octet: 22
port_bindings: port_bindings:
@@ -30,16 +24,11 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: 'so-idstools':
- name: memlock final_octet: 25
soft: -1 custom_bind_mounts: []
hard: -1 extra_hosts: []
- name: nofile extra_env: []
soft: 65536
hard: 65536
- name: nproc
soft: 4096
hard: 4096
'so-influxdb': 'so-influxdb':
final_octet: 26 final_octet: 26
port_bindings: port_bindings:
@@ -47,7 +36,6 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-kibana': 'so-kibana':
final_octet: 27 final_octet: 27
port_bindings: port_bindings:
@@ -55,7 +43,6 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-kratos': 'so-kratos':
final_octet: 28 final_octet: 28
port_bindings: port_bindings:
@@ -64,16 +51,6 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-hydra':
final_octet: 30
port_bindings:
- 0.0.0.0:4444:4444
- 0.0.0.0:4445:4445
custom_bind_mounts: []
extra_hosts: []
extra_env: []
ulimits: []
'so-logstash': 'so-logstash':
final_octet: 29 final_octet: 29
port_bindings: port_bindings:
@@ -90,7 +67,13 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: [] 'so-mysql':
final_octet: 30
port_bindings:
- 0.0.0.0:3306:3306
custom_bind_mounts: []
extra_hosts: []
extra_env: []
'so-nginx': 'so-nginx':
final_octet: 31 final_octet: 31
port_bindings: port_bindings:
@@ -98,19 +81,16 @@ docker:
- 443:443 - 443:443
- 8443:8443 - 8443:8443
- 7788:7788 - 7788:7788
- 7789:7789
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: [] 'so-playbook':
'so-nginx-fleet-node': final_octet: 32
final_octet: 31
port_bindings: port_bindings:
- 8443:8443 - 0.0.0.0:3000:3000
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-redis': 'so-redis':
final_octet: 33 final_octet: 33
port_bindings: port_bindings:
@@ -119,13 +99,11 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-sensoroni': 'so-sensoroni':
final_octet: 99 final_octet: 99
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-soc': 'so-soc':
final_octet: 34 final_octet: 34
port_bindings: port_bindings:
@@ -133,19 +111,23 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: [] 'so-soctopus':
final_octet: 35
port_bindings:
- 0.0.0.0:7000:7000
custom_bind_mounts: []
extra_hosts: []
extra_env: []
'so-strelka-backend': 'so-strelka-backend':
final_octet: 36 final_octet: 36
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-strelka-filestream': 'so-strelka-filestream':
final_octet: 37 final_octet: 37
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-strelka-frontend': 'so-strelka-frontend':
final_octet: 38 final_octet: 38
port_bindings: port_bindings:
@@ -153,13 +135,11 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-strelka-manager': 'so-strelka-manager':
final_octet: 39 final_octet: 39
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-strelka-gatekeeper': 'so-strelka-gatekeeper':
final_octet: 40 final_octet: 40
port_bindings: port_bindings:
@@ -167,7 +147,6 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-strelka-coordinator': 'so-strelka-coordinator':
final_octet: 41 final_octet: 41
port_bindings: port_bindings:
@@ -175,13 +154,11 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-elastalert': 'so-elastalert':
final_octet: 42 final_octet: 42
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-elastic-fleet-package-registry': 'so-elastic-fleet-package-registry':
final_octet: 44 final_octet: 44
port_bindings: port_bindings:
@@ -189,13 +166,11 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-idh': 'so-idh':
final_octet: 45 final_octet: 45
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-elastic-agent': 'so-elastic-agent':
final_octet: 46 final_octet: 46
port_bindings: port_bindings:
@@ -204,36 +179,23 @@ docker:
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-telegraf': 'so-telegraf':
final_octet: 99 final_octet: 99
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: [] 'so-steno':
final_octet: 99
custom_bind_mounts: []
extra_hosts: []
extra_env: []
'so-suricata': 'so-suricata':
final_octet: 99 final_octet: 99
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits: []
'so-zeek': 'so-zeek':
final_octet: 99 final_octet: 99
custom_bind_mounts: [] custom_bind_mounts: []
extra_hosts: [] extra_hosts: []
extra_env: [] extra_env: []
ulimits:
- name: core
soft: 0
hard: 0
'so-kafka':
final_octet: 88
port_bindings:
- 0.0.0.0:9092:9092
- 0.0.0.0:29092:29092
- 0.0.0.0:9093:9093
- 0.0.0.0:8778:8778
custom_bind_mounts: []
extra_hosts: []
extra_env: []
ulimits: []
+4 -4
View File
@@ -1,8 +1,8 @@
{% import_yaml 'docker/defaults.yaml' as DOCKERDEFAULTS %} {% import_yaml 'docker/defaults.yaml' as DOCKERDEFAULTS %}
{% set DOCKERMERGED = salt['pillar.get']('docker', DOCKERDEFAULTS.docker, merge=True) %} {% set DOCKER = salt['pillar.get']('docker', DOCKERDEFAULTS.docker, merge=True) %}
{% set RANGESPLIT = DOCKERMERGED.range.split('.') %} {% set RANGESPLIT = DOCKER.range.split('.') %}
{% set FIRSTTHREE = RANGESPLIT[0] ~ '.' ~ RANGESPLIT[1] ~ '.' ~ RANGESPLIT[2] ~ '.' %} {% set FIRSTTHREE = RANGESPLIT[0] ~ '.' ~ RANGESPLIT[1] ~ '.' ~ RANGESPLIT[2] ~ '.' %}
{% for container, vals in DOCKERMERGED.containers.items() %} {% for container, vals in DOCKER.containers.items() %}
{% do DOCKERMERGED.containers[container].update({'ip': FIRSTTHREE ~ DOCKERMERGED.containers[container].final_octet}) %} {% do DOCKER.containers[container].update({'ip': FIRSTTHREE ~ DOCKER.containers[container].final_octet}) %}
{% endfor %} {% endfor %}
-24
View File
@@ -1,24 +0,0 @@
{% from 'docker/docker.map.jinja' import DOCKERMERGED -%}
{
"registry-mirrors": [
"https://:5000"
],
"bip": "172.17.0.1/24",
"default-address-pools": [
{
"base": "172.17.0.0/24",
"size": 24
}
]
{%- if DOCKERMERGED.ulimits %},
"default-ulimits": {
{%- for ULIMIT in DOCKERMERGED.ulimits %}
"{{ ULIMIT.name }}": {
"Name": "{{ ULIMIT.name }}",
"Soft": {{ ULIMIT.soft }},
"Hard": {{ ULIMIT.hard }}
}{{ "," if not loop.last else "" }}
{%- endfor %}
}
{%- endif %}
}
+48 -12
View File
@@ -3,27 +3,61 @@
# https://securityonion.net/license; you may not use this file except in compliance with the # https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0. # Elastic License 2.0.
{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'docker/docker.map.jinja' import DOCKER %}
{% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'vars/globals.map.jinja' import GLOBALS %}
# docker service requires the ca.crt # include ssl since docker service requires the intca
include: include:
- ca - ssl
dockergroup: dockergroup:
group.present: group.present:
- name: docker - name: docker
- gid: 920 - gid: 920
{% if GLOBALS.os_family == 'Debian' %}
{% if grains.oscodename == 'bookworm' %}
dockerheldpackages: dockerheldpackages:
pkg.installed: pkg.installed:
- pkgs: - pkgs:
- containerd.io: 2.2.1-1.el9 - containerd.io: 1.6.21-1
- docker-ce: 3:29.2.1-1.el9 - docker-ce: 5:24.0.3-1~debian.12~bookworm
- docker-ce-cli: 1:29.2.1-1.el9 - docker-ce-cli: 5:24.0.3-1~debian.12~bookworm
- docker-ce-rootless-extras: 29.2.1-1.el9 - docker-ce-rootless-extras: 5:24.0.3-1~debian.12~bookworm
- hold: True - hold: True
- update_holds: True - update_holds: True
{% elif grains.oscodename == 'jammy' %}
dockerheldpackages:
pkg.installed:
- pkgs:
- containerd.io: 1.6.21-1
- docker-ce: 5:24.0.2-1~ubuntu.22.04~jammy
- docker-ce-cli: 5:24.0.2-1~ubuntu.22.04~jammy
- docker-ce-rootless-extras: 5:24.0.2-1~ubuntu.22.04~jammy
- hold: True
- update_holds: True
{% else %}
dockerheldpackages:
pkg.installed:
- pkgs:
- containerd.io: 1.4.9-1
- docker-ce: 5:20.10.8~3-0~ubuntu-focal
- docker-ce-cli: 5:20.10.5~3-0~ubuntu-focal
- docker-ce-rootless-extras: 5:20.10.5~3-0~ubuntu-focal
- hold: True
- update_holds: True
{% endif %}
{% else %}
dockerheldpackages:
pkg.installed:
- pkgs:
- containerd.io: 1.6.21-3.1.el9
- docker-ce: 24.0.4-1.el9
- docker-ce-cli: 24.0.4-1.el9
- docker-ce-rootless-extras: 24.0.4-1.el9
- hold: True
- update_holds: True
{% endif %}
#disable docker from managing iptables #disable docker from managing iptables
iptables_disabled: iptables_disabled:
@@ -41,9 +75,10 @@ dockeretc:
file.directory: file.directory:
- name: /etc/docker - name: /etc/docker
# Manager daemon.json
docker_daemon: docker_daemon:
file.managed: file.managed:
- source: salt://docker/files/daemon.json.jinja - source: salt://common/files/daemon.json
- name: /etc/docker/daemon.json - name: /etc/docker/daemon.json
- template: jinja - template: jinja
@@ -54,9 +89,10 @@ docker_running:
- enable: True - enable: True
- watch: - watch:
- file: docker_daemon - file: docker_daemon
- x509: trusttheca
- require: - require:
- file: docker_daemon - file: docker_daemon
- file: trusttheca - x509: trusttheca
# Reserve OS ports for Docker proxy in case boot settings are not already applied/present # Reserve OS ports for Docker proxy in case boot settings are not already applied/present
@@ -74,12 +110,12 @@ dockerreserveports:
sos_docker_net: sos_docker_net:
docker_network.present: docker_network.present:
- name: sobridge - name: sobridge
- subnet: {{ DOCKERMERGED.range }} - subnet: {{ DOCKER.range }}
- gateway: {{ DOCKERMERGED.gateway }} - gateway: {{ DOCKER.gateway }}
- options: - options:
com.docker.network.bridge.name: 'sobridge' com.docker.network.bridge.name: 'sobridge'
com.docker.network.driver.mtu: '1500' com.docker.network.driver.mtu: '1500'
com.docker.network.bridge.enable_ip_masquerade: 'true' com.docker.network.bridge.enable_ip_masquerade: 'true'
com.docker.network.bridge.enable_icc: 'true' com.docker.network.bridge.enable_icc: 'true'
com.docker.network.bridge.host_binding_ipv4: '0.0.0.0' com.docker.network.bridge.host_binding_ipv4: '0.0.0.0'
- unless: ip l | grep sobridge - unless: 'docker network ls | grep sobridge'
+12 -48
View File
@@ -1,94 +1,58 @@
docker: docker:
gateway: gateway:
description: Gateway for the default docker interface. description: Gateway for the default docker interface.
helpLink: docker helpLink: docker.html
advanced: True advanced: True
range: range:
description: Default docker IP range for containers. description: Default docker IP range for containers.
helpLink: docker
advanced: True
ulimits:
description: |
Default ulimit settings applied to all containers via the Docker daemon. Each entry specifies a resource name (e.g. nofile, memlock, core, nproc) with soft and hard limits. Individual container ulimits override these defaults. Valid resource names include: cpu, fsize, data, stack, core, rss, nproc, nofile, memlock, as, locks, sigpending, msgqueue, nice, rtprio, rttime.
forcedType: "[]{}"
syntax: json
advanced: True
helpLink: docker.html helpLink: docker.html
uiElements: advanced: True
- field: name
label: Resource Name
required: True
regex: ^(cpu|fsize|data|stack|core|rss|nproc|nofile|memlock|as|locks|sigpending|msgqueue|nice|rtprio|rttime)$
regexFailureMessage: You must enter a valid ulimit name (cpu, fsize, data, stack, core, rss, nproc, nofile, memlock, as, locks, sigpending, msgqueue, nice, rtprio, rttime).
- field: soft
label: Soft Limit
forcedType: int
- field: hard
label: Hard Limit
forcedType: int
containers: containers:
so-dockerregistry: &dockerOptions so-dockerregistry: &dockerOptions
final_octet: final_octet:
description: Last octet of the container IP address. description: Last octet of the container IP address.
helpLink: docker helpLink: docker.html
readonly: True readonly: True
advanced: True advanced: True
global: True global: True
port_bindings: port_bindings:
description: List of port bindings for the container. description: List of port bindings for the container.
helpLink: docker helpLink: docker.html
advanced: True advanced: True
multiline: True multiline: True
forcedType: "[]string" forcedType: "[]string"
custom_bind_mounts: custom_bind_mounts:
description: List of custom local volume bindings. description: List of custom local volume bindings.
advanced: True advanced: True
helpLink: docker helpLink: docker.html
multiline: True multiline: True
forcedType: "[]string" forcedType: "[]string"
extra_hosts: extra_hosts:
description: List of additional host entries for the container. description: List of additional host entries for the container.
advanced: True advanced: True
helpLink: docker helpLink: docker.html
multiline: True multiline: True
forcedType: "[]string" forcedType: "[]string"
extra_env: extra_env:
description: List of additional ENV entries for the container. description: List of additional ENV entries for the container.
advanced: True advanced: True
helpLink: docker helpLink: docker.html
multiline: True multiline: True
forcedType: "[]string" forcedType: "[]string"
ulimits:
description: |
Ulimit settings for the container. Each entry specifies a resource name (e.g. nofile, memlock, core, nproc) with optional soft and hard limits. Valid resource names include: cpu, fsize, data, stack, core, rss, nproc, nofile, memlock, as, locks, sigpending, msgqueue, nice, rtprio, rttime.
advanced: True
helpLink: docker.html
forcedType: "[]{}"
syntax: json
uiElements:
- field: name
label: Resource Name
required: True
regex: ^(cpu|fsize|data|stack|core|rss|nproc|nofile|memlock|as|locks|sigpending|msgqueue|nice|rtprio|rttime)$
regexFailureMessage: You must enter a valid ulimit name (cpu, fsize, data, stack, core, rss, nproc, nofile, memlock, as, locks, sigpending, msgqueue, nice, rtprio, rttime).
- field: soft
label: Soft Limit
forcedType: int
- field: hard
label: Hard Limit
forcedType: int
so-elastic-fleet: *dockerOptions so-elastic-fleet: *dockerOptions
so-elasticsearch: *dockerOptions so-elasticsearch: *dockerOptions
so-idstools: *dockerOptions
so-influxdb: *dockerOptions so-influxdb: *dockerOptions
so-kibana: *dockerOptions so-kibana: *dockerOptions
so-kratos: *dockerOptions so-kratos: *dockerOptions
so-hydra: *dockerOptions
so-logstash: *dockerOptions so-logstash: *dockerOptions
so-mysql: *dockerOptions
so-nginx: *dockerOptions so-nginx: *dockerOptions
so-nginx-fleet-node: *dockerOptions so-playbook: *dockerOptions
so-redis: *dockerOptions so-redis: *dockerOptions
so-sensoroni: *dockerOptions so-sensoroni: *dockerOptions
so-soc: *dockerOptions so-soc: *dockerOptions
so-soctopus: *dockerOptions
so-strelka-backend: *dockerOptions so-strelka-backend: *dockerOptions
so-strelka-filestream: *dockerOptions so-strelka-filestream: *dockerOptions
so-strelka-frontend: *dockerOptions so-strelka-frontend: *dockerOptions
@@ -100,6 +64,6 @@ docker:
so-idh: *dockerOptions so-idh: *dockerOptions
so-elastic-agent: *dockerOptions so-elastic-agent: *dockerOptions
so-telegraf: *dockerOptions so-telegraf: *dockerOptions
so-steno: *dockerOptions
so-suricata: *dockerOptions so-suricata: *dockerOptions
so-zeek: *dockerOptions so-zeek: *dockerOptions
so-kafka: *dockerOptions
-30
View File
@@ -82,36 +82,6 @@ elastasomodulesync:
- group: 933 - group: 933
- makedirs: True - makedirs: True
elastacustomdir:
file.directory:
- name: /opt/so/conf/elastalert/custom
- user: 933
- group: 933
- makedirs: True
elastacustomsync:
file.recurse:
- name: /opt/so/conf/elastalert/custom
- source: salt://elastalert/files/custom
- user: 933
- group: 933
- makedirs: True
- file_mode: 660
- show_changes: False
elastapredefinedsync:
file.recurse:
- name: /opt/so/conf/elastalert/predefined
- source: salt://elastalert/files/predefined
- user: 933
- group: 933
- makedirs: True
- template: jinja
- file_mode: 660
- context:
elastalert: {{ ELASTALERTMERGED }}
- show_changes: False
elastaconf: elastaconf:
file.managed: file.managed:
- name: /opt/so/conf/elastalert/elastalert_config.yaml - name: /opt/so/conf/elastalert/elastalert_config.yaml
-1
View File
@@ -1,6 +1,5 @@
elastalert: elastalert:
enabled: False enabled: False
alerter_parameters: ""
config: config:
rules_folder: /opt/elastalert/rules/ rules_folder: /opt/elastalert/rules/
scan_subdirectories: true scan_subdirectories: true
+9 -17
View File
@@ -6,7 +6,7 @@
{% from 'allowed_states.map.jinja' import allowed_states %} {% from 'allowed_states.map.jinja' import allowed_states %}
{% if sls.split('.')[0] in allowed_states %} {% if sls.split('.')[0] in allowed_states %}
{% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'vars/globals.map.jinja' import GLOBALS %}
{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'docker/docker.map.jinja' import DOCKER %}
include: include:
- elastalert.config - elastalert.config
@@ -24,39 +24,31 @@ so-elastalert:
- user: so-elastalert - user: so-elastalert
- networks: - networks:
- sobridge: - sobridge:
- ipv4_address: {{ DOCKERMERGED.containers['so-elastalert'].ip }} - ipv4_address: {{ DOCKER.containers['so-elastalert'].ip }}
- detach: True - detach: True
- binds: - binds:
- /opt/so/rules/elastalert:/opt/elastalert/rules/:ro - /opt/so/rules/elastalert:/opt/elastalert/rules/:ro
- /opt/so/log/elastalert:/var/log/elastalert:rw - /opt/so/log/elastalert:/var/log/elastalert:rw
- /opt/so/conf/elastalert/modules/:/opt/elastalert/modules/:ro - /opt/so/conf/elastalert/modules/:/opt/elastalert/modules/:ro
- /opt/so/conf/elastalert/predefined/:/opt/elastalert/predefined/:ro
- /opt/so/conf/elastalert/custom/:/opt/elastalert/custom/:ro
- /opt/so/conf/elastalert/elastalert_config.yaml:/opt/elastalert/config.yaml:ro - /opt/so/conf/elastalert/elastalert_config.yaml:/opt/elastalert/config.yaml:ro
{% if DOCKERMERGED.containers['so-elastalert'].custom_bind_mounts %} {% if DOCKER.containers['so-elastalert'].custom_bind_mounts %}
{% for BIND in DOCKERMERGED.containers['so-elastalert'].custom_bind_mounts %} {% for BIND in DOCKER.containers['so-elastalert'].custom_bind_mounts %}
- {{ BIND }} - {{ BIND }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
- extra_hosts: - extra_hosts:
- {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }}
{% if DOCKERMERGED.containers['so-elastalert'].extra_hosts %} {% if DOCKER.containers['so-elastalert'].extra_hosts %}
{% for XTRAHOST in DOCKERMERGED.containers['so-elastalert'].extra_hosts %} {% for XTRAHOST in DOCKER.containers['so-elastalert'].extra_hosts %}
- {{ XTRAHOST }} - {{ XTRAHOST }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% if DOCKERMERGED.containers['so-elastalert'].extra_env %} {% if DOCKER.containers['so-elastalert'].extra_env %}
- environment: - environment:
{% for XTRAENV in DOCKERMERGED.containers['so-elastalert'].extra_env %} {% for XTRAENV in DOCKER.containers['so-elastalert'].extra_env %}
- {{ XTRAENV }} - {{ XTRAENV }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% if DOCKERMERGED.containers['so-elastalert'].ulimits %}
- ulimits:
{% for ULIMIT in DOCKERMERGED.containers['so-elastalert'].ulimits %}
- {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }}
{% endfor %}
{% endif %}
- require: - require:
- cmd: wait_for_elasticsearch - cmd: wait_for_elasticsearch
- file: elastarules - file: elastarules
@@ -66,7 +58,7 @@ so-elastalert:
- watch: - watch:
- file: elastaconf - file: elastaconf
- onlyif: - onlyif:
- "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 9" {# only run this state if elasticsearch is version 9 #} - "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 8" {# only run this state if elasticsearch is version 8 #}
delete_so-elastalert_so-status.disabled: delete_so-elastalert_so-status.disabled:
file.uncomment: file.uncomment:
@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
from time import gmtime, strftime
import requests,json
from elastalert.alerts import Alerter
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class PlaybookESAlerter(Alerter):
"""
Use matched data to create alerts in elasticsearch
"""
required_options = set(['play_title','play_url','sigma_level'])
def alert(self, matches):
for match in matches:
today = strftime("%Y.%m.%d", gmtime())
timestamp = strftime("%Y-%m-%d"'T'"%H:%M:%S"'.000Z', gmtime())
headers = {"Content-Type": "application/json"}
creds = None
if 'es_username' in self.rule and 'es_password' in self.rule:
creds = (self.rule['es_username'], self.rule['es_password'])
payload = {"tags":"alert","rule": { "name": self.rule['play_title'],"case_template": self.rule['play_id'],"uuid": self.rule['play_id'],"category": self.rule['rule.category']},"event":{ "severity": self.rule['event.severity'],"module": self.rule['event.module'],"dataset": self.rule['event.dataset'],"severity_label": self.rule['sigma_level']},"kibana_pivot": self.rule['kibana_pivot'],"soc_pivot": self.rule['soc_pivot'],"play_url": self.rule['play_url'],"sigma_level": self.rule['sigma_level'],"event_data": match, "@timestamp": timestamp}
url = f"https://{self.rule['es_host']}:{self.rule['es_port']}/logs-playbook.alerts-so/_doc/"
requests.post(url, data=json.dumps(payload), headers=headers, verify=False, auth=creds)
def get_info(self):
return {'type': 'PlaybookESAlerter'}
@@ -1,63 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
# https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0.
from time import gmtime, strftime
import requests,json
from elastalert.alerts import Alerter
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class SecurityOnionESAlerter(Alerter):
"""
Use matched data to create alerts in Elasticsearch.
"""
required_options = set(['detection_title', 'sigma_level'])
optional_fields = ['sigma_category', 'sigma_product', 'sigma_service']
def alert(self, matches):
for match in matches:
timestamp = strftime("%Y-%m-%d"'T'"%H:%M:%S"'.000Z', gmtime())
headers = {"Content-Type": "application/json"}
creds = None
if 'es_username' in self.rule and 'es_password' in self.rule:
creds = (self.rule['es_username'], self.rule['es_password'])
# Start building the rule dict
rule_info = {
"name": self.rule['detection_title'],
"uuid": self.rule['detection_public_id']
}
# Add optional fields if they are present in the rule
for field in self.optional_fields:
rule_key = field.split('_')[-1] # Assumes field format "sigma_<key>"
if field in self.rule:
rule_info[rule_key] = self.rule[field]
# Construct the payload with the conditional rule_info
payload = {
"tags": "alert",
"rule": rule_info,
"event": {
"severity": self.rule['event.severity'],
"module": self.rule['event.module'],
"dataset": self.rule['event.dataset'],
"severity_label": self.rule['sigma_level']
},
"sigma_level": self.rule['sigma_level'],
"event_data": match,
"@timestamp": timestamp
}
url = f"https://{self.rule['es_host']}:{self.rule['es_port']}/logs-detections.alerts-so/_doc/"
requests.post(url, data=json.dumps(payload), headers=headers, verify=False, auth=creds)
def get_info(self):
return {'type': 'SecurityOnionESAlerter'}
@@ -1,6 +0,0 @@
{% if elastalert.get('jira_user', '') | length > 0 and elastalert.get('jira_pass', '') | length > 0 %}
user: {{ elastalert.jira_user }}
password: {{ elastalert.jira_pass }}
{% else %}
apikey: {{ elastalert.get('jira_api_key', '') }}
{% endif %}
@@ -1,2 +0,0 @@
user: {{ elastalert.get('smtp_user', '') }}
password: {{ elastalert.get('smtp_pass', '') }}
-16
View File
@@ -13,19 +13,3 @@
{% do ELASTALERTDEFAULTS.elastalert.config.update({'es_password': pillar.elasticsearch.auth.users.so_elastic_user.pass}) %} {% do ELASTALERTDEFAULTS.elastalert.config.update({'es_password': pillar.elasticsearch.auth.users.so_elastic_user.pass}) %}
{% set ELASTALERTMERGED = salt['pillar.get']('elastalert', ELASTALERTDEFAULTS.elastalert, merge=True) %} {% set ELASTALERTMERGED = salt['pillar.get']('elastalert', ELASTALERTDEFAULTS.elastalert, merge=True) %}
{% if 'ntf' in salt['pillar.get']('features', []) %}
{% set params = ELASTALERTMERGED.get('alerter_parameters', '') | load_yaml %}
{% if params != None and params | length > 0 %}
{% do ELASTALERTMERGED.config.update(params) %}
{% endif %}
{% if ELASTALERTMERGED.get('smtp_user', '') | length > 0 %}
{% do ELASTALERTMERGED.config.update({'smtp_auth_file': '/opt/elastalert/predefined/smtp_auth.yaml'}) %}
{% endif %}
{% if ELASTALERTMERGED.get('jira_user', '') | length > 0 or ELASTALERTMERGED.get('jira_key', '') | length > 0 %}
{% do ELASTALERTMERGED.config.update({'jira_account_file': '/opt/elastalert/predefined/jira_auth.yaml'}) %}
{% endif %}
{% endif %}
+11 -145
View File
@@ -1,180 +1,46 @@
elastalert: elastalert:
enabled: enabled:
description: Enables or disables the ElastAlert 2 process. This process is critical for ensuring alerts arrive in SOC, and for outbound notification delivery. description: You can enable or disable Elastalert.
forcedType: bool helpLink: elastalert.html
helpLink: elastalert
alerter_parameters:
title: Custom Configuration Parameters
description: Optional configuration parameters made available as defaults for all rules and alerters. Use YAML format for these parameters, and reference the ElastAlert 2 documentation, located at https://elastalert2.readthedocs.io, for available configuration parameters. Requires a valid Security Onion license key.
global: True
multiline: True
syntax: yaml
helpLink: elastalert
forcedType: string
jira_api_key:
title: Jira API Key
description: Optional configuration parameter for Jira API Key, used instead of the Jira username and password. Requires a valid Security Onion license key.
global: True
sensitive: True
helpLink: elastalert
forcedType: string
jira_pass:
title: Jira Password
description: Optional configuration parameter for Jira password. Requires a valid Security Onion license key.
global: True
sensitive: True
helpLink: elastalert
forcedType: string
jira_user:
title: Jira Username
description: Optional configuration parameter for Jira username. Requires a valid Security Onion license key.
global: True
helpLink: elastalert
forcedType: string
smtp_pass:
title: SMTP Password
description: Optional configuration parameter for SMTP password, required for authenticating email servers. Requires a valid Security Onion license key.
global: True
sensitive: True
helpLink: elastalert
forcedType: string
smtp_user:
title: SMTP Username
description: Optional configuration parameter for SMTP username, required for authenticating email servers. Requires a valid Security Onion license key.
global: True
helpLink: elastalert
forcedType: string
files:
custom:
alertmanager_ca__crt:
description: Optional custom Certificate Authority for connecting to an AlertManager server. To utilize this custom file, the alertmanager_ca_certs key must be set to /opt/elastalert/custom/alertmanager_ca.crt in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
gelf_ca__crt:
description: Optional custom Certificate Authority for connecting to a Graylog server. To utilize this custom file, the graylog_ca_certs key must be set to /opt/elastalert/custom/graylog_ca.crt in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
http_post_ca__crt:
description: Optional custom Certificate Authority for connecting to a generic HTTP server, via the legacy HTTP POST alerter. To utilize this custom file, the http_post_ca_certs key must be set to /opt/elastalert/custom/http_post2_ca.crt in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
http_post2_ca__crt:
description: Optional custom Certificate Authority for connecting to a generic HTTP server, via the newer HTTP POST 2 alerter. To utilize this custom file, the http_post2_ca_certs key must be set to /opt/elastalert/custom/http_post2_ca.crt in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
ms_teams_ca__crt:
description: Optional custom Certificate Authority for connecting to Microsoft Teams server. To utilize this custom file, the ms_teams_ca_certs key must be set to /opt/elastalert/custom/ms_teams_ca.crt in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
pagerduty_ca__crt:
description: Optional custom Certificate Authority for connecting to PagerDuty server. To utilize this custom file, the pagerduty_ca_certs key must be set to /opt/elastalert/custom/pagerduty_ca.crt in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
rocket_chat_ca__crt:
description: Optional custom Certificate Authority for connecting to PagerDuty server. To utilize this custom file, the rocket_chart_ca_certs key must be set to /opt/elastalert/custom/rocket_chat_ca.crt in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
smtp__crt:
description: Optional custom certificate for connecting to an SMTP server. To utilize this custom file, the smtp_cert_file key must be set to /opt/elastalert/custom/smtp.crt in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
smtp__key:
description: Optional custom certificate key for connecting to an SMTP server. To utilize this custom file, the smtp_key_file key must be set to /opt/elastalert/custom/smtp.key in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
slack_ca__crt:
description: Optional custom Certificate Authority for connecting to Slack. To utilize this custom file, the slack_ca_certs key must be set to /opt/elastalert/custom/slack_ca.crt in the Alerter Parameters setting. Requires a valid Security Onion license key.
global: True
file: True
helpLink: elastalert
config: config:
scan_subdirectories:
description: Recursively scan subdirectories for rules.
forcedType: bool
advanced: True
global: True
helpLink: elastalert
disable_rules_on_error: disable_rules_on_error:
description: Disable rules on failure. description: Disable rules on failure.
forcedType: bool
global: True global: True
helpLink: elastalert helpLink: elastalert.html
run_every: run_every:
minutes: minutes:
description: Amount of time in minutes between searches. description: Amount of time in minutes between searches.
global: True global: True
helpLink: elastalert helpLink: elastalert.html
buffer_time: buffer_time:
minutes: minutes:
description: Amount of time in minutes to look through. description: Amount of time in minutes to look through.
global: True global: True
helpLink: elastalert helpLink: elastalert.html
old_query_limit: old_query_limit:
minutes: minutes:
description: Amount of time in minutes between queries to start at the most recently run query. description: Amount of time in minutes between queries to start at the most recently run query.
global: True global: True
helpLink: elastalert helpLink: elastalert.html
es_conn_timeout: es_conn_timeout:
description: Timeout in seconds for connecting to and reading from Elasticsearch. description: Timeout in seconds for connecting to and reading from Elasticsearch.
global: True global: True
helpLink: elastalert helpLink: elastalert.html
max_query_size: max_query_size:
description: The maximum number of documents that will be returned from Elasticsearch in a single query. description: The maximum number of documents that will be returned from Elasticsearch in a single query.
global: True global: True
helpLink: elastalert helpLink: elastalert.html
use_ssl:
description: Use SSL to connect to Elasticsearch.
forcedType: bool
advanced: True
global: True
helpLink: elastalert
verify_certs:
description: Verify TLS certificates when connecting to Elasticsearch.
forcedType: bool
advanced: True
global: True
helpLink: elastalert
alert_time_limit: alert_time_limit:
days: days:
description: The retry window for failed alerts. description: The retry window for failed alerts.
global: True global: True
helpLink: elastalert helpLink: elastalert.html
index_settings: index_settings:
shards: shards:
description: The number of shards for elastalert indices. description: The number of shards for elastalert indices.
global: True global: True
helpLink: elastalert helpLink: elastalert.html
replicas: replicas:
description: The number of replicas for elastalert indices. description: The number of replicas for elastalert indices.
global: True global: True
helpLink: elastalert helpLink: elastalert.html
logging:
incremental:
description: When incremental is false (the default), the logging configuration is applied in full, replacing any existing logging setup. When true, only the level attributes of existing loggers and handlers are updated, leaving the rest of the logging configuration unchanged.
forcedType: bool
advanced: True
global: True
helpLink: elastalert
disable_existing_loggers:
description: Disable existing loggers.
forcedType: bool
advanced: True
global: True
helpLink: elastalert
loggers:
'':
propagate:
description: Propagate log messages to parent loggers.
forcedType: bool
advanced: True
global: True
helpLink: elastalert
@@ -6,7 +6,7 @@
{% from 'allowed_states.map.jinja' import allowed_states %} {% from 'allowed_states.map.jinja' import allowed_states %}
{% if sls.split('.')[0] in allowed_states %} {% if sls.split('.')[0] in allowed_states %}
{% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'vars/globals.map.jinja' import GLOBALS %}
{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'docker/docker.map.jinja' import DOCKER %}
include: include:
- elastic-fleet-package-registry.config - elastic-fleet-package-registry.config
@@ -21,36 +21,30 @@ so-elastic-fleet-package-registry:
- user: 948 - user: 948
- networks: - networks:
- sobridge: - sobridge:
- ipv4_address: {{ DOCKERMERGED.containers['so-elastic-fleet-package-registry'].ip }} - ipv4_address: {{ DOCKER.containers['so-elastic-fleet-package-registry'].ip }}
- extra_hosts: - extra_hosts:
- {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }}
{% if DOCKERMERGED.containers['so-elastic-fleet-package-registry'].extra_hosts %} {% if DOCKER.containers['so-elastic-fleet-package-registry'].extra_hosts %}
{% for XTRAHOST in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].extra_hosts %} {% for XTRAHOST in DOCKER.containers['so-elastic-fleet-package-registry'].extra_hosts %}
- {{ XTRAHOST }} - {{ XTRAHOST }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
- port_bindings: - port_bindings:
{% for BINDING in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].port_bindings %} {% for BINDING in DOCKER.containers['so-elastic-fleet-package-registry'].port_bindings %}
- {{ BINDING }} - {{ BINDING }}
{% endfor %} {% endfor %}
{% if DOCKERMERGED.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %} {% if DOCKER.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %}
- binds: - binds:
{% for BIND in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %} {% for BIND in DOCKER.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %}
- {{ BIND }} - {{ BIND }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% if DOCKERMERGED.containers['so-elastic-fleet-package-registry'].extra_env %} {% if DOCKER.containers['so-elastic-fleet-package-registry'].extra_env %}
- environment: - environment:
{% for XTRAENV in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].extra_env %} {% for XTRAENV in DOCKER.containers['so-elastic-fleet-package-registry'].extra_env %}
- {{ XTRAENV }} - {{ XTRAENV }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% if DOCKERMERGED.containers['so-elastic-fleet-package-registry'].ulimits %}
- ulimits:
{% for ULIMIT in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].ulimits %}
- {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }}
{% endfor %}
{% endif %}
delete_so-elastic-fleet-package-registry_so-status.disabled: delete_so-elastic-fleet-package-registry_so-status.disabled:
file.uncomment: file.uncomment:
- name: /opt/so/conf/so-status/so-status.conf - name: /opt/so/conf/so-status/so-status.conf
@@ -1,5 +1,4 @@
elastic_fleet_package_registry: elastic_fleet_package_registry:
enabled: enabled:
description: Enables or disables the Fleet package registry process. This process must remain enabled to allow Elastic Agent packages to be updated. description: You can enable or disable Elastic Fleet Package Registry.
forcedType: bool
advanced: True advanced: True
+10 -18
View File
@@ -6,10 +6,10 @@
{% from 'allowed_states.map.jinja' import allowed_states %} {% from 'allowed_states.map.jinja' import allowed_states %}
{% if sls.split('.')[0] in allowed_states %} {% if sls.split('.')[0] in allowed_states %}
{% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'vars/globals.map.jinja' import GLOBALS %}
{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'docker/docker.map.jinja' import DOCKER %}
include: include:
- ca
- elasticagent.config - elasticagent.config
- elasticagent.sostatus - elasticagent.sostatus
@@ -22,17 +22,17 @@ so-elastic-agent:
- user: 949 - user: 949
- networks: - networks:
- sobridge: - sobridge:
- ipv4_address: {{ DOCKERMERGED.containers['so-elastic-agent'].ip }} - ipv4_address: {{ DOCKER.containers['so-elastic-agent'].ip }}
- extra_hosts: - extra_hosts:
- {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }}
- {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }}
{% if DOCKERMERGED.containers['so-elastic-agent'].extra_hosts %} {% if DOCKER.containers['so-elastic-agent'].extra_hosts %}
{% for XTRAHOST in DOCKERMERGED.containers['so-elastic-agent'].extra_hosts %} {% for XTRAHOST in DOCKER.containers['so-elastic-agent'].extra_hosts %}
- {{ XTRAHOST }} - {{ XTRAHOST }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
- port_bindings: - port_bindings:
{% for BINDING in DOCKERMERGED.containers['so-elastic-agent'].port_bindings %} {% for BINDING in DOCKER.containers['so-elastic-agent'].port_bindings %}
- {{ BINDING }} - {{ BINDING }}
{% endfor %} {% endfor %}
- binds: - binds:
@@ -41,31 +41,23 @@ so-elastic-agent:
- /etc/pki/tls/certs/intca.crt:/etc/pki/tls/certs/intca.crt:ro - /etc/pki/tls/certs/intca.crt:/etc/pki/tls/certs/intca.crt:ro
- /nsm:/nsm:ro - /nsm:/nsm:ro
- /opt/so/log:/opt/so/log:ro - /opt/so/log:/opt/so/log:ro
{% if DOCKERMERGED.containers['so-elastic-agent'].custom_bind_mounts %} {% if DOCKER.containers['so-elastic-agent'].custom_bind_mounts %}
{% for BIND in DOCKERMERGED.containers['so-elastic-agent'].custom_bind_mounts %} {% for BIND in DOCKER.containers['so-elastic-agent'].custom_bind_mounts %}
- {{ BIND }} - {{ BIND }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
- environment: - environment:
- FLEET_CA=/etc/pki/tls/certs/intca.crt - FLEET_CA=/etc/pki/tls/certs/intca.crt
- LOGS_PATH=logs - LOGS_PATH=logs
{% if DOCKERMERGED.containers['so-elastic-agent'].extra_env %} {% if DOCKER.containers['so-elastic-agent'].extra_env %}
{% for XTRAENV in DOCKERMERGED.containers['so-elastic-agent'].extra_env %} {% for XTRAENV in DOCKER.containers['so-elastic-agent'].extra_env %}
- {{ XTRAENV }} - {{ XTRAENV }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% if DOCKERMERGED.containers['so-elastic-agent'].ulimits %}
- ulimits:
{% for ULIMIT in DOCKERMERGED.containers['so-elastic-agent'].ulimits %}
- {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }}
{% endfor %}
{% endif %}
- require: - require:
- file: create-elastic-agent-config - file: create-elastic-agent-config
- file: trusttheca
- watch: - watch:
- file: create-elastic-agent-config - file: create-elastic-agent-config
- file: trusttheca
delete_so-elastic-agent_so-status.disabled: delete_so-elastic-agent_so-status.disabled:
file.uncomment: file.uncomment:
+310 -159
View File
@@ -3,7 +3,7 @@
{%- set ES_PASS = salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:pass', '') %} {%- set ES_PASS = salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:pass', '') %}
id: aea1ba80-1065-11ee-a369-97538913b6a9 id: aea1ba80-1065-11ee-a369-97538913b6a9
revision: 4 revision: 1
outputs: outputs:
default: default:
type: elasticsearch type: elasticsearch
@@ -22,133 +22,242 @@ agent:
metrics: false metrics: false
features: {} features: {}
inputs: inputs:
- id: filestream-filestream-85820eb0-25ef-11f0-a18d-1b26f69b8310 - id: logfile-logs-fefef78c-422f-4cfa-8abf-4cd1b9428f62
name: import-suricata-logs name: import-evtx-logs
revision: 3 revision: 2
type: filestream type: logfile
use_output: default use_output: default
meta: meta:
package: package:
name: filestream name: log
version: version:
data_stream: data_stream:
namespace: so namespace: so
package_policy_id: 85820eb0-25ef-11f0-a18d-1b26f69b8310 package_policy_id: fefef78c-422f-4cfa-8abf-4cd1b9428f62
streams: streams:
- id: filestream-filestream.generic-85820eb0-25ef-11f0-a18d-1b26f69b8310 - id: logfile-log.log-fefef78c-422f-4cfa-8abf-4cd1b9428f62
data_stream: data_stream:
dataset: import dataset: import
paths: paths:
- /nsm/import/*/suricata/eve*.json - /nsm/import/*/evtx/*.json
pipeline: suricata.common
prospector.scanner.recursive_glob: true
prospector.scanner.exclude_files:
- \.gz$
ignore_older: 72h
clean_inactive: -1
parsers: null
processors:
- add_fields:
target: event
fields:
category: network
module: suricata
imported: true
- dissect:
tokenizer: /nsm/import/%{import.id}/suricata/%{import.file}
field: log.file.path
target_prefix: ''
file_identity.native: null
prospector.scanner.fingerprint.enabled: false
- id: filestream-filestream-86b4e960-25ef-11f0-a18d-1b26f69b8310
name: import-zeek-logs
revision: 3
type: filestream
use_output: default
meta:
package:
name: filestream
version:
data_stream:
namespace: so
package_policy_id: 86b4e960-25ef-11f0-a18d-1b26f69b8310
streams:
- id: filestream-filestream.generic-86b4e960-25ef-11f0-a18d-1b26f69b8310
data_stream:
dataset: import
paths:
- /nsm/import/*/zeek/logs/*.log
prospector.scanner.recursive_glob: true
prospector.scanner.exclude_files:
- >-
(broker|capture_loss|cluster|conn-summary|console|ecat_arp_info|known_certs|known_hosts|known_services|loaded_scripts|ntp|ocsp|packet_filter|reporter|stats|stderr|stdout).log$
clean_inactive: -1
parsers: null
processors: processors:
- dissect: - dissect:
tokenizer: /nsm/import/%{import.id}/zeek/logs/%{import.file}
field: log.file.path field: log.file.path
tokenizer: '/nsm/import/%{import.id}/evtx/%{import.file}'
target_prefix: '' target_prefix: ''
- script:
lang: javascript
source: |
function process(event) {
var pl = event.Get("import.file").slice(0,-4);
event.Put("@metadata.pipeline", "zeek." + pl);
}
- add_fields:
target: event
fields:
category: network
module: zeek
imported: true
- add_tags:
tags: ics
when:
regexp:
import.file: >-
^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm*
file_identity.native: null
prospector.scanner.fingerprint.enabled: false
- id: filestream-filestream-91741240-25ef-11f0-a18d-1b26f69b8310
name: soc-sensoroni-logs
revision: 3
type: filestream
use_output: default
meta:
package:
name: filestream
version:
data_stream:
namespace: so
package_policy_id: 91741240-25ef-11f0-a18d-1b26f69b8310
streams:
- id: filestream-filestream.generic-91741240-25ef-11f0-a18d-1b26f69b8310
data_stream:
dataset: soc
paths:
- /opt/so/log/sensoroni/sensoroni.log
pipeline: common
prospector.scanner.recursive_glob: true
prospector.scanner.exclude_files:
- \.gz$
clean_inactive: -1
parsers: null
processors:
- decode_json_fields: - decode_json_fields:
fields: fields:
- message - message
target: sensoroni target: ''
- drop_fields:
ignore_missing: true
fields:
- host
- add_fields:
fields:
dataset: system.security
type: logs
namespace: default
target: data_stream
- add_fields:
fields:
dataset: system.security
module: system
imported: true
target: event
- then:
- add_fields:
fields:
dataset: windows.sysmon_operational
target: data_stream
- add_fields:
fields:
dataset: windows.sysmon_operational
module: windows
imported: true
target: event
if:
equals:
winlog.channel: Microsoft-Windows-Sysmon/Operational
- then:
- add_fields:
fields:
dataset: system.application
target: data_stream
- add_fields:
fields:
dataset: system.application
target: event
if:
equals:
winlog.channel: Application
- then:
- add_fields:
fields:
dataset: system.system
target: data_stream
- add_fields:
fields:
dataset: system.system
target: event
if:
equals:
winlog.channel: System
- then:
- add_fields:
fields:
dataset: windows.powershell_operational
target: data_stream
- add_fields:
fields:
dataset: windows.powershell_operational
module: windows
target: event
if:
equals:
winlog.channel: Microsoft-Windows-PowerShell/Operational
tags:
- import
- id: logfile-redis-fc98c947-7d17-4861-a318-7ad075f6d1b0
name: redis-logs
revision: 2
type: logfile
use_output: default
meta:
package:
name: redis
version:
data_stream:
namespace: default
package_policy_id: fc98c947-7d17-4861-a318-7ad075f6d1b0
streams:
- id: logfile-redis.log-fc98c947-7d17-4861-a318-7ad075f6d1b0
data_stream:
dataset: redis.log
type: logs
exclude_files:
- .gz$
paths:
- /opt/so/log/redis/redis.log
tags:
- redis-log
exclude_lines:
- '^\s+[\-`(''.|_]'
- id: logfile-logs-3b56803d-5ade-4c93-b25e-9b37182f66b8
name: import-suricata-logs
revision: 2
type: logfile
use_output: default
meta:
package:
name: log
version:
data_stream:
namespace: so
package_policy_id: 3b56803d-5ade-4c93-b25e-9b37182f66b8
streams:
- id: logfile-log.log-3b56803d-5ade-4c93-b25e-9b37182f66b8
data_stream:
dataset: import
pipeline: suricata.common
paths:
- /nsm/import/*/suricata/eve*.json
processors:
- add_fields:
fields:
module: suricata
imported: true
category: network
target: event
- dissect:
field: log.file.path
tokenizer: '/nsm/import/%{import.id}/suricata/%{import.file}'
target_prefix: ''
- id: logfile-logs-c327e1a3-1ebe-449c-a8eb-f6f35032e69d
name: soc-server-logs
revision: 2
type: logfile
use_output: default
meta:
package:
name: log
version:
data_stream:
namespace: so
package_policy_id: c327e1a3-1ebe-449c-a8eb-f6f35032e69d
streams:
- id: logfile-log.log-c327e1a3-1ebe-449c-a8eb-f6f35032e69d
data_stream:
dataset: soc
pipeline: common
paths:
- /opt/so/log/soc/sensoroni-server.log
processors:
- decode_json_fields:
add_error_key: true
process_array: true process_array: true
max_depth: 2 max_depth: 2
add_error_key: true
- add_fields:
target: event
fields: fields:
- message
target: soc
- add_fields:
fields:
module: soc
dataset_temp: server
category: host category: host
target: event
- rename:
ignore_missing: true
fields:
- from: soc.fields.sourceIp
to: source.ip
- from: soc.fields.status
to: http.response.status_code
- from: soc.fields.method
to: http.request.method
- from: soc.fields.path
to: url.path
- from: soc.message
to: event.action
- from: soc.level
to: log.level
tags:
- so-soc
- id: logfile-logs-906e0d4c-9ec3-4c6a-bef6-e347ec9fd073
name: soc-sensoroni-logs
revision: 2
type: logfile
use_output: default
meta:
package:
name: log
version:
data_stream:
namespace: so
package_policy_id: 906e0d4c-9ec3-4c6a-bef6-e347ec9fd073
streams:
- id: logfile-log.log-906e0d4c-9ec3-4c6a-bef6-e347ec9fd073
data_stream:
dataset: soc
pipeline: common
paths:
- /opt/so/log/sensoroni/sensoroni.log
processors:
- decode_json_fields:
add_error_key: true
process_array: true
max_depth: 2
fields:
- message
target: sensoroni
- add_fields:
fields:
module: soc module: soc
dataset_temp: sensoroni dataset_temp: sensoroni
category: host
target: event
- rename: - rename:
ignore_missing: true
fields: fields:
- from: sensoroni.fields.sourceIp - from: sensoroni.fields.sourceIp
to: source.ip to: source.ip
@@ -162,100 +271,141 @@ inputs:
to: event.action to: event.action
- from: sensoroni.level - from: sensoroni.level
to: log.level to: log.level
ignore_missing: true - id: logfile-logs-df0d7f2c-221f-433b-b18b-d1cf83250515
file_identity.native: null name: soc-salt-relay-logs
prospector.scanner.fingerprint.enabled: false revision: 2
- id: filestream-filestream-976e3900-25ef-11f0-a18d-1b26f69b8310 type: logfile
name: suricata-logs
revision: 3
type: filestream
use_output: default use_output: default
meta: meta:
package: package:
name: filestream name: log
version: version:
data_stream: data_stream:
namespace: so namespace: so
package_policy_id: 976e3900-25ef-11f0-a18d-1b26f69b8310 package_policy_id: df0d7f2c-221f-433b-b18b-d1cf83250515
streams: streams:
- id: filestream-filestream.generic-976e3900-25ef-11f0-a18d-1b26f69b8310 - id: logfile-log.log-df0d7f2c-221f-433b-b18b-d1cf83250515
data_stream:
dataset: soc
pipeline: common
paths:
- /opt/so/log/soc/salt-relay.log
processors:
- dissect:
field: message
tokenizer: '%{soc.ts} | %{event.action}'
target_prefix: ''
- add_fields:
fields:
module: soc
dataset_temp: salt_relay
category: host
target: event
tags:
- so-soc
- id: logfile-logs-74bd2366-fe52-493c-bddc-843a017fc4d0
name: soc-auth-sync-logs
revision: 2
type: logfile
use_output: default
meta:
package:
name: log
version:
data_stream:
namespace: so
package_policy_id: 74bd2366-fe52-493c-bddc-843a017fc4d0
streams:
- id: logfile-log.log-74bd2366-fe52-493c-bddc-843a017fc4d0
data_stream:
dataset: soc
pipeline: common
paths:
- /opt/so/log/soc/sync.log
processors:
- dissect:
field: message
tokenizer: '%{event.action}'
target_prefix: ''
- add_fields:
fields:
module: soc
dataset_temp: auth_sync
category: host
target: event
tags:
- so-soc
- id: logfile-logs-d151d9bf-ff2a-4529-9520-c99244bc0253
name: suricata-logs
revision: 2
type: logfile
use_output: default
meta:
package:
name: log
version:
data_stream:
namespace: so
package_policy_id: d151d9bf-ff2a-4529-9520-c99244bc0253
streams:
- id: logfile-log.log-d151d9bf-ff2a-4529-9520-c99244bc0253
data_stream: data_stream:
dataset: suricata dataset: suricata
pipeline: suricata.common
paths: paths:
- /nsm/suricata/eve*.json - /nsm/suricata/eve*.json
pipeline: suricata.common
prospector.scanner.recursive_glob: true
prospector.scanner.exclude_files:
- \.gz$
clean_inactive: -1
parsers: null
processors: processors:
- add_fields: - add_fields:
target: event
fields: fields:
category: network
module: suricata module: suricata
file_identity.native: null category: network
prospector.scanner.fingerprint.enabled: false target: event
- id: filestream-filestream-95091fe0-25ef-11f0-a18d-1b26f69b8310 - id: logfile-logs-31f94d05-ae75-40ee-b9c5-0e0356eff327
name: strelka-logs name: strelka-logs
revision: 3 revision: 2
type: filestream type: logfile
use_output: default use_output: default
meta: meta:
package: package:
name: filestream name: log
version: version:
data_stream: data_stream:
namespace: so namespace: so
package_policy_id: 95091fe0-25ef-11f0-a18d-1b26f69b8310 package_policy_id: 31f94d05-ae75-40ee-b9c5-0e0356eff327
streams: streams:
- id: filestream-filestream.generic-95091fe0-25ef-11f0-a18d-1b26f69b8310 - id: logfile-log.log-31f94d05-ae75-40ee-b9c5-0e0356eff327
data_stream: data_stream:
dataset: strelka dataset: strelka
pipeline: strelka.file
paths: paths:
- /nsm/strelka/log/strelka.log - /nsm/strelka/log/strelka.log
pipeline: strelka.file
prospector.scanner.recursive_glob: true
prospector.scanner.exclude_files:
- \.gz$
clean_inactive: -1
parsers: null
processors: processors:
- add_fields: - add_fields:
target: event
fields: fields:
category: file
module: strelka module: strelka
file_identity.native: null category: file
prospector.scanner.fingerprint.enabled: false target: event
- id: filestream-filestream-9f309ca0-25ef-11f0-a18d-1b26f69b8310 - id: logfile-logs-6197fe84-9b58-4d9b-8464-3d517f28808d
name: zeek-logs name: zeek-logs
revision: 2 revision: 1
type: filestream type: logfile
use_output: default use_output: default
meta: meta:
package: package:
name: filestream name: log
version: version:
data_stream: data_stream:
namespace: so namespace: so
package_policy_id: 9f309ca0-25ef-11f0-a18d-1b26f69b8310 package_policy_id: 6197fe84-9b58-4d9b-8464-3d517f28808d
streams: streams:
- id: filestream-filestream.generic-9f309ca0-25ef-11f0-a18d-1b26f69b8310 - id: logfile-log.log-6197fe84-9b58-4d9b-8464-3d517f28808d
data_stream: data_stream:
dataset: zeek dataset: zeek
paths: paths:
- /nsm/zeek/logs/current/*.log - /nsm/zeek/logs/current/*.log
prospector.scanner.recursive_glob: true
prospector.scanner.exclude_files:
- >-
(broker|capture_loss|cluster|conn-summary|console|ecat_arp_info|known_certs|known_hosts|known_services|loaded_scripts|ntp|ocsp|packet_filter|reporter|stats|stderr|stdout).log$
clean_inactive: -1
parsers: null
processors: processors:
- dissect: - dissect:
tokenizer: /nsm/zeek/logs/current/%{pipeline}.log tokenizer: '/nsm/zeek/logs/current/%{pipeline}.log'
field: log.file.path field: log.file.path
trim_chars: .log trim_chars: .log
target_prefix: '' target_prefix: ''
@@ -277,17 +427,18 @@ inputs:
regexp: regexp:
pipeline: >- pipeline: >-
^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm* ^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm*
file_identity.native: null exclude_files:
prospector.scanner.fingerprint.enabled: false - >-
broker|capture_loss|cluster|ecat_arp_info|known_hosts|known_services|loaded_scripts|ntp|ocsp|packet_filter|reporter|stats|stderr|stdout.log$
- id: udp-udp-35051de0-46a5-11ee-8d5d-9f98c8182f60 - id: udp-udp-35051de0-46a5-11ee-8d5d-9f98c8182f60
name: syslog-udp-514 name: syslog-udp-514
revision: 4 revision: 3
type: udp type: udp
use_output: default use_output: default
meta: meta:
package: package:
name: udp name: udp
version: version: 1.10.0
data_stream: data_stream:
namespace: so namespace: so
package_policy_id: 35051de0-46a5-11ee-8d5d-9f98c8182f60 package_policy_id: 35051de0-46a5-11ee-8d5d-9f98c8182f60
@@ -307,13 +458,13 @@ inputs:
- syslog - syslog
- id: tcp-tcp-33d37bb0-46a5-11ee-8d5d-9f98c8182f60 - id: tcp-tcp-33d37bb0-46a5-11ee-8d5d-9f98c8182f60
name: syslog-tcp-514 name: syslog-tcp-514
revision: 4 revision: 3
type: tcp type: tcp
use_output: default use_output: default
meta: meta:
package: package:
name: tcp name: tcp
version: version: 1.10.0
data_stream: data_stream:
namespace: so namespace: so
package_policy_id: 33d37bb0-46a5-11ee-8d5d-9f98c8182f60 package_policy_id: 33d37bb0-46a5-11ee-8d5d-9f98c8182f60
-5
View File
@@ -1,5 +0,0 @@
elasticagent:
enabled:
description: Enables or disables the Elastic Agent process. This process must remain enabled to allow collection of node events.
forcedType: bool
advanced: True
-3
View File
@@ -9,6 +9,3 @@ fleetartifactdir:
- user: 947 - user: 947
- group: 939 - group: 939
- makedirs: True - makedirs: True
- recurse:
- user
- group
-34
View File
@@ -1,34 +0,0 @@
{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
https://securityonion.net/license; you may not use this file except in compliance with the
Elastic License 2.0. #}
{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
{# advanced config_yaml options for elasticfleet logstash output #}
{% set ADV_OUTPUT_LOGSTASH_RAW = ELASTICFLEETMERGED.config.outputs.logstash %}
{% set ADV_OUTPUT_LOGSTASH = {} %}
{% for k, v in ADV_OUTPUT_LOGSTASH_RAW.items() %}
{% if v != "" and v is not none %}
{% if k == 'queue_mem_events' %}
{# rename queue_mem_events queue.mem.events #}
{% do ADV_OUTPUT_LOGSTASH.update({'queue.mem.events':v}) %}
{% elif k == 'loadbalance' %}
{% if v %}
{# only include loadbalance config when its True #}
{% do ADV_OUTPUT_LOGSTASH.update({k:v}) %}
{% endif %}
{% else %}
{% do ADV_OUTPUT_LOGSTASH.update({k:v}) %}
{% endif %}
{% endif %}
{% endfor %}
{% set LOGSTASH_CONFIG_YAML_RAW = [] %}
{% if ADV_OUTPUT_LOGSTASH %}
{% for k, v in ADV_OUTPUT_LOGSTASH.items() %}
{% do LOGSTASH_CONFIG_YAML_RAW.append(k ~ ': ' ~ v) %}
{% endfor %}
{% endif %}
{% set LOGSTASH_CONFIG_YAML = LOGSTASH_CONFIG_YAML_RAW | join('\\n') if LOGSTASH_CONFIG_YAML_RAW else '' %}
+1 -70
View File
@@ -9,10 +9,6 @@
{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %} {% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
{% set node_data = salt['pillar.get']('node_data') %} {% set node_data = salt['pillar.get']('node_data') %}
include:
- elasticfleet.artifact_registry
- elasticfleet.ssl
# Add EA Group # Add EA Group
elasticfleetgroup: elasticfleetgroup:
group.present: group.present:
@@ -34,7 +30,6 @@ elasticfleet_sbin:
- user: 947 - user: 947
- group: 939 - group: 939
- file_mode: 755 - file_mode: 755
- show_changes: False
elasticfleet_sbin_jinja: elasticfleet_sbin_jinja:
file.recurse: file.recurse:
@@ -46,7 +41,6 @@ elasticfleet_sbin_jinja:
- template: jinja - template: jinja
- exclude_pat: - exclude_pat:
- so-elastic-fleet-package-upgrade # exclude this because we need to watch it for changes - so-elastic-fleet-package-upgrade # exclude this because we need to watch it for changes
- show_changes: False
eaconfdir: eaconfdir:
file.directory: file.directory:
@@ -69,14 +63,6 @@ eastatedir:
- group: 939 - group: 939
- makedirs: True - makedirs: True
custommappingsdir:
file.directory:
- name: /nsm/custom-mappings
- user: 947
- group: 939
- makedirs: True
eapackageupgrade: eapackageupgrade:
file.managed: file.managed:
- name: /usr/sbin/so-elastic-fleet-package-upgrade - name: /usr/sbin/so-elastic-fleet-package-upgrade
@@ -87,59 +73,6 @@ eapackageupgrade:
- template: jinja - template: jinja
{% if GLOBALS.role != "so-fleet" %} {% if GLOBALS.role != "so-fleet" %}
{% if not GLOBALS.airgap %}
soresourcesrepoclone:
git.latest:
- name: https://github.com/Security-Onion-Solutions/securityonion-resources.git
- target: /nsm/securityonion-resources
- rev: 'main'
- depth: 1
- force_reset: True
- retry:
attempts: 3
interval: 10
{% endif %}
elasticdefendconfdir:
file.directory:
- name: /opt/so/conf/elastic-fleet/defend-exclusions/rulesets
- user: 947
- group: 939
- makedirs: True
elasticdefenddisabled:
file.managed:
- name: /opt/so/conf/elastic-fleet/defend-exclusions/disabled-filters.yaml
- source: salt://elasticfleet/files/soc/elastic-defend-disabled-filters.yaml
- user: 947
- group: 939
- mode: 600
elasticdefendcustom:
file.managed:
- name: /opt/so/conf/elastic-fleet/defend-exclusions/rulesets/custom-filters-raw
- source: salt://elasticfleet/files/soc/elastic-defend-custom-filters.yaml
- user: 947
- group: 939
- mode: 600
{% if ELASTICFLEETMERGED.config.defend_filters.enable_auto_configuration %}
{% set ap = "present" %}
{% else %}
{% set ap = "absent" %}
{% endif %}
cron-elastic-defend-filters:
cron.{{ap}}:
- name: python3 /sbin/so-elastic-defend-manage-filters.py -c /opt/so/conf/elasticsearch/curl.config -d /opt/so/conf/elastic-fleet/defend-exclusions/disabled-filters.yaml -i /nsm/securityonion-resources/event_filters/ -i /opt/so/conf/elastic-fleet/defend-exclusions/rulesets/custom-filters/ &>> /opt/so/log/elasticfleet/elastic-defend-manage-filters.log
- identifier: elastic-defend-filters
- user: root
- minute: '0'
- hour: '3'
- daymonth: '*'
- month: '*'
- dayweek: '*'
eaintegrationsdir: eaintegrationsdir:
file.directory: file.directory:
- name: /opt/so/conf/elastic-fleet/integrations - name: /opt/so/conf/elastic-fleet/integrations
@@ -154,7 +87,6 @@ eadynamicintegration:
- user: 947 - user: 947
- group: 939 - group: 939
- template: jinja - template: jinja
- show_changes: False
eaintegration: eaintegration:
file.recurse: file.recurse:
@@ -162,7 +94,6 @@ eaintegration:
- source: salt://elasticfleet/files/integrations - source: salt://elasticfleet/files/integrations
- user: 947 - user: 947
- group: 939 - group: 939
- show_changes: False
eaoptionalintegrationsdir: eaoptionalintegrationsdir:
file.directory: file.directory:
@@ -173,7 +104,7 @@ eaoptionalintegrationsdir:
{% for minion in node_data %} {% for minion in node_data %}
{% set role = node_data[minion]["role"] %} {% set role = node_data[minion]["role"] %}
{% if role in [ "eval","fleet","heavynode","import","manager", "managerhype", "managersearch","standalone" ] %} {% if role in [ "eval","fleet","heavynode","import","manager","managersearch","standalone" ] %}
{% set optional_integrations = ELASTICFLEETMERGED.optional_integrations %} {% set optional_integrations = ELASTICFLEETMERGED.optional_integrations %}
{% set integration_keys = optional_integrations.keys() %} {% set integration_keys = optional_integrations.keys() %}
fleet_server_integrations_{{ minion }}: fleet_server_integrations_{{ minion }}:

Some files were not shown because too many files have changed in this diff Show More